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();
     }

Reply via email to