sd/qa/unit/tiledrendering/data/SlideRenderingTest_SlideNumber_Header_DateTime.odp |binary sd/qa/unit/tiledrendering/tiledrendering.cxx | 203 ++++++++++ sd/source/ui/inc/SlideshowLayerRenderer.hxx | 29 - sd/source/ui/tools/SlideshowLayerRenderer.cxx | 191 +++++++-- 4 files changed, 372 insertions(+), 51 deletions(-)
New commits: commit 45ce6fb9e609b2ccebf698503b926af9cc190bdf Author: Marco Cecchetti <marco.cecche...@collabora.com> AuthorDate: Tue Nov 5 21:13:44 2024 +0100 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Thu Nov 7 11:11:43 2024 +0100 slideshow: render text shape with all paragraphs animated properly When all paragraphs of a text shape are animated, the render pass related to the non animated part of the text shape was rendering all the paragraphs instead of the text shape background only. Change-Id: I1b4d9e301efe569b2b26bec19f569ff54ef61182 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176166 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx b/sd/source/ui/tools/SlideshowLayerRenderer.cxx index f1fb10c8cac9..bb83542ef4d8 100644 --- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx +++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx @@ -458,7 +458,10 @@ public: auto const& rParagraphs = aIterator->second; - if (!rParagraphs.empty()) + // A render pass for the non-animated part of a text shapes whose paragraphs are all animated + // has no paragraphs (rParagraphs.empty()) anyway it still needs to be modified in order to + // render the text shape background only; on the contrary it will render all paragraphs. + if (!rParagraphs.empty() || mrRenderPass.mbRenderObjectBackground) { auto const& rViewInformation2D = rOriginal.GetObjectContact().getViewInformation2D(); auto rContainer commit cfdc63bb6858fb4738e8371b25d1ea4c1807ad91 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu Oct 24 18:12:18 2024 +0200 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Thu Nov 7 11:11:35 2024 +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/+/175570 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Tomaž Vajngerl <qui...@gmail.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 4aa19c1ccd98..08fd4521bf49 100644 --- a/sd/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -3523,6 +3523,209 @@ 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(!pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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; + CPPUNIT_ASSERT(pXImpressDocument->renderNextSlideLayer(pBuffer.data(), bIsBitmapLayer, 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 1d8f427735bb..01e9374e9244 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; } @@ -153,9 +148,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 0ccde3ebefb8..f1fb10c8cac9 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> @@ -228,19 +230,12 @@ void modifyParagraphs(drawinglayer::primitive2d::Primitive2DContainer& rContaine /// Analyze the renderng 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() { @@ -257,6 +252,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, @@ -289,6 +326,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()) @@ -317,7 +356,7 @@ public: mpCurrentRenderPass->meStage = eCurrentStage; mpCurrentRenderPass->mbRenderObjectBackground = true; mpCurrentRenderPass->mbAnimation = true; - mpCurrentRenderPass->mpAnimatedObject = pObject; + mpCurrentRenderPass->mpObject = pObject; closeRenderPass(); // Add all the animated paragraphs @@ -327,8 +366,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(); } } @@ -340,17 +379,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 specal handling is needed, just add the object to the current rendering pass @@ -427,6 +487,7 @@ SlideshowLayerRenderer::SlideshowLayerRenderer(SdrPage& rPage) { maRenderState.meStage = RenderStage::Background; setupAnimations(); + setupMasterPageFields(); } void SlideshowLayerRenderer::resolveEffect(CustomAnimationEffectPtr const& rEffect) @@ -523,6 +584,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(); @@ -593,21 +690,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) { @@ -631,8 +740,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"); + { + ::tools::ScopedJsonWriterNode aContentNode = aJsonWriter.startNode("content"); + aJsonWriter.put("type", rRenderPass.maFieldType); + } + } + else if (rRenderPass.meStage == RenderStage::TextFields) + { + ::tools::ScopedJsonWriterNode aContentNode = aJsonWriter.startNode("content"); + aJsonWriter.put("type", rRenderPass.maFieldType); + writeContentNode(aJsonWriter); + } + else + { + aJsonWriter.put("type", "bitmap"); + writeContentNode(aJsonWriter); + } } rJsonMsg = aJsonWriter.finishAndGetAsOString(); @@ -644,9 +771,6 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) { // We want to render one pass (one iteration through objects) - // Reset state for this pass - maRenderState.resetPass(); - RenderContext aRenderContext(pBuffer, mrModel, mrPage, maSlideSize); // Render Background and analyze other passes @@ -655,13 +779,10 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) // 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; } @@ -672,16 +793,13 @@ bool SlideshowLayerRenderer::render(unsigned char* pBuffer, OString& rJsonMsg) 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(); }