diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2024-08-30 16:56:59 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2024-11-22 16:51:26 +0100 |
commit | 180a99d9ffe156a79a0d49bd0d5bd9c5d5f05ca9 (patch) | |
tree | 1f8858994fe248586fa603bdc19556b31c72b671 | |
parent | a680e71b50e8957674f432a6b8c7adb1ee0cd70d (diff) |
Render objects that are in an animation as a separate layer
Change-Id: I4220b8398e75589bd54b67942cf987244b1d0b0c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177035
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp | bin | 0 -> 15242 bytes | |||
-rw-r--r-- | sd/qa/unit/tiledrendering/tiledrendering.cxx | 134 | ||||
-rw-r--r-- | sd/source/ui/inc/SlideshowLayerRenderer.hxx | 7 | ||||
-rw-r--r-- | sd/source/ui/tools/SlideshowLayerRenderer.cxx | 79 |
4 files changed, 181 insertions, 39 deletions
diff --git a/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp Binary files differnew file mode 100644 index 000000000000..b827e0a94cf6 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx index 49812ce6788f..f08f2a919831 100644 --- a/sd/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -59,6 +59,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\n\n", 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); @@ -2754,8 +2780,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(); @@ -2776,15 +2800,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering) CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); CPPUNIT_ASSERT(bIsBitmapLayer); // TODO - check JSON content - // printf ("1 %s\n\n", 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)); @@ -2803,15 +2821,9 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering) CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, rJsonMsg)); CPPUNIT_ASSERT(bIsBitmapLayer); // TODO - check JSON content - // printf ("2 %s\n\n", 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)); @@ -2838,8 +2850,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(); @@ -2860,15 +2870,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\n\n", 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)); @@ -2887,15 +2891,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\n\n", 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)); @@ -2914,15 +2912,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\n\n", 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)); @@ -2944,6 +2936,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 dfe697a5cf9c..805541e3e857 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 3e1297225d4c..6d8b4c08dc22 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) |