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)