sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp |binary
 sd/qa/unit/tiledrendering/tiledrendering.cxx                     |  134 
+++++++---
 sd/source/ui/inc/SlideshowLayerRenderer.hxx                      |    7 
 sd/source/ui/tools/SlideshowLayerRenderer.cxx                    |   79 +++++
 4 files changed, 181 insertions(+), 39 deletions(-)

New commits:
commit 33301e862309838286669bc5ff1d68dc90d62cac
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Fri Aug 30 16:56:59 2024 +0200
Commit:     Szymon Kłos <szymon.k...@collabora.com>
CommitDate: Fri Sep 6 09:14:02 2024 +0200

    Render objects that are in an animation as a separate layer
    
    Change-Id: I4220b8398e75589bd54b67942cf987244b1d0b0c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172664
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp 
b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp
new file mode 100644
index 000000000000..b827e0a94cf6
Binary files /dev/null and 
b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp differ
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx 
b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index eab5a8f05669..fd654594c2b2 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -65,6 +65,32 @@
 
 using namespace css;
 
+namespace
+{
+
+void debugWriteImageToFile(unsigned step, const std::vector<sal_uInt8>& 
pBuffer,
+    unsigned nViewWidth, unsigned nViewHeight, const char* sJSON)
+{
+    (void)step;
+    (void)pBuffer;
+    (void)nViewWidth;
+    (void)nViewHeight;
+    (void)sJSON;
+
+#if false
+    printf ("%u %s

", step, sJSON);
+
+    BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
+
+    OUString sFileName = "/tmp/slideshow_" + OUString::number(step) + ".png";
+    SvFileStream aStream(sFileName, StreamMode::WRITE | StreamMode::TRUNC);
+    vcl::PngImageWriter aPNGWriter(aStream);
+    aPNGWriter.write(aBitmapEx);
+#endif
+}
+
+}
+
 static std::ostream& operator<<(std::ostream& os, ViewShellId id)
 {
     os << static_cast<sal_Int32>(id);
@@ -3174,8 +3200,6 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering)
     // - master slide layer
     // - main slide layer
 
-    const bool bOutputPNG = false; // Control layer output to PNG files
-
     SdXImpressDocument* pXImpressDocument = 
createDoc("SlideRenderingTest.odp");
     
pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
     sd::ViewShell* pViewShell = 
pXImpressDocument->GetDocShell()->GetViewShell();
@@ -3196,15 +3220,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering)
         
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
         CPPUNIT_ASSERT(bIsBitmapLayer);
         // TODO - check JSON content
-        // printf ("1 %s

", rJsonMsg.toUtf8().getStr());
 
         BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
-        if (bOutputPNG)
-        {
-            SvFileStream aStream("/home/quikee/XXX_01.png", StreamMode::WRITE 
| StreamMode::TRUNC);
-            vcl::PngImageWriter aPNGWriter(aStream);
-            aPNGWriter.write(aBitmapEx);
-        }
+        debugWriteImageToFile(1, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
 
         // top-left corner
         CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, 
20));
@@ -3223,15 +3241,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering)
         
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
         CPPUNIT_ASSERT(bIsBitmapLayer);
         // TODO - check JSON content
-        // printf ("2 %s

", rJsonMsg.toUtf8().getStr());
+        debugWriteImageToFile(2, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
 
         BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
-        if (bOutputPNG)
-        {
-            SvFileStream aStream("/home/quikee/XXX_02.png", StreamMode::WRITE 
| StreamMode::TRUNC);
-            vcl::PngImageWriter aPNGWriter(aStream);
-            aPNGWriter.write(aBitmapEx);
-        }
 
         // top-left corner
         CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x50, 0x90), 
aBitmapEx.GetPixelColor(20, 20));
@@ -3258,8 +3270,6 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_WithFie
     // - master slide layer
     // - main slide layer
 
-    const bool bOutputPNG = false; // Control layer output to PNG files
-
     SdXImpressDocument* pXImpressDocument = 
createDoc("SlideRenderingTest_WithFields.odp");
     
pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
     sd::ViewShell* pViewShell = 
pXImpressDocument->GetDocShell()->GetViewShell();
@@ -3280,15 +3290,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_WithFie
         
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
         CPPUNIT_ASSERT(bIsBitmapLayer);
         // TODO - check JSON content
-        // printf ("1 %s

", rJsonMsg.toUtf8().getStr());
+        debugWriteImageToFile(1, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
 
         BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
-        if (bOutputPNG)
-        {
-            SvFileStream aStream("/home/quikee/XXX_01.png", StreamMode::WRITE 
| StreamMode::TRUNC);
-            vcl::PngImageWriter aPNGWriter(aStream);
-            aPNGWriter.write(aBitmapEx);
-        }
 
         // top-left corner
         CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, 
20));
@@ -3307,15 +3311,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_WithFie
         
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
         CPPUNIT_ASSERT(bIsBitmapLayer);
         // TODO - check JSON content
-        // printf ("2 %s

", rJsonMsg.toUtf8().getStr());
+        debugWriteImageToFile(2, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
 
         BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
-        if (bOutputPNG)
-        {
-            SvFileStream aStream("/home/quikee/XXX_02.png", StreamMode::WRITE 
| StreamMode::TRUNC);
-            vcl::PngImageWriter aPNGWriter(aStream);
-            aPNGWriter.write(aBitmapEx);
-        }
 
         // top-left corner
         CPPUNIT_ASSERT_EQUAL(aTransparentColor, aBitmapEx.GetPixelColor(20, 
20));
@@ -3334,15 +3332,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_WithFie
         
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
         CPPUNIT_ASSERT(bIsBitmapLayer);
         // TODO - check JSON content
-        // printf ("3 %s

", rJsonMsg.toUtf8().getStr());
+        debugWriteImageToFile(3, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
 
         BitmapEx aBitmapEx = vcl::bitmap::CreateFromData(pBuffer.data(), 
nViewWidth, nViewHeight, nViewWidth * 4, /*nBitsPerPixel*/32, true, true);
-        if (bOutputPNG)
-        {
-            SvFileStream aStream("/home/quikee/XXX_03.png", StreamMode::WRITE 
| StreamMode::TRUNC);
-            vcl::PngImageWriter aPNGWriter(aStream);
-            aPNGWriter.write(aBitmapEx);
-        }
 
         // top-left corner
         CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x50, 0x90), 
aBitmapEx.GetPixelColor(20, 20));
@@ -3364,6 +3356,70 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_WithFie
     pXImpressDocument->postSlideshowCleanup();
 }
 
+CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, 
testSlideshowLayeredRendering_Animations)
+{
+    SdXImpressDocument* pXImpressDocument = 
createDoc("SlideRenderingTest_Animations.odp");
+    
pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+    sd::ViewShell* pViewShell = 
pXImpressDocument->GetDocShell()->GetViewShell();
+    CPPUNIT_ASSERT(pViewShell);
+    SdPage* pPage = pViewShell->GetActualPage();
+    CPPUNIT_ASSERT(pPage);
+    sal_Int32 nViewWidth = 2000;
+    sal_Int32 nViewHeight = 2000;
+    CPPUNIT_ASSERT(pXImpressDocument->createSlideRenderer(0, nViewWidth, 
nViewHeight, true, true));
+    CPPUNIT_ASSERT_EQUAL(2000, nViewWidth);
+    CPPUNIT_ASSERT_EQUAL(1125, nViewHeight);
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+        CPPUNIT_ASSERT(bIsBitmapLayer);
+        // TODO - check JSON content
+        debugWriteImageToFile(1, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+        CPPUNIT_ASSERT(bIsBitmapLayer);
+        // TODO - check JSON content
+        debugWriteImageToFile(2, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+        CPPUNIT_ASSERT(bIsBitmapLayer);
+        // TODO - check JSON content
+        debugWriteImageToFile(3, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        
CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+        CPPUNIT_ASSERT(bIsBitmapLayer);
+        // TODO - check JSON content
+        debugWriteImageToFile(4, pBuffer, nViewWidth, nViewHeight, 
rJsonMsg.toUtf8().getStr());
+    }
+
+    {
+        std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4);
+        bool bIsBitmapLayer = false;
+        OUString rJsonMsg;
+        CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), 
bIsBitmapLayer, rJsonMsg));
+    }
+
+    pXImpressDocument->postSlideshowCleanup();
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/inc/SlideshowLayerRenderer.hxx 
b/sd/source/ui/inc/SlideshowLayerRenderer.hxx
index 7f26d9b23b52..d0b49398ce5b 100644
--- a/sd/source/ui/inc/SlideshowLayerRenderer.hxx
+++ b/sd/source/ui/inc/SlideshowLayerRenderer.hxx
@@ -40,6 +40,7 @@ struct RenderState
     bool mbStopRenderingWhenField = true;
 
     std::unordered_set<SdrObject*> maObjectsDone;
+    std::unordered_set<SdrObject*> maInAnimation;
     sal_Int32 mnIndex = 0;
 
     bool mbFirstObjectInPass = true;
@@ -99,6 +100,11 @@ struct RenderState
     {
         return maObjectsDone.find(pObject) != maObjectsDone.end();
     }
+
+    bool isObjectInAnimation(SdrObject* pObject)
+    {
+        return maInAnimation.find(pObject) != maInAnimation.end();
+    }
 };
 
 /** Renders a slide */
@@ -112,6 +118,7 @@ private:
 
     void createViewAndDraw(RenderContext& rRenderContext);
     void writeJSON(OString& rJsonMsg);
+    void setupAnimations();
 
 public:
     SlideshowLayerRenderer(SdrPage& rPage);
diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx 
b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
index a9bc564bf1ea..32a8a5d7dea9 100644
--- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx
+++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
@@ -22,6 +22,18 @@
 #include <tools/json_writer.hxx>
 #include <editeng/editeng.hxx>
 
+#include <com/sun/star/animations/XAnimate.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+
+#include <animations/animationnodehelper.hxx>
+#include <sdpage.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <svx/unoshape.hxx>
+
+using namespace ::com::sun::star;
+
 namespace sd
 {
 struct RenderContext
@@ -144,6 +156,11 @@ public:
             }
         }
 
+        if (mrRenderState.isObjectInAnimation(pObject))
+        {
+            mrRenderState.mbSkipAllInThisPass = true;
+        }
+
         if (mrRenderState.meStage == RenderStage::Master && hasFields(pObject)
             && mrRenderState.mbStopRenderingWhenField && 
!mrRenderState.mbFirstObjectInPass)
         {
@@ -187,6 +204,68 @@ SlideshowLayerRenderer::SlideshowLayerRenderer(SdrPage& 
rPage)
         maRenderState.meStage = RenderStage::Master;
     else
         maRenderState.meStage = RenderStage::Slide;
+
+    setupAnimations();
+}
+
+void SlideshowLayerRenderer::setupAnimations()
+{
+    auto* pSdPage = dynamic_cast<SdPage*>(&mrPage);
+
+    if (!pSdPage)
+        return;
+
+    std::vector<uno::Reference<animations::XAnimationNode>> aAnimationVector;
+    anim::create_deep_vector(pSdPage->getAnimationNode(), aAnimationVector);
+
+    for (uno::Reference<animations::XAnimationNode> const& rNode : 
aAnimationVector)
+    {
+        switch (rNode->getType())
+        {
+            // filter out the most obvious
+            case animations::AnimationNodeType::CUSTOM:
+            case animations::AnimationNodeType::ANIMATE:
+            case animations::AnimationNodeType::SET:
+            case animations::AnimationNodeType::ANIMATEMOTION:
+            case animations::AnimationNodeType::ANIMATECOLOR:
+            case animations::AnimationNodeType::ANIMATETRANSFORM:
+            case animations::AnimationNodeType::TRANSITIONFILTER:
+            case animations::AnimationNodeType::ANIMATEPHYSICS:
+            {
+                uno::Reference<animations::XAnimate> xAnimate(rNode, 
uno::UNO_QUERY);
+                if (xAnimate.is())
+                {
+                    uno::Any aAny = xAnimate->getTarget();
+
+                    uno::Reference<drawing::XShape> xShape;
+                    if ((aAny >>= xShape) && xShape.is())
+                    {
+                        SvxShape* pShape = 
comphelper::getFromUnoTunnel<SvxShape>(xShape);
+                        if (pShape)
+                        {
+                            
maRenderState.maInAnimation.insert(pShape->GetSdrObject());
+                        }
+                    }
+                    else // if target is not a shape
+                    {
+                        presentation::ParagraphTarget aParagraphTarget;
+                        if ((aAny >>= aParagraphTarget) && 
aParagraphTarget.Shape.is())
+                        {
+                            //sal_Int32 nParagraph = 
aParagraphTarget.Paragraph;
+
+                            xShape = aParagraphTarget.Shape;
+
+                            SvxShape* pShape = 
comphelper::getFromUnoTunnel<SvxShape>(xShape);
+                            if (pShape)
+                            {
+                                
maRenderState.maInAnimation.insert(pShape->GetSdrObject());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
 }
 
 Size SlideshowLayerRenderer::calculateAndSetSizePixel(Size const& 
rDesiredSizePixel)

Reply via email to