sd/qa/unit/tiledrendering/data/SlideRenderingTest_SlideNumber_Header_DateTime.odp |binary sd/qa/unit/tiledrendering/tiledrendering.cxx | 212 ++++++++++ sd/source/ui/inc/SlideshowLayerRenderer.hxx | 29 - sd/source/ui/tools/SlideshowLayerRenderer.cxx | 186 +++++++- 4 files changed, 377 insertions(+), 50 deletions(-)
New commits: commit 036235278ce569ea657fa7f07ac6b2de40301da2 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu Oct 24 18:12:18 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Mar 18 14:41:49 2025 +0100 slideshow: render fields slide number, footer, date/time Add support for rendering of slide number, footer and date/time fields to slide layer renderer, with the compatible JSON output. But still keep the more generic field rendering in. Change-Id: Ieaa31c15dc86c3e0dab6d13d914756abace667d4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183065 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sd/qa/unit/tiledrendering/data/SlideRenderingTest_SlideNumber_Header_DateTime.odp b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_SlideNumber_Header_DateTime.odp new file mode 100644 index 000000000000..475d54f89480 Binary files /dev/null and b/sd/qa/unit/tiledrendering/data/SlideRenderingTest_SlideNumber_Header_DateTime.odp differ diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx index 752b324419b5..76c449705e01 100644 --- a/sd/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -3121,6 +3121,218 @@ CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering_WithFie pXImpressDocument->postSlideshowCleanup(); } +CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering_SlideNumber_Header_DateTime) +{ + SdXImpressDocument* pXImpressDocument = createDoc("SlideRenderingTest_SlideNumber_Header_DateTime.odp"); + pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + CPPUNIT_ASSERT(pViewShell); + SdPage* pPage = pViewShell->GetActualPage(); + + CPPUNIT_ASSERT(pPage); + std::string sHash = GetInterfaceHash(GetXDrawPageForSdrPage(pPage)); + sal_Int32 nViewWidth = 2000; + sal_Int32 nViewHeight = 2000; + CPPUNIT_ASSERT(pXImpressDocument->createSlideRenderer(sHash.c_str(), 0, nViewWidth, nViewHeight, true, true)); + CPPUNIT_ASSERT_EQUAL(2000, nViewWidth); + CPPUNIT_ASSERT_EQUAL(1125, nViewHeight); + + // Background Layer + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + debugWriteImageToFile(0, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("Background"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(0, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(std::string("bitmap"), aTree.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(1, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("MasterPage"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(0, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(std::string("placeholder"), aTree.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("DateTime"), aContentChild.get_child("type").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(2, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("MasterPage"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(1, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(std::string("placeholder"), aTree.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("Footer"), aContentChild.get_child("type").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(3, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("MasterPage"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(2, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(std::string("placeholder"), aTree.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("SlideNumber"), aContentChild.get_child("type").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(4, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("DrawPage"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(0, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(std::string("bitmap"), aTree.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(5, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("TextFields"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(0, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("DateTime"), aContentChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aContentChild, "content")); + auto aContentChildChild = aContentChild.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGETYPE%"), aContentChildChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGECHECKSUM%"), aContentChildChild.get_child("checksum").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(6, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("TextFields"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(1, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("Footer"), aContentChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aContentChild, "content")); + auto aContentChildChild = aContentChild.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGETYPE%"), aContentChildChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGECHECKSUM%"), aContentChildChild.get_child("checksum").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(bIsBitmapLayer); + + debugWriteImageToFile(6, pBuffer, nViewWidth, nViewHeight, aJson.toUtf8().getStr()); + + boost::property_tree::ptree aTree; + readJSON(aTree, aJson); + + CPPUNIT_ASSERT_EQUAL(std::string("TextFields"), aTree.get_child("group").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(2, aTree.get_child("index").get_value<int>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aTree, "content")); + { + auto aContentChild = aTree.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("SlideNumber"), aContentChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(true, has_child(aContentChild, "content")); + auto aContentChildChild = aContentChild.get_child("content"); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGETYPE%"), aContentChildChild.get_child("type").get_value<std::string>()); + CPPUNIT_ASSERT_EQUAL(std::string("%IMAGECHECKSUM%"), aContentChildChild.get_child("checksum").get_value<std::string>()); + } + } + + { + std::vector<sal_uInt8> pBuffer(nViewWidth * nViewHeight * 4); + bool bIsBitmapLayer = false; + OUString aJson; + double dScale = 1.0; + CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, dScale, aJson)); + CPPUNIT_ASSERT(aJson.isEmpty()); + } + + pXImpressDocument->postSlideshowCleanup(); +} + CPPUNIT_TEST_FIXTURE(SdTiledRenderingTest, testSlideshowLayeredRendering_Animations) { // Check rendering of animated objects - each in own layer diff --git a/sd/source/ui/inc/SlideshowLayerRenderer.hxx b/sd/source/ui/inc/SlideshowLayerRenderer.hxx index cfadb19ba346..d76367adee73 100644 --- a/sd/source/ui/inc/SlideshowLayerRenderer.hxx +++ b/sd/source/ui/inc/SlideshowLayerRenderer.hxx @@ -72,8 +72,10 @@ struct RenderPass bool mbRenderObjectBackground = false; bool mbAnimation = false; - SdrObject* mpAnimatedObject = nullptr; - sal_Int32 mnAnimatedParagraph = -1; + SdrObject* mpObject = nullptr; + sal_Int32 mnParagraph = -1; + bool mbPlaceholder = false; + OUString maFieldType; bool isEmpty() { return maObjectsAndParagraphs.empty(); } }; @@ -82,6 +84,7 @@ struct RenderPass struct RenderState { std::deque<RenderPass> maRenderPasses; + std::vector<RenderPass> maTextFields; RenderStage meStage = RenderStage::Background; @@ -92,6 +95,11 @@ struct RenderState SdrObject* mpCurrentTarget = nullptr; sal_Int32 mnCurrentTargetParagraph = -1; + bool mbShowMasterPageObjects = false; + bool mbFooterEnabled = false; + bool mbDateTimeEnabled = false; + bool mbSlideNumberEnabled = false; + /// increments index depending on the current render stage void incrementIndex() { maIndices[size_t(meStage)]++; } @@ -110,19 +118,6 @@ struct RenderState /// returns the current index depending on the current render stage sal_Int32 currentIndex() const { return maIndices[size_t(meStage)]; } - /// returns the current target element for which layer is created if any - SdrObject* currentTarget() const { return mpCurrentTarget; } - - /// returns the current target paragraph index or -1 if paragraph is not relevant - sal_Int32 currentTargetParagraph() const { return mnCurrentTargetParagraph; } - - /// resets properties that are valid for one pass - void resetPass() - { - mpCurrentTarget = nullptr; - mnCurrentTargetParagraph = -1; - } - /// should include background in rendering bool includeBackground() const { return meStage == RenderStage::Background; } }; @@ -138,9 +133,11 @@ private: void createViewAndDraw(RenderContext& rRenderContext, sdr::contact::ViewObjectContactRedirector* pRedirector); - void writeJSON(OString& rJsonMsg); + void writeBackgroundJSON(OString& rJsonMsg); + void writeJSON(OString& rJsonMsg, RenderPass const& rRenderPass); void setupAnimations(); + void setupMasterPageFields(); void resolveEffect(CustomAnimationEffectPtr const& rEffect); public: diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx b/sd/source/ui/tools/SlideshowLayerRenderer.cxx index c231b077d52c..e63e76be30b7 100644 --- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx +++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx @@ -24,6 +24,8 @@ #include <editeng/editeng.hxx> #include <animations/animationnodehelper.hxx> #include <sdpage.hxx> +#include <drawdoc.hxx> +#include <unokywds.hxx> #include <comphelper/servicehelper.hxx> #include <com/sun/star/animations/XAnimate.hpp> @@ -227,19 +229,12 @@ void modifyParagraphs(drawinglayer::primitive2d::Primitive2DContainer& rContaine /// Analyze the rendering and create rendering passes class AnalyzeRenderingRedirector : public sdr::contact::ViewObjectContactRedirector { -protected: +private: RenderState& mrRenderState; RenderPass* mpCurrentRenderPass; RenderStage mePreviousStage = RenderStage::Master; -public: - AnalyzeRenderingRedirector(RenderState& rRenderState) - : mrRenderState(rRenderState) - , mpCurrentRenderPass(newRenderPass()) - { - } - // Adds a new rendering pass to the list and returns it RenderPass* newRenderPass() { @@ -256,6 +251,48 @@ public: mpCurrentRenderPass = newRenderPass(); } + OUString getMasterTextFieldString(SdrObject* pObject) + { + OUString aType; + + uno::Reference<drawing::XShape> xShape = pObject->getUnoShape(); + if (!xShape.is()) + return aType; + + OUString sShapeType = xShape->getShapeType(); + + if (mrRenderState.mbSlideNumberEnabled + && sShapeType == u"com.sun.star.presentation.SlideNumberShape") + aType = u"SlideNumber"_ustr; + else if (mrRenderState.mbFooterEnabled + && sShapeType == u"com.sun.star.presentation.FooterShape") + aType = u"Footer"_ustr; + else if (mrRenderState.mbDateTimeEnabled + && sShapeType == u"com.sun.star.presentation.DateTimeShape") + aType = u"DateTime"_ustr; + + return aType; + } + +public: + AnalyzeRenderingRedirector(RenderState& rRenderState) + : mrRenderState(rRenderState) + , mpCurrentRenderPass(newRenderPass()) + { + } + + void finalizeRenderPasses() + { + // Last rendering pass might be empty - delete + if (mrRenderState.maRenderPasses.back().isEmpty()) + mrRenderState.maRenderPasses.pop_back(); + + for (auto& rRenderWork : mrRenderState.maTextFields) + { + mrRenderState.maRenderPasses.push_back(rRenderWork); + } + } + virtual void createRedirectedPrimitive2DSequence( const sdr::contact::ViewObjectContact& rOriginal, const sdr::contact::DisplayInfo& rDisplayInfo, @@ -288,6 +325,8 @@ public: if (eCurrentStage == RenderStage::Slide && mePreviousStage == RenderStage::Master) closeRenderPass(); + OUString sTextFieldString = getMasterTextFieldString(pObject); + // check if object is in an animation auto aIterator = mrRenderState.maAnimationRenderInfoList.find(pObject); if (aIterator != mrRenderState.maAnimationRenderInfoList.end()) @@ -316,7 +355,7 @@ public: mpCurrentRenderPass->meStage = eCurrentStage; mpCurrentRenderPass->mbRenderObjectBackground = true; mpCurrentRenderPass->mbAnimation = true; - mpCurrentRenderPass->mpAnimatedObject = pObject; + mpCurrentRenderPass->mpObject = pObject; closeRenderPass(); // Add all the animated paragraphs @@ -326,8 +365,8 @@ public: pObject, std::deque<sal_Int32>{ nParagraph }); mpCurrentRenderPass->meStage = eCurrentStage; mpCurrentRenderPass->mbAnimation = true; - mpCurrentRenderPass->mpAnimatedObject = pObject; - mpCurrentRenderPass->mnAnimatedParagraph = nParagraph; + mpCurrentRenderPass->mpObject = pObject; + mpCurrentRenderPass->mnParagraph = nParagraph; closeRenderPass(); } } @@ -339,17 +378,38 @@ public: std::deque<sal_Int32>()); mpCurrentRenderPass->meStage = eCurrentStage; mpCurrentRenderPass->mbAnimation = true; - mpCurrentRenderPass->mpAnimatedObject = pObject; + mpCurrentRenderPass->mpObject = pObject; closeRenderPass(); } } - // Check if the object has fields (slide number) + // Check if the object has slide number, footer, date/time + else if (eCurrentStage == RenderStage::Master && !sTextFieldString.isEmpty()) + { + closeRenderPass(); + + mpCurrentRenderPass->maObjectsAndParagraphs.emplace(pObject, std::deque<sal_Int32>()); + mpCurrentRenderPass->meStage = eCurrentStage; + mpCurrentRenderPass->mbPlaceholder = true; + mpCurrentRenderPass->maFieldType = sTextFieldString; + mpCurrentRenderPass->mpObject = pObject; + closeRenderPass(); + + RenderPass aTextFieldPass; + aTextFieldPass.maObjectsAndParagraphs.emplace(pObject, std::deque<sal_Int32>()); + aTextFieldPass.meStage = RenderStage::TextFields; + aTextFieldPass.maFieldType = sTextFieldString; + aTextFieldPass.mpObject = pObject; + + mrRenderState.maTextFields.push_back(aTextFieldPass); + } + // Check if the object has fields else if (eCurrentStage == RenderStage::Master && hasFields(pObject)) { closeRenderPass(); mpCurrentRenderPass->maObjectsAndParagraphs.emplace(pObject, std::deque<sal_Int32>()); mpCurrentRenderPass->meStage = eCurrentStage; + mpCurrentRenderPass->mpObject = pObject; closeRenderPass(); } // No special handling is needed, just add the object to the current rendering pass @@ -426,6 +486,7 @@ SlideshowLayerRenderer::SlideshowLayerRenderer(SdrPage& rPage) { maRenderState.meStage = RenderStage::Background; setupAnimations(); + setupMasterPageFields(); } void SlideshowLayerRenderer::resolveEffect(CustomAnimationEffectPtr const& rEffect) @@ -522,6 +583,42 @@ void SlideshowLayerRenderer::setupAnimations() } } +void SlideshowLayerRenderer::setupMasterPageFields() +{ + auto* pSdPage = dynamic_cast<SdPage*>(&mrPage); + + if (!pSdPage) + return; + + SdDrawDocument& rDocument(static_cast<SdDrawDocument&>(pSdPage->getSdrModelFromSdrPage())); + + if (rDocument.GetMasterPageCount()) + { + SdrLayerAdmin& rLayerAdmin = rDocument.GetLayerAdmin(); + SdrLayerIDSet aVisibleLayers = pSdPage->TRG_GetMasterPageVisibleLayers(); + maRenderState.mbShowMasterPageObjects + = aVisibleLayers.IsSet(rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects)); + } + + if (maRenderState.mbShowMasterPageObjects) + { + const sd::HeaderFooterSettings& rSettings = pSdPage->getHeaderFooterSettings(); + + if (rSettings.mbFooterVisible && !rSettings.maFooterText.isEmpty()) + maRenderState.mbFooterEnabled = true; + + if (rSettings.mbDateTimeVisible) + { + maRenderState.mbDateTimeEnabled = true; + + if (rSettings.mbDateTimeIsFixed && rSettings.maDateTimeText.isEmpty()) + maRenderState.mbDateTimeEnabled = false; + } + + maRenderState.mbSlideNumberEnabled = rSettings.mbSlideNumberVisible; + } +} + Size SlideshowLayerRenderer::calculateAndSetSizePixel(Size const& rDesiredSizePixel) { double fRatio = double(mrPage.GetHeight()) / mrPage.GetWidth(); @@ -592,21 +689,33 @@ void writeAnimated(::tools::JsonWriter& aJsonWriter, AnimationLayerInfo const& r } // end anonymous namespace -void SlideshowLayerRenderer::writeJSON(OString& rJsonMsg) +void SlideshowLayerRenderer::writeBackgroundJSON(OString& rJsonMsg) +{ + ::tools::JsonWriter aJsonWriter; + aJsonWriter.put("group", maRenderState.stageString()); + aJsonWriter.put("index", maRenderState.currentIndex()); + aJsonWriter.put("slideHash", GetInterfaceHash(GetXDrawPageForSdrPage(&mrPage))); + aJsonWriter.put("type", "bitmap"); + writeContentNode(aJsonWriter); + rJsonMsg = aJsonWriter.finishAndGetAsOString(); + maRenderState.incrementIndex(); +} + +void SlideshowLayerRenderer::writeJSON(OString& rJsonMsg, RenderPass const& rRenderPass) { ::tools::JsonWriter aJsonWriter; aJsonWriter.put("group", maRenderState.stageString()); aJsonWriter.put("index", maRenderState.currentIndex()); aJsonWriter.put("slideHash", GetInterfaceHash(GetXDrawPageForSdrPage(&mrPage))); - SdrObject* pObject = maRenderState.currentTarget(); - sal_Int32 nParagraph = maRenderState.currentTargetParagraph(); + SdrObject* pObject = rRenderPass.mpObject; + sal_Int32 nParagraph = rRenderPass.mnParagraph; auto aIterator = maRenderState.maAnimationRenderInfoList.find(pObject); + // Animation object if (aIterator != maRenderState.maAnimationRenderInfoList.end()) { AnimationRenderInfo& rInfo = aIterator->second; - assert(pObject); if (nParagraph >= 0) { @@ -630,8 +739,26 @@ void SlideshowLayerRenderer::writeJSON(OString& rJsonMsg) { if (pObject && hasFields(pObject)) aJsonWriter.put("isField", true); // TODO: to be removed, implement properly - aJsonWriter.put("type", "bitmap"); - writeContentNode(aJsonWriter); + + if (rRenderPass.mbPlaceholder) + { + aJsonWriter.put("type", "placeholder"); + { + auto aContentNode = aJsonWriter.startNode("content"); + aJsonWriter.put("type", rRenderPass.maFieldType); + } + } + else if (rRenderPass.meStage == RenderStage::TextFields) + { + auto aContentNode = aJsonWriter.startNode("content"); + aJsonWriter.put("type", rRenderPass.maFieldType); + writeContentNode(aJsonWriter); + } + else + { + aJsonWriter.put("type", "bitmap"); + writeContentNode(aJsonWriter); + } } rJsonMsg = aJsonWriter.finishAndGetAsOString(); @@ -643,9 +770,6 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, double& rScale, OStr { // We want to render one pass (one iteration through objects) - // Reset state for this pass - maRenderState.resetPass(); - RenderContext aRenderContext(pBuffer, mrModel, mrPage, maSlideSize, Fraction(rScale)); // Render Background and analyze other passes @@ -654,13 +778,10 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, double& rScale, OStr // Render no objects, just the background, but analyze and create rendering passes AnalyzeRenderingRedirector aRedirector(maRenderState); createViewAndDraw(aRenderContext, &aRedirector); - - // Last rendering pass might be empty - delete - if (maRenderState.maRenderPasses.back().isEmpty()) - maRenderState.maRenderPasses.pop_back(); + aRedirector.finalizeRenderPasses(); // Write JSON for the Background layer - writeJSON(rJsonMsg); + writeBackgroundJSON(rJsonMsg); maRenderState.meStage = RenderStage::Master; } @@ -671,16 +792,13 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, double& rScale, OStr auto const& rRenderPass = maRenderState.maRenderPasses.front(); maRenderState.meStage = rRenderPass.meStage; - RenderPassObjectRedirector aRedirector(maRenderState, rRenderPass); - createViewAndDraw(aRenderContext, &aRedirector); - - if (rRenderPass.mbAnimation) + if (!rRenderPass.mbPlaceholder) // no need to render if placehodler { - maRenderState.mpCurrentTarget = rRenderPass.mpAnimatedObject; - maRenderState.mnCurrentTargetParagraph = rRenderPass.mnAnimatedParagraph; + RenderPassObjectRedirector aRedirector(maRenderState, rRenderPass); + createViewAndDraw(aRenderContext, &aRedirector); } - writeJSON(rJsonMsg); + writeJSON(rJsonMsg, rRenderPass); maRenderState.maRenderPasses.pop_front(); }