include/svx/sdr/animation/animationstate.hxx |    2 +
 svx/source/sdr/animation/animationstate.cxx  |    6 +++
 svx/source/sdr/contact/viewobjectcontact.cxx |   49 +++++++++++++++++----------
 3 files changed, 40 insertions(+), 17 deletions(-)

New commits:
commit 12baba92e0a581866c6dedea428e888dd0934d78
Author:     Noel Grandin <[email protected]>
AuthorDate: Tue Nov 25 08:19:54 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Tue Nov 25 11:52:46 2025 +0100

    tdf#169656 Crash upon starting animated GIF
    
    this is caused by freeing an object that is currently on the callstack.
    
    I dont have a complete fix here, this will fix it 99% of the time.
    
    regression from
      commit e6a8c40e5051363d5825bd09131b86cf8a2b659b
      Author: Noel Grandin <[email protected]>
      Date:   Tue Sep 30 14:54:37 2025 +0200
      tdf#116975 Laggy behavior when clicking between table cells in impress
    but only because it made it more obvious, this has been a lurking problem.
    
    Change-Id: I4f2f56a54a74f2a51e7ca05421d3db82de47f2ca
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194502
    Tested-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins
    Code-Style: Noel Grandin <[email protected]>
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/include/svx/sdr/animation/animationstate.hxx 
b/include/svx/sdr/animation/animationstate.hxx
index a2e079725df3..ad41a592666b 100644
--- a/include/svx/sdr/animation/animationstate.hxx
+++ b/include/svx/sdr/animation/animationstate.hxx
@@ -47,6 +47,8 @@ namespace sdr::animation
             // destructor
             virtual ~PrimitiveAnimation() override;
 
+            void 
SetPrimitives(drawinglayer::primitive2d::Primitive2DContainer&&);
+
             // execute event, from base class Event
             virtual void Trigger(sal_uInt32 nTime) override;
         };
diff --git a/svx/source/sdr/animation/animationstate.cxx 
b/svx/source/sdr/animation/animationstate.cxx
index 375bccaf0975..9690e25591dc 100644
--- a/svx/source/sdr/animation/animationstate.cxx
+++ b/svx/source/sdr/animation/animationstate.cxx
@@ -122,6 +122,12 @@ namespace sdr::animation
                 prepareNextEvent();
         }
 
+        void 
PrimitiveAnimation::SetPrimitives(drawinglayer::primitive2d::Primitive2DContainer&&
 rAnimatedPrimitives)
+        {
+            // called from ViewObjectContact::checkForPrimitive2DAnimations
+            maAnimatedPrimitives = std::move(rAnimatedPrimitives);
+        }
+
 } // end of namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx 
b/svx/source/sdr/contact/viewobjectcontact.cxx
index beb2163d4f0f..b1bef068102f 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -287,30 +287,45 @@ void ViewObjectContact::ActionChildInserted(ViewContact& 
rChild)
     // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
 }
 
+// Check for animated primitives.
 void ViewObjectContact::checkForPrimitive2DAnimations()
 {
-    // remove old one
-    mpPrimitiveAnimation.reset();
-
-    // check for animated primitives
-    if(mxPrimitive2DSequence.empty())
-        return;
-
-    const bool 
bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
-    const bool 
bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
-
-    if(bTextAnimationAllowed || bGraphicAnimationAllowed)
+    // Somewhat odd structure here, because we are trying to avoid deleting 
and re-allocating the mpPrimitiveAnimation
+    // object, because we might be inside a call from the Scheduler, in which 
case we will be deleting an object
+    // on the call stack.
+    // Yes, this does still leave a possible situation where the user could 
turn animations off while we are
+    // animating and we could crash. I dont have a better solution right now.
+    //
+    drawinglayer::primitive2d::Primitive2DContainer aNewAnimatedPrimitives;
+    if(!mxPrimitive2DSequence.empty())
     {
-        AnimatedExtractingProcessor2D 
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
-            bTextAnimationAllowed, bGraphicAnimationAllowed);
-        aAnimatedExtractor.process(mxPrimitive2DSequence);
+        const bool 
bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
+        const bool 
bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
 
-        if(!aAnimatedExtractor.getPrimitive2DSequence().empty())
+        if(bTextAnimationAllowed || bGraphicAnimationAllowed)
         {
-            // derived primitiveList is animated, setup new PrimitiveAnimation
-            mpPrimitiveAnimation.reset( new 
sdr::animation::PrimitiveAnimation(*this, 
aAnimatedExtractor.extractPrimitive2DSequence()) );
+            AnimatedExtractingProcessor2D 
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
+                bTextAnimationAllowed, bGraphicAnimationAllowed);
+            aAnimatedExtractor.process(mxPrimitive2DSequence);
+
+            if(!aAnimatedExtractor.getPrimitive2DSequence().empty())
+            {
+                // derived primitiveList is animated, setup new 
PrimitiveAnimation
+                aNewAnimatedPrimitives = 
aAnimatedExtractor.extractPrimitive2DSequence();
+            }
         }
     }
+    if (!aNewAnimatedPrimitives.empty())
+    {
+        // derived primitiveList is animated, setup new PrimitiveAnimation
+        if (mpPrimitiveAnimation)
+            
mpPrimitiveAnimation->SetPrimitives(std::move(aNewAnimatedPrimitives));
+        else
+            mpPrimitiveAnimation.reset( new 
sdr::animation::PrimitiveAnimation(*this, std::move(aNewAnimatedPrimitives)) );
+    }
+    else
+        // remove old one
+        mpPrimitiveAnimation.reset();
 }
 
 void ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& 
rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& 
rVisitor) const

Reply via email to