include/svx/annotation/Annotation.hxx |   29 ++----
 svx/source/annotation/Annotation.cxx  |  151 ++++++++++++++++++++--------------
 2 files changed, 104 insertions(+), 76 deletions(-)

New commits:
commit dedf0c1bcbbf4fc9e2df3acd69906a01da1737e7
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Sun Sep 7 21:27:51 2025 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri Sep 12 09:37:43 2025 +0200

    cid#1659918 Data race condition
    
    and
    
    cid#1660133 Data race condition
    cid#1660238 Data race condition
    etc.
    
    Change-Id: Ic0278e430c62abda92e8ce0e590a4726a4488b30
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190791
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/include/svx/annotation/Annotation.hxx 
b/include/svx/annotation/Annotation.hxx
index 56944c97a20a..e0180d72d431 100644
--- a/include/svx/annotation/Annotation.hxx
+++ b/include/svx/annotation/Annotation.hxx
@@ -89,9 +89,6 @@ struct SVXCORE_DLLPUBLIC AnnotationData
     OUString m_Initials;
     css::util::DateTime m_DateTime;
     OUString m_Text;
-
-    void get(Annotation& rAnnotation);
-    void set(Annotation& rAnnotation);
 };
 
 /** Annotation object, responsible for handling of the annotation.
@@ -103,6 +100,11 @@ class SVXCORE_DLLPUBLIC Annotation
     : public ::comphelper::WeakComponentImplHelper<css::office::XAnnotation>,
       public ::cppu::PropertySetMixin<css::office::XAnnotation>
 {
+private:
+    css::uno::Reference<css::text::XText> getTextRangeImpl(const 
std::unique_lock<std::mutex>& g);
+    OUString GetTextImpl(const std::unique_lock<std::mutex>& g);
+    void SetTextImpl(OUString const& rText, const 
std::unique_lock<std::mutex>& g);
+
 protected:
     SdrPage* mpPage;
     UniqueID maUniqueID;
@@ -135,20 +137,8 @@ public:
     }
 
     // Changes without triggering notification broadcast
-    const css::geometry::RealPoint2D& GetPosition() const { return m_Position; 
}
-    void SetPosition(const css::geometry::RealPoint2D& rValue) { m_Position = 
rValue; }
-
-    const css::geometry::RealSize2D& GetSize() const { return m_Size; }
-    void SetSize(const css::geometry::RealSize2D& rValue) { m_Size = rValue; }
-
-    const OUString& GetAuthor() const { return m_Author; }
-    void SetAuthor(const OUString& rValue) { m_Author = rValue; }
-
-    const OUString& GetInitials() const { return m_Initials; }
-    void SetInitials(const OUString& rValue) { m_Initials = rValue; }
-
-    const css::util::DateTime& GetDateTime() const { return m_DateTime; }
-    void SetDateTime(const css::util::DateTime& rValue) { m_DateTime = rValue; 
}
+    void SetPosition(const css::geometry::RealPoint2D& rValue);
+    void SetSize(const css::geometry::RealSize2D& rValue);
 
     virtual css::uno::Reference<css::text::XText> SAL_CALL getTextRange() 
override;
 
@@ -160,6 +150,11 @@ public:
 
     OUString GetText();
     void SetText(OUString const& rText);
+
+    OString ToJSON(CommentNotificationType nType);
+    void toData(AnnotationData& rData);
+    void fromData(const AnnotationData& rData);
+
     const rtl::Reference<sdr::annotation::TextApiObject>& getTextApiObject() { 
return m_TextRange; }
 
     SdrModel* GetModel() const;
diff --git a/svx/source/annotation/Annotation.cxx 
b/svx/source/annotation/Annotation.cxx
index af516a20b535..0d6caa17d4ee 100644
--- a/svx/source/annotation/Annotation.cxx
+++ b/svx/source/annotation/Annotation.cxx
@@ -22,42 +22,6 @@ namespace sdr::annotation
 {
 namespace
 {
-OString lcl_LOKGetCommentPayload(CommentNotificationType nType, Annotation& 
rAnnotation)
-{
-    tools::JsonWriter aJsonWriter;
-    {
-        auto aCommentNode = aJsonWriter.startNode("comment");
-
-        aJsonWriter.put(
-            "action",
-            (nType == CommentNotificationType::Add
-                 ? "Add"
-                 : (nType == CommentNotificationType::Remove
-                        ? "Remove"
-                        : (nType == CommentNotificationType::Modify ? "Modify" 
: "???"))));
-        aJsonWriter.put("id", rAnnotation.GetId());
-
-        if (nType != CommentNotificationType::Remove)
-        {
-            aJsonWriter.put("id", rAnnotation.GetId());
-            aJsonWriter.put("author", rAnnotation.GetAuthor());
-            aJsonWriter.put("dateTime", 
utl::toISO8601(rAnnotation.GetDateTime()));
-            aJsonWriter.put("text", rAnnotation.GetText());
-            SdrPage const* pPage = rAnnotation.getPage();
-            aJsonWriter.put("parthash", pPage ? 
OString::number(pPage->GetUniqueID()) : OString());
-            geometry::RealPoint2D const aPoint = rAnnotation.GetPosition();
-            geometry::RealSize2D const aSize = rAnnotation.GetSize();
-            tools::Rectangle aRectangle(
-                Point(std::round(o3tl::toTwips(aPoint.X, o3tl::Length::mm)),
-                      std::round(o3tl::toTwips(aPoint.Y, o3tl::Length::mm))),
-                Size(std::round(o3tl::toTwips(aSize.Width, o3tl::Length::mm)),
-                     std::round(o3tl::toTwips(aSize.Height, 
o3tl::Length::mm))));
-            aJsonWriter.put("rectangle", aRectangle.toString());
-        }
-    }
-    return aJsonWriter.finishAndGetAsOString();
-}
-
 /** Undo/redo a modification of an annotation - change of annotation data */
 class UndoAnnotation : public SdrUndoAction
 {
@@ -66,20 +30,20 @@ public:
         : SdrUndoAction(*rAnnotation.GetModel())
         , mrAnnotation(rAnnotation)
     {
-        maUndoData.get(mrAnnotation);
+        mrAnnotation.toData(maUndoData);
     }
 
     void Undo() override
     {
-        maRedoData.get(mrAnnotation);
-        maUndoData.set(mrAnnotation);
+        mrAnnotation.toData(maRedoData);
+        mrAnnotation.fromData(maUndoData);
         LOKCommentNotifyAll(CommentNotificationType::Modify, mrAnnotation);
     }
 
     void Redo() override
     {
-        maUndoData.get(mrAnnotation);
-        maRedoData.set(mrAnnotation);
+        mrAnnotation.toData(maUndoData);
+        mrAnnotation.fromData(maRedoData);
         LOKCommentNotifyAll(CommentNotificationType::Modify, mrAnnotation);
     }
 
@@ -98,7 +62,7 @@ void LOKCommentNotify(CommentNotificationType nType, const 
SfxViewShell* pViewSh
     if (!comphelper::LibreOfficeKit::isActive() || 
comphelper::LibreOfficeKit::isTiledAnnotations())
         return;
 
-    OString aPayload = lcl_LOKGetCommentPayload(nType, rAnnotation);
+    OString aPayload = rAnnotation.ToJSON(nType);
     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload);
 }
 
@@ -108,7 +72,7 @@ void LOKCommentNotifyAll(CommentNotificationType nType, 
Annotation& rAnnotation)
     if (!comphelper::LibreOfficeKit::isActive() || 
comphelper::LibreOfficeKit::isTiledAnnotations())
         return;
 
-    OString aPayload = lcl_LOKGetCommentPayload(nType, rAnnotation);
+    OString aPayload = rAnnotation.ToJSON(nType);
 
     const SfxViewShell* pViewShell = SfxViewShell::GetFirst();
     while (pViewShell)
@@ -118,24 +82,26 @@ void LOKCommentNotifyAll(CommentNotificationType nType, 
Annotation& rAnnotation)
     }
 }
 
-void AnnotationData::get(Annotation& rAnnotation)
+void Annotation::toData(AnnotationData& rData)
 {
-    m_Position = rAnnotation.GetPosition();
-    m_Size = rAnnotation.GetSize();
-    m_Author = rAnnotation.GetAuthor();
-    m_Initials = rAnnotation.GetInitials();
-    m_DateTime = rAnnotation.GetDateTime();
-    m_Text = rAnnotation.GetText();
+    std::unique_lock g(m_aMutex);
+    rData.m_Position = m_Position;
+    rData.m_Size = m_Size;
+    rData.m_Author = m_Author;
+    rData.m_Initials = m_Initials;
+    rData.m_DateTime = m_DateTime;
+    rData.m_Text = GetTextImpl(g);
 }
 
-void AnnotationData::set(Annotation& rAnnotation)
+void Annotation::fromData(const AnnotationData& rData)
 {
-    rAnnotation.SetPosition(m_Position);
-    rAnnotation.SetSize(m_Size);
-    rAnnotation.SetAuthor(m_Author);
-    rAnnotation.SetInitials(m_Initials);
-    rAnnotation.SetDateTime(m_DateTime);
-    rAnnotation.SetText(m_Text);
+    std::unique_lock g(m_aMutex);
+    m_Position = rData.m_Position;
+    m_Size = rData.m_Size;
+    m_Author = rData.m_Author;
+    m_Initials = rData.m_Initials;
+    m_DateTime = rData.m_DateTime;
+    SetTextImpl(rData.m_Text, g);
 }
 
 Annotation::Annotation(const css::uno::Reference<css::uno::XComponentContext>& 
rxContext,
@@ -163,19 +129,36 @@ std::unique_ptr<SdrUndoAction> 
Annotation::createUndoAnnotation()
 
 OUString Annotation::GetText()
 {
-    uno::Reference<text::XText> xText(getTextRange());
+    std::unique_lock g(m_aMutex);
+    return GetTextImpl(g);
+}
+
+OUString Annotation::GetTextImpl(const std::unique_lock<std::mutex>& g)
+{
+    uno::Reference<text::XText> xText(getTextRangeImpl(g));
     return xText->getString();
 }
 
 void Annotation::SetText(OUString const& rText)
 {
-    uno::Reference<text::XText> xText(getTextRange());
+    std::unique_lock g(m_aMutex);
+    SetTextImpl(rText, g);
+}
+
+void Annotation::SetTextImpl(OUString const& rText, const 
std::unique_lock<std::mutex>& g)
+{
+    uno::Reference<text::XText> xText(getTextRangeImpl(g));
     return xText->setString(rText);
 }
 
 uno::Reference<text::XText> SAL_CALL Annotation::getTextRange()
 {
     std::unique_lock g(m_aMutex);
+    return getTextRangeImpl(g);
+}
+
+uno::Reference<text::XText> Annotation::getTextRangeImpl(const 
std::unique_lock<std::mutex>& /*g*/)
+{
     if (!m_TextRange.is() && mpPage != nullptr)
     {
         m_TextRange = 
sdr::annotation::TextApiObject::create(&mpPage->getSdrModelFromSdrPage());
@@ -183,6 +166,18 @@ uno::Reference<text::XText> SAL_CALL 
Annotation::getTextRange()
     return m_TextRange;
 }
 
+void Annotation::SetPosition(const css::geometry::RealPoint2D& rValue)
+{
+    std::unique_lock g(m_aMutex);
+    m_Position = rValue;
+}
+
+void Annotation::SetSize(const css::geometry::RealSize2D& rValue)
+{
+    std::unique_lock g(m_aMutex);
+    m_Size = rValue;
+}
+
 void Annotation::disposing(std::unique_lock<std::mutex>& /*rGuard*/)
 {
     mpPage = nullptr;
@@ -210,6 +205,44 @@ SdrObject* Annotation::findAnnotationObject()
     return nullptr;
 }
 
+OString Annotation::ToJSON(CommentNotificationType nType)
+{
+    tools::JsonWriter aJsonWriter;
+
+    {
+        auto aCommentNode = aJsonWriter.startNode("comment");
+
+        aJsonWriter.put(
+            "action",
+            (nType == CommentNotificationType::Add
+                 ? "Add"
+                 : (nType == CommentNotificationType::Remove
+                        ? "Remove"
+                        : (nType == CommentNotificationType::Modify ? "Modify" 
: "???"))));
+
+        std::unique_lock g(m_aMutex);
+        sal_uInt64 id = maUniqueID.getID();
+        aJsonWriter.put("id", id);
+        if (nType != CommentNotificationType::Remove)
+        {
+            aJsonWriter.put("id", id);
+            aJsonWriter.put("author", m_Author);
+            aJsonWriter.put("dateTime", utl::toISO8601(m_DateTime));
+            aJsonWriter.put("text", GetTextImpl(g));
+            aJsonWriter.put("parthash",
+                            mpPage ? OString::number(mpPage->GetUniqueID()) : 
OString());
+            tools::Rectangle aRectangle(
+                Point(std::round(o3tl::toTwips(m_Position.X, 
o3tl::Length::mm)),
+                      std::round(o3tl::toTwips(m_Position.Y, 
o3tl::Length::mm))),
+                Size(std::round(o3tl::toTwips(m_Size.Width, o3tl::Length::mm)),
+                     std::round(o3tl::toTwips(m_Size.Height, 
o3tl::Length::mm))));
+            aJsonWriter.put("rectangle", aRectangle.toString());
+        }
+    }
+
+    return aJsonWriter.finishAndGetAsOString();
+}
+
 } // namespace sdr::annotation
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to