include/svx/sdr/contact/viewobjectcontact.hxx |    3 +++
 svx/source/sdr/contact/viewobjectcontact.cxx  |   18 ++++++++++++++----
 2 files changed, 17 insertions(+), 4 deletions(-)

New commits:
commit b33a4d3c4acc37b9284c611caaaa661d2fe34db8
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Fri Dec 17 10:54:59 2021 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Dec 17 11:21:25 2021 +0100

    fix for crash converting ooo31011-1.sxw and tdf#146132
    
    ./instdir/program/soffice.bin --headless --convert-to odt
    ./ooo31011-1.sxw
    
    regression from
        commit 681e10eecf67a1a01bdec2cc9b834e0345e25206
        Author: Noel Grandin <noel.gran...@collabora.co.uk>
        Date:   Thu Dec 9 11:12:49 2021 +0200
        tdf#146137 tdf#146132 image redrawing
    
    It is because we cache high-level primitives, and then during paint, we
    decompose those high-level primitives, and that triggers layout,
    which triggers an invalidate i.e. an ActionChanged(), which blows
    away the cached data we are iterating over.
    
    Change-Id: Id18e47b6c2b71a5404f24b075a43d2040a5e3509
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126995
    Tested-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/include/svx/sdr/contact/viewobjectcontact.hxx 
b/include/svx/sdr/contact/viewobjectcontact.hxx
index f13f247e55c2..7cee496afdb2 100644
--- a/include/svx/sdr/contact/viewobjectcontact.hxx
+++ b/include/svx/sdr/contact/viewobjectcontact.hxx
@@ -59,6 +59,9 @@ private:
     // possible on-demand calculated GridOffset for non-linear ViewToDevice 
transformation (calc)
     basegfx::B2DVector                              maGridOffset;
 
+    // used to to detect ActionChanged() during primitive construction
+    int                                             mnActionChangedCount;
+
     // This bool gets set when the object gets invalidated by ActionChanged() 
and
     // can be used from the OC to late-invalidates
     bool                                            mbLazyInvalidate : 1;
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index 9dcac9eb153c..8b8f0c3250d7 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -147,6 +147,7 @@ ViewObjectContact::ViewObjectContact(ObjectContact& 
rObjectContact, ViewContact&
 :   mrObjectContact(rObjectContact),
     mrViewContact(rViewContact),
     maGridOffset(0.0, 0.0),
+    mnActionChangedCount(0),
     mbLazyInvalidate(false)
 {
     // make the ViewContact remember me
@@ -210,6 +211,7 @@ void ViewObjectContact::ActionChanged()
 {
     // clear cached primitives
     mxPrimitive2DSequence.clear();
+    ++mnActionChangedCount;
 
     if(mbLazyInvalidate)
         return;
@@ -345,7 +347,7 @@ drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPr
     drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence;
 
     // take care of redirectors and create new list
-    ViewObjectContactRedirector* pRedirector = 
GetObjectContact().GetViewObjectContactRedirector();
+    ViewObjectContactRedirector* pRedirector = 
GetObjectContact().GetViewObjectContactRedirector();\
 
     if(pRedirector)
     {
@@ -421,8 +423,8 @@ void 
ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInf
     if(!isPrimitiveVisible(rDisplayInfo))
         return;
 
-    const drawinglayer::primitive2d::Primitive2DContainer& xRetval = 
getPrimitive2DSequence(rDisplayInfo);
-    if(xRetval.empty())
+    getPrimitive2DSequence(rDisplayInfo);
+    if(mxPrimitive2DSequence.empty())
         return;
 
     // get ranges
@@ -434,7 +436,15 @@ void 
ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInf
     if(!bVisible)
         return;
 
-    rVisitor.visit(xRetval);
+    // temporarily take over the mxPrimitive2DSequence, in case it gets 
invalidated while we want to iterate over it
+    auto tmp = 
std::move(const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence);
+    int nPrevCount = mnActionChangedCount;
+
+    rVisitor.visit(tmp);
+
+    // if we received ActionChanged() calls while walking the primitives, then 
leave it empty, otherwise move it back
+    if (mnActionChangedCount == nPrevCount)
+        const_cast<ViewObjectContact*>(this)->mxPrimitive2DSequence = 
std::move(tmp);
 }
 
 void ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& 
rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& 
rVisitor) const

Reply via email to