summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2024-08-30 16:56:59 +0200
committerMiklos Vajna <vmiklos@collabora.com>2024-11-22 16:51:26 +0100
commit180a99d9ffe156a79a0d49bd0d5bd9c5d5f05ca9 (patch)
tree1f8858994fe248586fa603bdc19556b31c72b671
parenta680e71b50e8957674f432a6b8c7adb1ee0cd70d (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.odpbin0 -> 15242 bytes
-rw-r--r--sd/qa/unit/tiledrendering/tiledrendering.cxx134
-rw-r--r--sd/source/ui/inc/SlideshowLayerRenderer.hxx7
-rw-r--r--sd/source/ui/tools/SlideshowLayerRenderer.cxx79
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
new file mode 100644
index 000000000000..b827e0a94cf6
--- /dev/null
+++ b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_Animations.odp
Binary files differ
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)