include/svx/sdr/contact/viewobjectcontact.hxx            |   12 ++++-
 svx/source/sdr/contact/viewobjectcontact.cxx             |   32 ++++++++++-----
 svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx |    6 ++
 3 files changed, 39 insertions(+), 11 deletions(-)

New commits:
commit d2b03c4bfa284efbb45cb4904122e97439d3ee06
Author:     Noel Grandin <n...@peralex.com>
AuthorDate: Mon Dec 6 15:58:19 2021 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Mon Dec 6 19:46:10 2021 +0100

    Revert "lose the caching in ViewObjectContact" because it breaks...
    
    bitmap caching. Added some notes for future would-be optimizers.
    
    This reverts commit 7f02cb80ac2075b65ee1adee4e29d1d5c4819424.
    
    Change-Id: I39c41ea95d23d4a65edd3cef46a5d86fab48a044
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126425
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>
    Tested-by: Jenkins

diff --git a/include/svx/sdr/contact/viewobjectcontact.hxx 
b/include/svx/sdr/contact/viewobjectcontact.hxx
index 56deadd59afe..f13f247e55c2 100644
--- a/include/svx/sdr/contact/viewobjectcontact.hxx
+++ b/include/svx/sdr/contact/viewobjectcontact.hxx
@@ -48,6 +48,11 @@ private:
     // This range defines the object's BoundRect
     basegfx::B2DRange                               maObjectRange;
 
+    // PrimitiveSequence of the ViewContact. This contains all necessary 
information
+    // for the graphical visualisation and needs to be supported by all VCs 
which
+    // can be visualized.
+    drawinglayer::primitive2d::Primitive2DContainer  mxPrimitive2DSequence;
+
     // the PrimitiveAnimation if Primitive2DContainer contains animations
     std::unique_ptr<sdr::animation::PrimitiveAnimation> mpPrimitiveAnimation;
 
@@ -64,7 +69,7 @@ protected:
 
     // Called from getPrimitive2DSequence() when vector has changed. Evaluate 
object animation
     // and setup accordingly
-    void checkForPrimitive2DAnimations(const 
drawinglayer::primitive2d::Primitive2DContainer& );
+    void checkForPrimitive2DAnimations();
 
     // This method is responsible for creating the graphical visualisation 
data which is
     // stored/cached in the local primitive. Default gets view-independent 
Primitive
@@ -73,6 +78,9 @@ protected:
     // This method will not handle included hierarchies and not check 
geometric visibility.
     virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, 
drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const;
 
+    // method for flushing Primitive2DContainer for VOC implementations
+    void flushPrimitive2DSequence() { mxPrimitive2DSequence.clear(); }
+
 public:
     // basic constructor.
     ViewObjectContact(ObjectContact& rObjectContact, ViewContact& 
rViewContact);
@@ -103,7 +111,7 @@ public:
     // access to the local primitive. This will ensure that the local 
primitive is
     // current in comparing the local one with a fresh created incarnation
     // This method will not handle included hierarchies and not check 
visibility.
-    drawinglayer::primitive2d::Primitive2DContainer 
getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const;
+    drawinglayer::primitive2d::Primitive2DContainer const & 
getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const;
 
     // test this VOC for visibility concerning model-view stuff like e.g. Layer
     virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const;
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index c72c34dfaccb..1dd8fef29415 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -263,13 +263,13 @@ void ViewObjectContact::ActionChildInserted(ViewContact& 
rChild)
     // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
 }
 
-void ViewObjectContact::checkForPrimitive2DAnimations(const 
drawinglayer::primitive2d::Primitive2DContainer& xPrimitive2DSequence)
+void ViewObjectContact::checkForPrimitive2DAnimations()
 {
     // remove old one
     mpPrimitiveAnimation.reset();
 
     // check for animated primitives
-    if(xPrimitive2DSequence.empty())
+    if(mxPrimitive2DSequence.empty())
         return;
 
     const bool 
bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
@@ -279,7 +279,7 @@ void ViewObjectContact::checkForPrimitive2DAnimations(const 
drawinglayer::primit
     {
         AnimatedExtractingProcessor2D 
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
             bTextAnimationAllowed, bGraphicAnimationAllowed);
-        aAnimatedExtractor.process(xPrimitive2DSequence);
+        aAnimatedExtractor.process(mxPrimitive2DSequence);
 
         if(!aAnimatedExtractor.getPrimitive2DSequence().empty())
         {
@@ -328,8 +328,14 @@ void ViewObjectContact::createPrimitive2DSequence(const 
DisplayInfo& rDisplayInf
     rVisitor.visit(xRetval);
 }
 
-drawinglayer::primitive2d::Primitive2DContainer 
ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
+drawinglayer::primitive2d::Primitive2DContainer const & 
ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
 {
+    /**
+    This method is weird because
+    (1) we have to re-walk the primitive tree because the flushing is 
unreliable
+    (2) we cannot just always use the new data because the old data has cached 
bitmaps in it e.g. see the documents in tdf#104878
+    */
+
     drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence;
 
     // take care of redirectors and create new list
@@ -344,12 +350,19 @@ drawinglayer::primitive2d::Primitive2DContainer 
ViewObjectContact::getPrimitive2
         createPrimitive2DSequence(rDisplayInfo, xNewPrimitiveSequence);
     }
 
+    // local up-to-date checks. New list different from local one?
+    if(mxPrimitive2DSequence == xNewPrimitiveSequence)
+        return mxPrimitive2DSequence;
+
+    // has changed, copy content
+    const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = 
std::move(xNewPrimitiveSequence);
+
     // check for animated stuff
-    const_cast< ViewObjectContact* 
>(this)->checkForPrimitive2DAnimations(xNewPrimitiveSequence);
+    const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations();
 
     // always update object range when PrimitiveSequence changes
     const drawinglayer::geometry::ViewInformation2D& 
rViewInformation2D(GetObjectContact().getViewInformation2D());
-    const_cast< ViewObjectContact* >(this)->maObjectRange = 
xNewPrimitiveSequence.getB2DRange(rViewInformation2D);
+    const_cast< ViewObjectContact* >(this)->maObjectRange = 
mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
 
     // check and eventually embed to GridOffset transform primitive
     if(GetObjectContact().supportsGridOffsets())
@@ -364,7 +377,7 @@ drawinglayer::primitive2d::Primitive2DContainer 
ViewObjectContact::getPrimitive2
             drawinglayer::primitive2d::Primitive2DReference aEmbed(
                  new drawinglayer::primitive2d::TransformPrimitive2D(
                     aTranslateGridOffset,
-                    std::move(xNewPrimitiveSequence)));
+                    std::move(const_cast< ViewObjectContact* 
>(this)->mxPrimitive2DSequence)));
 
             // Set values at local data. So for now, the mechanism is to reset 
some of the
             // defining things (mxPrimitive2DSequence, maGridOffset) and 
re-create the
@@ -375,13 +388,13 @@ drawinglayer::primitive2d::Primitive2DContainer 
ViewObjectContact::getPrimitive2
             // just allow re-creation of the PrimitiveSequence (and removing 
buffered
             // decomposed content of it). May be optimized, though. OTOH it 
only happens
             // in calc which traditionally does not have a huge amount of 
DrawObjects anyways.
-            xNewPrimitiveSequence = 
drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
+            const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = 
drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
             const_cast< ViewObjectContact* 
>(this)->maObjectRange.transform(aTranslateGridOffset);
         }
     }
 
     // return current Primitive2DContainer
-    return xNewPrimitiveSequence;
+    return mxPrimitive2DSequence;
 }
 
 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& 
/*rDisplayInfo*/) const
@@ -452,6 +465,7 @@ void ViewObjectContact::resetGridOffset()
     maGridOffset.setY(0.0);
 
     // also reset sequence to get a re-calculation when GridOffset changes
+    mxPrimitive2DSequence.clear();
     maObjectRange.reset();
 }
 
diff --git a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx 
b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
index 4881954b2eb1..4c0f54d93b1f 100644
--- a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -1747,6 +1747,12 @@ namespace sdr::contact {
     {
         // graphical invalidate at all views
         ActionChanged();
+
+        // #i93318# flush Primitive2DContainer to force recreation with 
updated XControlModel
+        // since e.g. background color has changed and existing decompositions 
are possibly no
+        // longer valid. Unfortunately this is not detected from 
ControlPrimitive2D::operator==
+        // since it only has a uno reference to the XControlModel
+        flushPrimitive2DSequence();
     }
 
     UnoControlPrintOrPreviewContact::UnoControlPrintOrPreviewContact( 
ObjectContactOfPageView& _rObjectContact, ViewContactOfUnoControl& 
_rViewContact )

Reply via email to