include/vcl/ITiledRenderable.hxx                 |   18 
 offapi/com/sun/star/presentation/XSlideShow.idl  |   17 
 sd/source/ui/inc/DrawViewShell.hxx               |    7 
 sd/source/ui/inc/unomodel.hxx                    |    9 
 sd/source/ui/unoidl/unomodel.cxx                 |   60 +
 sd/source/ui/view/drviewsa.cxx                   |    2 
 sd/source/ui/view/drviewsk.cxx                   |   42 +
 slideshow/source/engine/shapes/shapeimporter.cxx |   30 
 slideshow/source/engine/slide/slideimpl.cxx      |  718 ++++++++++++++++++++++-
 slideshow/source/engine/slideshowimpl.cxx        |   75 ++
 slideshow/source/inc/shapeimporter.hxx           |   13 
 slideshow/source/inc/slide.hxx                   |   10 
 12 files changed, 993 insertions(+), 8 deletions(-)

New commits:
commit 0d959d483555307c363f5bfa5b83eaf5bd98d357
Author:     Marco Cecchetti <marco.cecche...@collabora.com>
AuthorDate: Mon Jun 24 15:26:18 2024 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Tue Jun 25 17:11:23 2024 +0200

    sd: slideshow render interface and implementation
    
    Interface and implementation to expose the ability to render
    the slide's layers to a bitmap.
    
    Change-Id: I3da48585e498354592e163d84bd29659b233c255
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/169450
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/vcl/ITiledRenderable.hxx b/include/vcl/ITiledRenderable.hxx
index 483176aca3b8..05db0bad6db0 100644
--- a/include/vcl/ITiledRenderable.hxx
+++ b/include/vcl/ITiledRenderable.hxx
@@ -390,6 +390,24 @@ public:
     {
         return {};
     }
+    /** Creates a slide show renderer (Impress only function) */
+    virtual bool createSlideRenderer(
+        sal_Int32 /*nSlideNumber*/, sal_Int32& /*nViewWidth*/, sal_Int32& 
/*nViewHeight*/,
+        bool /*bRenderBackground*/, bool /*bRenderMasterPage*/)
+   {
+        return false;
+   }
+
+    /** Clean-up slideshow */
+    virtual void postSlideshowCleanup()
+    {
+    }
+
+    /** render slideshow layer*/
+    virtual bool renderNextSlideLayer(unsigned char* /*pBuffer*/, bool& 
/*bIsBitmapLayer*/, OUString& /*rJsonMsg*/)
+    {
+        return true;
+    }
 };
 } // namespace vcl
 
diff --git a/offapi/com/sun/star/presentation/XSlideShow.idl 
b/offapi/com/sun/star/presentation/XSlideShow.idl
index ca31d88d8e24..622648cf6435 100644
--- a/offapi/com/sun/star/presentation/XSlideShow.idl
+++ b/offapi/com/sun/star/presentation/XSlideShow.idl
@@ -320,6 +320,23 @@ interface XSlideShow : ::com::sun::star::uno::XInterface
         [in] ::com::sun::star::drawing::XShape xShape,
         [in] short nPointerShape );
 
+    /** Used to create a slide renderer for the Online client.<p>
+    */
+    boolean createLOKSlideRenderer(
+        [out] long nViewWidth,
+        [out] long nViewHeight,
+        [in] boolean bRenderMasterPage,
+        [in] boolean bRenderBackground,
+        [in] ::com::sun::star::drawing::XDrawPage xSlide,
+        [in] ::com::sun::star::drawing::XDrawPagesSupplier xDrawPages,
+        [in] ::com::sun::star::animations::XAnimationNode xRootNode );
+
+    /** Used to renderer a slide layer for the Online client.<p>
+    */
+    boolean renderNextLOKSlideLayer(
+        [in] hyper nBufferPointer,
+        [out] boolean bIsBitmapLayer,
+        [out] string rJsonMsg );
 };
 
 }; }; }; };
diff --git a/sd/source/ui/inc/DrawViewShell.hxx 
b/sd/source/ui/inc/DrawViewShell.hxx
index 3043ba007bf2..cdd2cc3a44fd 100644
--- a/sd/source/ui/inc/DrawViewShell.hxx
+++ b/sd/source/ui/inc/DrawViewShell.hxx
@@ -33,6 +33,7 @@
 namespace svx::sidebar { class SelectionChangeHandler; }
 namespace com::sun::star::lang { class XEventListener; }
 namespace com::sun::star::scanner { class XScannerManager2; }
+namespace com::sun::star::presentation { class XSlideShow; }
 
 class Outliner;
 class SdPage;
@@ -376,6 +377,10 @@ public:
     const SdViewOptions& GetViewOptions() const { return maViewOptions; }
     //move this method to ViewShell.
     //void  NotifyAccUpdate();
+
+    css::uno::Reference<css::presentation::XSlideShow> getXSlideShowInstance();
+    void destroyXSlideShowInstance();
+
 protected:
                     DECL_DLLPRIVATE_LINK( ClipboardChanged, 
TransferableDataHelper*, void );
                     DECL_DLLPRIVATE_LINK( TabSplitHdl, TabBar *, void );
@@ -495,6 +500,8 @@ private:
     ::std::unique_ptr< ViewOverlayManager > mpViewOverlayManager;
     std::vector<std::unique_ptr<SdrExternalToolEdit>> m_ExternalEdits;
     SdViewOptions maViewOptions;
+
+    css::uno::Reference<com::sun::star::presentation::XSlideShow> mxSlideShow;
 };
 
     /// Merge the background properties together and deposit the result in 
rMergeAttr
diff --git a/sd/source/ui/inc/unomodel.hxx b/sd/source/ui/inc/unomodel.hxx
index 0cf13555ddfa..155d50e9ecce 100644
--- a/sd/source/ui/inc/unomodel.hxx
+++ b/sd/source/ui/inc/unomodel.hxx
@@ -283,12 +283,19 @@ public:
     }
     /// @see vcl::ITiledRenderable::setPaintTextEdit().
     virtual void setPaintTextEdit(bool bPaint) override { mbPaintTextEdit = 
bPaint; }
-
     /// @see vcl::ITiledRenderable::getViewRenderState().
     OString getViewRenderState(SfxViewShell* pViewShell = nullptr) override;
 
     /// @see vcl::ITiledRenderable::getPresentationInfo().
     OString getPresentationInfo() const override;
+    /// @see vcl::ITiledRenderable::createSlideRenderer().
+    bool createSlideRenderer(
+        sal_Int32 nSlideNumber, sal_Int32& nViewWidth, sal_Int32& nViewHeight,
+        bool bRenderBackground, bool bRenderMasterPage) override;
+    /// @see vcl::ITiledRenderable::postSlideshowCleanup().
+    void postSlideshowCleanup() override;
+    /// @see vcl::ITiledRenderable::renderNextSlideLayer().
+    bool renderNextSlideLayer(unsigned char* pBuffer, bool& bIsBitmapLayer, 
OUString& rJsonMsg) override;
 
     // XComponent
 
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index efda0612a3cc..1bb62e02c832 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -80,6 +80,7 @@
 #include <editeng/eeitem.hxx>
 #include <unotools/datetime.hxx>
 #include <xmloff/autolayout.hxx>
+#include <tools/helpers.hxx>
 #include <tools/json_writer.hxx>
 #include <tools/helpers.hxx>
 
@@ -3081,6 +3082,65 @@ OString SdXImpressDocument::getPresentationInfo() const
     return aJsonWriter.finishAndGetAsOString();
 }
 
+bool SdXImpressDocument::createSlideRenderer(
+    sal_Int32 nSlideNumber, sal_Int32& nViewWidth, sal_Int32& nViewHeight,
+    bool bRenderBackground, bool bRenderMasterPage)
+{
+    DrawViewShell* pViewSh = GetViewShell();
+    if (!pViewSh)
+        return false;
+
+    uno::Reference<presentation::XSlideShow> xSlideShow = 
pViewSh->getXSlideShowInstance();
+    if (!xSlideShow.is())
+        return false;
+
+    bool bSuccess = false;
+    try
+    {
+        uno::Reference<drawing::XDrawPagesSupplier> 
xDrawPages(mpDoc->getUnoModel(), uno::UNO_QUERY_THROW);
+        uno::Reference<container::XIndexAccess> 
xSlides(xDrawPages->getDrawPages(), uno::UNO_QUERY_THROW);
+        uno::Reference<drawing::XDrawPage> 
xSlide(xSlides->getByIndex(nSlideNumber), uno::UNO_QUERY_THROW);
+        uno::Reference<animations::XAnimationNodeSupplier> 
xAnimNodeSupplier(xSlide, uno::UNO_QUERY_THROW);
+        uno::Reference<animations::XAnimationNode> xAnimNode = 
xAnimNodeSupplier->getAnimationNode();
+
+        bSuccess = xSlideShow->createLOKSlideRenderer(nViewWidth, nViewHeight,
+                                                 bRenderMasterPage, 
bRenderBackground,
+                                                 xSlide, xDrawPages, 
xAnimNode);
+    }
+    catch (uno::Exception&)
+    {
+        TOOLS_WARN_EXCEPTION( "sd", 
"SdXImpressDocument::createLOKSlideRenderer: failed" );
+    }
+    return bSuccess;
+}
+
+void SdXImpressDocument::postSlideshowCleanup()
+{
+    DrawViewShell* pViewSh = GetViewShell();
+    if (!pViewSh)
+        return;
+
+    pViewSh->destroyXSlideShowInstance();
+}
+
+bool SdXImpressDocument::renderNextSlideLayer(unsigned char* pBuffer, bool& 
bIsBitmapLayer, OUString& rJsonMsg)
+{
+    DrawViewShell* pViewSh = GetViewShell();
+    if (!pViewSh)
+        return true;
+
+    uno::Reference<presentation::XSlideShow> xSlideShow = 
pViewSh->getXSlideShowInstance();
+    if (!xSlideShow.is())
+        return true;
+
+    auto nBufferPointer = 
sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(pBuffer));
+    sal_Bool bBitmapLayer = false;
+    bool bDone = xSlideShow->renderNextLOKSlideLayer(nBufferPointer, 
bBitmapLayer, rJsonMsg);
+    bIsBitmapLayer = bBitmapLayer;
+
+    return bDone;
+}
+
 SdrModel& SdXImpressDocument::getSdrModelFromUnoModel() const
 {
     OSL_ENSURE(GetDoc(), "No SdrModel in draw/Impress, should not happen");
diff --git a/sd/source/ui/view/drviewsa.cxx b/sd/source/ui/view/drviewsa.cxx
index 5d5cfe613245..9572561482f1 100644
--- a/sd/source/ui/view/drviewsa.cxx
+++ b/sd/source/ui/view/drviewsa.cxx
@@ -149,6 +149,8 @@ DrawViewShell::~DrawViewShell()
 
 void DrawViewShell::ImplDestroy()
 {
+    destroyXSlideShowInstance();
+
     SD_MOD()->GetColorConfig().RemoveListener(this);
 
     mpSelectionChangeHandler->Disconnect();
diff --git a/sd/source/ui/view/drviewsk.cxx b/sd/source/ui/view/drviewsk.cxx
index bdbb821e96b3..cb40d8398f04 100644
--- a/sd/source/ui/view/drviewsk.cxx
+++ b/sd/source/ui/view/drviewsk.cxx
@@ -11,12 +11,18 @@
 #include <ViewShellBase.hxx>
 #include <sdmod.hxx>
 
+#include <com/sun/star/presentation/SlideShow.hpp>
+
 #include <comphelper/lok.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/processfactory.hxx>
 #include <comphelper/servicehelper.hxx>
 #include <sfx2/lokhelper.hxx>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <unomodel.hxx>
 
+using namespace css;
+
 namespace sd {
 
 void DrawViewShell::ConfigurationChanged( utl::ConfigurationBroadcaster* pCb, 
ConfigurationHints )
@@ -57,6 +63,42 @@ void DrawViewShell::ConfigureAppBackgroundColor( 
svtools::ColorConfig *pColorCon
     maViewOptions.mnAppBackgroundColor = aFillColor;
 }
 
+void DrawViewShell::destroyXSlideShowInstance()
+{
+    if (!mxSlideShow.is())
+        return;
+
+    try
+    {
+        uno::Reference<lang::XComponent> xComponent(mxSlideShow, 
uno::UNO_QUERY);
+        if (xComponent.is())
+            xComponent->dispose();
+    }
+    catch (uno::Exception&)
+    {
+        TOOLS_WARN_EXCEPTION( "sd", "DrawViewShell::destroyXSlideShowInstance 
dispose");
+    }
+
+    mxSlideShow.clear();
+}
+
+uno::Reference<presentation::XSlideShow> DrawViewShell::getXSlideShowInstance()
+{
+    if (!mxSlideShow.is())
+    {
+        try
+        {
+            auto xContext = ::comphelper::getProcessComponentContext();
+            mxSlideShow.set(presentation::SlideShow::create(xContext), 
uno::UNO_SET_THROW);
+        }
+        catch (uno::Exception&)
+        {
+            TOOLS_WARN_EXCEPTION("sd", 
"DrawViewShell::createXSlideShowInstance()");
+        }
+    }
+    return mxSlideShow;
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/slideshow/source/engine/shapes/shapeimporter.cxx 
b/slideshow/source/engine/shapes/shapeimporter.cxx
index 92162eeb60ad..56fce5663c9a 100644
--- a/slideshow/source/engine/shapes/shapeimporter.cxx
+++ b/slideshow/source/engine/shapes/shapeimporter.cxx
@@ -201,6 +201,15 @@ ShapeSharedPtr ShapeImporter::createShape(
     uno::Reference<beans::XPropertySet> const& xPropSet,
     std::u16string_view shapeType ) const
 {
+    css::uno::Reference<css::drawing::XDrawPage> xPage = mxPage;
+    if (mbConvertingMasterPage && mbMasterPageObjectsOnly)
+    {
+        const XShapesEntry& rTop = maShapesStack.top();
+        css::uno::Reference<css::drawing::XDrawPage> 
xMasterPage(rTop.mxShapes, uno::UNO_QUERY_THROW);
+        if (xMasterPage.is())
+            xPage = xMasterPage;
+    }
+
     if( shapeType == u"com.sun.star.drawing.MediaShape" || shapeType == 
u"com.sun.star.presentation.MediaShape" )
     {
         // Media shape (video etc.). This is a special object
@@ -233,7 +242,7 @@ ShapeSharedPtr ShapeImporter::createShape(
         // #i46224# Mark OLE shapes as foreign content - scan them for
         // unsupported actions, and fallback to bitmap, if necessary
         return DrawShape::create( xCurrShape,
-                                  mxPage,
+                                  xPage,
                                   mnAscendingPrio,
                                   true,
                                   mrContext );
@@ -258,7 +267,7 @@ ShapeSharedPtr ShapeImporter::createShape(
             // anyway, or it's a metafile, which currently the
             // metafile renderer might not display correctly.
             return DrawShape::create( xCurrShape,
-                                      mxPage,
+                                      xPage,
                                       mnAscendingPrio,
                                       true,
                                       mrContext );
@@ -319,7 +328,7 @@ ShapeSharedPtr ShapeImporter::createShape(
                 aGraphAttrs ) );
 
         return DrawShape::create( xCurrShape,
-                                  mxPage,
+                                  xPage,
                                   mnAscendingPrio,
                                   aGraphic,
                                   mrContext );
@@ -327,7 +336,7 @@ ShapeSharedPtr ShapeImporter::createShape(
     else
     {
         return DrawShape::create( xCurrShape,
-                                  mxPage,
+                                  xPage,
                                   mnAscendingPrio,
                                   false,
                                   mrContext );
@@ -375,6 +384,15 @@ bool ShapeImporter::isSkip(
         {
             return true;
         }
+        if( mbTextFieldsOnly )
+        {
+            if( !( shapeType == u"com.sun.star.presentation.SlideNumberShape" 
||
+                   shapeType == u"com.sun.star.presentation.FooterShape" ||
+                   shapeType == u"com.sun.star.presentation.DateTimeShape" ) )
+            {
+                return true;
+            }
+        }
     }
     return false;
 }
@@ -526,7 +544,9 @@ ShapeImporter::ShapeImporter( 
uno::Reference<drawing::XDrawPage> const&
     maPolygons(),
     maShapesStack(),
     mnAscendingPrio( nOrdNumStart ),
-    mbConvertingMasterPage( bConvertingMasterPage )
+    mbConvertingMasterPage( bConvertingMasterPage ),
+    mbMasterPageObjectsOnly( false ),
+    mbTextFieldsOnly( false )
 {
     uno::Reference<drawing::XShapes> const xShapes(
         xPage, uno::UNO_QUERY_THROW );
diff --git a/slideshow/source/engine/slide/slideimpl.cxx 
b/slideshow/source/engine/slide/slideimpl.cxx
index 4f7cf5654d34..4ac39cf4ff0f 100644
--- a/slideshow/source/engine/slide/slideimpl.cxx
+++ b/slideshow/source/engine/slide/slideimpl.cxx
@@ -19,10 +19,13 @@
 
 
 #include <osl/diagnose.hxx>
+#include <canvas/canvastools.hxx>
 #include <comphelper/diagnose_ex.hxx>
 #include <cppcanvas/basegfxfactory.hxx>
+#include <cppcanvas/vclfactory.hxx>
 
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 #include <basegfx/point/b2dpoint.hxx>
 
 #include <com/sun/star/awt/SystemPointer.hpp>
@@ -47,9 +50,12 @@
 #include "userpaintoverlay.hxx"
 #include "targetpropertiescreator.hxx"
 #include <tools.hxx>
+#include <tools/helpers.hxx>
+#include <tools/json_writer.hxx>
 #include <box2dtools.hxx>
 #include <utility>
 #include <vcl/graphicfilter.hxx>
+#include <vcl/virdev.hxx>
 #include <svx/svdograf.hxx>
 
 using namespace ::com::sun::star;
@@ -57,8 +63,671 @@ using namespace ::com::sun::star;
 
 namespace slideshow::internal
 {
+
 namespace
 {
+basegfx::B2IVector getSlideSizePixel(const basegfx::B2DVector& rSlideSize,
+                                     const basegfx::B2DHomMatrix& 
rTransformation)
+{
+    const basegfx::B2DRange aRect(0, 0, rSlideSize.getX(), rSlideSize.getY());
+
+    basegfx::B2DRange aTmpRect;
+    canvas::tools::calcTransformedRectBounds(aTmpRect, aRect, rTransformation);
+
+    // #i42440# Returned slide size is one pixel too small, as
+    // rendering happens one pixel to the right and below the
+    // actual bound rect.
+    return basegfx::B2IVector(basegfx::fround(aTmpRect.getRange().getX()) + 1,
+                              basegfx::fround(aTmpRect.getRange().getY()) + 1);
+}
+
+basegfx::B2DHomMatrix createTransformation(Size& rDeviceSize, const Size& 
rSlideSize )
+{
+    basegfx::B2DHomMatrix aViewTransform(1, 0, 0, 0, 1, 0);
+
+    const Size aWindowSize( rDeviceSize );
+    Size aOutputSize( aWindowSize );
+    Size aPageSize( rSlideSize );
+
+    const double page_ratio = static_cast<double>(aPageSize.Width()) / 
static_cast<double>(aPageSize.Height());
+    const double output_ratio = static_cast<double>(aOutputSize.Width()) / 
static_cast<double>(aOutputSize.Height());
+
+    if( page_ratio > output_ratio )
+    {
+        aOutputSize.setHeight( ( aOutputSize.Width() * aPageSize.Height() ) / 
aPageSize.Width() );
+    }
+    else if( page_ratio < output_ratio )
+    {
+        aOutputSize.setWidth( ( aOutputSize.Height() * aPageSize.Width() ) / 
aPageSize.Height() );
+    }
+
+    // Reduce available width by one, as the slides might actually
+    // render one pixel wider and higher as aPageSize below specifies
+    // (when shapes of page size have visible border lines)
+    aOutputSize.AdjustWidth( -1 );
+    aOutputSize.AdjustHeight( -1 );
+
+    rDeviceSize = aOutputSize;
+
+    // scale presentation into available window rect (minus 10%); center in 
the window
+    aViewTransform = 
basegfx::utils::createScaleB2DHomMatrix(aOutputSize.Width(), 
aOutputSize.Height());
+
+    if (basegfx::fTools::equalZero(aViewTransform.get(0,0)) ||
+        basegfx::fTools::equalZero(aViewTransform.get(1,1)))
+    {
+        OSL_FAIL( "SlideView::SlideView(): Singular matrix!" );
+
+        aViewTransform = basegfx::B2DHomMatrix::abcdef(1, 0, 0, 0, 1, 0);
+    }
+
+    basegfx::B2DHomMatrix aScaleMatrix;
+    aScaleMatrix.scale( 1.0 / rSlideSize.getWidth(), 1.0 / 
rSlideSize.getHeight() );
+    aViewTransform = aViewTransform * aScaleMatrix;
+
+    return aViewTransform;
+}
+
+OUString getPlaceholderType(std::u16string_view sShapeType)
+{
+    OUString aType;
+    if (sShapeType == u"com.sun.star.presentation.SlideNumberShape")
+        aType = u"SlideNumber"_ustr;
+    if (sShapeType == u"com.sun.star.presentation.FooterShape")
+        aType = u"Footer"_ustr;
+    if (sShapeType == u"com.sun.star.presentation.DateTimeShape")
+        aType = u"DateTime"_ustr;
+
+    return aType;
+}
+
+class LOKSlideRenderer
+{
+public:
+    enum LayerGroupType
+    {
+        BACKGROUND,
+        MASTER_PAGE,
+        DRAW_PAGE,
+        TEXT_FIELDS
+    };
+public:
+    LOKSlideRenderer(const Size& rViewSize, const Size& rSlideSize,
+                     bool bRenderBackground, bool bRenderMasterPageObjects,
+                     const uno::Reference<drawing::XDrawPage>& rxDrawPage,
+                     const uno::Reference<drawing::XDrawPagesSupplier>& 
rxDrawPagesSupplier,
+                     const uno::Reference<animations::XAnimationNode>& 
rxRootNode,
+                     const SlideShowContext& rContext,
+                     const std::shared_ptr<LayerManager>& pLayerManager);
+
+    void renderBackground(unsigned char* pBuffer);
+    void renderTextFields(unsigned char* pBuffer);
+    void renderMasterPage(unsigned char* pBuffer);
+    void renderDrawPage(unsigned char* pBuffer);
+    void renderNextLayer(unsigned char* pBuffer);
+
+    const Size& getDeviceSize() const { return maDeviceSize; }
+    bool isBackgroundRenderingDone() const { return mbBackgroundRenderingDone; 
}
+    bool isTextFieldsRenderingDone() const { return mbTextFieldsRenderingDone; 
}
+    bool isMasterPageRenderingDone() const { return mbMasterPageRenderingDone; 
}
+    bool isDrawPageRenderingDone() const { return mbDrawPageRenderingDone; }
+    bool isSlideRenderingDone() const { return mbSlideRenderingDone; }
+    bool isBitmapLayer() const { return mbIsBitmapLayer; }
+
+    const OString& getJsonMessage() const { return msLastJsonMessage; }
+
+private:
+    void collectAnimatedShapes();
+
+    void renderImpl(LayerGroupType eLayersSet, unsigned char* pBuffer);
+    void renderBackgroundImpl(VirtualDevice& rDevice);
+    void renderTextFieldsImpl(VirtualDevice& rDevice);
+    void renderMasterPageImpl(VirtualDevice& rDevice);
+    void renderDrawPageImpl(VirtualDevice& rDevice);
+
+    void renderLayerImpl(VirtualDevice& rDevice, tools::JsonWriter& 
rJsonWriter);
+    void renderAnimatedShapeImpl(VirtualDevice& rDevice, const 
std::shared_ptr<Shape>& pShape,
+                                 tools::JsonWriter& rJsonWriter);
+
+    SlideBitmapSharedPtr createLayerBitmap(const ::cppcanvas::CanvasSharedPtr& 
pCanvas,
+                                           const ::basegfx::B2ISize& rBmpSize 
) const;
+    void renderLayerBitmapImpl(VirtualDevice& rDevice);
+
+private:
+    Size maDeviceSize;
+    Size maSlideSize;
+    bool mbRenderBackground;
+    bool mbRenderMasterPageObjects;
+    basegfx::B2DHomMatrix maTransformation;
+    uno::Reference<drawing::XDrawPage> mxDrawPage;
+    uno::Reference<drawing::XDrawPagesSupplier> mxDrawPagesSupplier;
+    uno::Reference<animations::XAnimationNode> mxRootNode;
+    const SlideShowContext& mrContext;
+    std::shared_ptr<LayerManager> mpLayerManager;
+    uno::Reference<drawing::XDrawPage> mxMasterPage;
+    std::shared_ptr<ShapeImporter> mpTFShapesFunctor;
+    std::shared_ptr<ShapeImporter> mpMPShapesFunctor;
+    std::shared_ptr<ShapeImporter> mpShapesFunctor;
+    std::unordered_map< BitmapChecksum, BitmapEx > maBitmapMap;
+    std::vector<OString> maJsonMsgList;
+    std::unordered_map<std::string, bool> maAnimatedShapeVisibilityMap;
+
+    sal_uInt32 mnMPLayerIndex;
+    sal_uInt32 mnDPLayerIndex;
+    bool mbBackgroundRenderingDone;
+    bool mbTextFieldsRenderingDone;
+    bool mbMasterPageRenderingDone;
+    bool mbDrawPageRenderingDone;
+    bool mbSlideRenderingDone;
+    ShapeSharedPtr mpDPLastAnimatedShape;
+    OUString msLastPlaceholder;
+
+    bool mbIsBitmapLayer;
+    OString msLastJsonMessage;
+};
+
+LOKSlideRenderer::LOKSlideRenderer(const Size& rViewSize, const Size& 
rSlideSize,
+                                   bool bRenderBackground, bool 
bRenderMasterPageObjects,
+                                   const uno::Reference<drawing::XDrawPage>& 
rxDrawPage,
+                                   const 
uno::Reference<drawing::XDrawPagesSupplier>& rxDrawPagesSupplier,
+                                   const 
uno::Reference<animations::XAnimationNode>& rxRootNode,
+                                   const SlideShowContext& rContext,
+                                   const std::shared_ptr<LayerManager>& 
pLayerManager) :
+    maDeviceSize(rViewSize),
+    maSlideSize(rSlideSize),
+    mbRenderBackground(bRenderBackground),
+    mbRenderMasterPageObjects(bRenderMasterPageObjects),
+    maTransformation(createTransformation(maDeviceSize, maSlideSize)),
+    mxDrawPage(rxDrawPage),
+    mxDrawPagesSupplier(rxDrawPagesSupplier),
+    mxRootNode(rxRootNode),
+    mrContext(rContext),
+    mpLayerManager(pLayerManager),
+    mnMPLayerIndex(0),
+    mnDPLayerIndex(0),
+    mbBackgroundRenderingDone(false),
+    mbTextFieldsRenderingDone(false),
+    mbMasterPageRenderingDone(false),
+    mbDrawPageRenderingDone(false),
+    mbSlideRenderingDone(false),
+    mbIsBitmapLayer(false)
+{
+    uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( 
mxDrawPage, uno::UNO_QUERY );
+    if( xMasterPageTarget.is() )
+    {
+        mxMasterPage = xMasterPageTarget->getMasterPage();
+        uno::Reference< drawing::XShapes > xMasterPageShapes = mxMasterPage;
+        OSL_ASSERT(mxDrawPage.is() && mxMasterPage.is() && 
xMasterPageShapes.is());
+
+        uno::Reference<beans::XPropertySet> xPropSet(mxDrawPage, 
uno::UNO_QUERY);
+        OSL_ASSERT(xPropSet.is());
+
+        bool bBackgroundVisibility = true; // default visible
+        xPropSet->getPropertyValue("IsBackgroundVisible")  >>= 
bBackgroundVisibility;
+        mbBackgroundRenderingDone = !bBackgroundVisibility;
+
+        bool bBackgroundObjectsVisibility = true; // default visible
+        xPropSet->getPropertyValue("IsBackgroundObjectsVisible") >>= 
bBackgroundObjectsVisibility;
+        mbTextFieldsRenderingDone = mbMasterPageRenderingDone = 
!bBackgroundObjectsVisibility;
+
+        if (!mbTextFieldsRenderingDone)
+        {
+            mpTFShapesFunctor
+                = std::make_shared<ShapeImporter>(mxMasterPage, mxDrawPage, 
mxDrawPagesSupplier,
+                                                  mrContext, 0, /* shape num 
starts at 0 */
+                                                  true);
+            mpTFShapesFunctor->setTextFieldsOnly(true);
+        }
+        if (!(mbBackgroundRenderingDone && mbMasterPageRenderingDone))
+        {
+            mpMPShapesFunctor
+                = std::make_shared<ShapeImporter>(mxMasterPage, mxDrawPage, 
mxDrawPagesSupplier,
+                                                  mrContext, 0, /* shape num 
starts at 0 */
+                                                  true);
+            mpMPShapesFunctor->setMasterPageObjectsOnly(true);
+        }
+
+        mpShapesFunctor = std::make_shared<ShapeImporter>(mxDrawPage, 
mxDrawPage, mxDrawPagesSupplier,
+                                                          mrContext, 0, /* 
shape num starts at 0 */
+                                                          false);
+    }
+    collectAnimatedShapes();
+}
+
+void LOKSlideRenderer::renderBackground(unsigned char* pBuffer)
+{
+    renderImpl(LayerGroupType::BACKGROUND, pBuffer);
+}
+
+void LOKSlideRenderer::renderMasterPage(unsigned char* pBuffer)
+{
+    renderImpl(LayerGroupType::MASTER_PAGE, pBuffer);
+}
+
+void LOKSlideRenderer::renderDrawPage(unsigned char* pBuffer)
+{
+    renderImpl(LayerGroupType::DRAW_PAGE, pBuffer);
+}
+
+void LOKSlideRenderer::renderTextFields(unsigned char* pBuffer)
+{
+    renderImpl(LayerGroupType::TEXT_FIELDS, pBuffer);
+}
+
+void LOKSlideRenderer::renderNextLayer(unsigned char* pBuffer)
+{
+    OSL_ASSERT(pBuffer);
+
+    if (mbRenderBackground && !isBackgroundRenderingDone())
+        renderBackground(pBuffer);
+
+    if (!isTextFieldsRenderingDone())
+    {
+        renderTextFields(pBuffer);
+        return;
+    }
+
+    if (mbRenderMasterPageObjects && !isMasterPageRenderingDone())
+    {
+        renderMasterPage(pBuffer);
+        return;
+    }
+
+    if (!isDrawPageRenderingDone())
+    {
+        renderDrawPage(pBuffer);
+        return;
+    }
+
+    mbSlideRenderingDone = true;
+}
+
+void LOKSlideRenderer::renderBackgroundImpl(VirtualDevice& rDevice)
+{
+    if (mbBackgroundRenderingDone)
+        return;
+
+    tools::JsonWriter aJsonWriter;
+    aJsonWriter.put("group", "Background");
+    std::string sLayerId = GetInterfaceHash(mxDrawPage) + ".0";
+    aJsonWriter.put("id", sLayerId);
+
+    ShapeSharedPtr const& rBGShape(mpMPShapesFunctor->importBackgroundShape());
+    mpLayerManager->addShape(rBGShape);
+
+    // render and collect bitmap
+    renderLayerBitmapImpl(rDevice);
+    BitmapEx aBitmapEx(
+        rDevice.GetBitmapEx(Point(0, 0), rDevice.GetOutputSizePixel()));
+    BitmapChecksum nChecksum = aBitmapEx.GetChecksum();
+    maBitmapMap[nChecksum] = aBitmapEx;
+
+    // json
+    mbIsBitmapLayer = true;
+    aJsonWriter.put("type", "bitmap");
+    aJsonWriter.put("checksum", std::to_string(nChecksum));
+
+    msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+    maJsonMsgList.push_back(msLastJsonMessage);
+
+    // clean up
+    rDevice.Erase();
+    mpLayerManager->removeShape(rBGShape);
+
+    mbBackgroundRenderingDone = true;
+}
+
+void LOKSlideRenderer::renderMasterPageImpl(VirtualDevice& rDevice)
+{
+    if (mpMPShapesFunctor->isImportDone())
+        mbMasterPageRenderingDone = true;
+
+    if (mbMasterPageRenderingDone)
+        return;
+
+    tools::JsonWriter aJsonWriter;
+    aJsonWriter.put("group", "MasterPage");
+    std::string sLayerId = GetInterfaceHash(mxMasterPage) + "." + 
std::to_string(mnMPLayerIndex);
+    aJsonWriter.put("id", sLayerId);
+
+    if (!msLastPlaceholder.isEmpty())
+    {
+        aJsonWriter.put("type", "placeholder");
+        aJsonWriter.put("placeholderId", msLastPlaceholder);
+        msLastPlaceholder = "";
+        msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+        maJsonMsgList.push_back(msLastJsonMessage);
+        ++mnMPLayerIndex;
+        return;
+    }
+
+    bool bDoRendering = false;
+    while (!mpMPShapesFunctor->isImportDone())
+    {
+        ShapeSharedPtr const& rShape(mpMPShapesFunctor->importShape());
+        uno::Reference<drawing::XShape> xShape = rShape->getXShape();
+        if (xShape.is())
+        {
+            OUString sShapeType = xShape->getShapeType();
+            OUString sPlaceholderType = getPlaceholderType(sShapeType);
+            if (sPlaceholderType.isEmpty())
+            {
+                mpLayerManager->addShape(rShape);
+                bDoRendering = true;
+            }
+            else
+            {
+                if (bDoRendering)
+                {
+                    msLastPlaceholder = sPlaceholderType;
+                    renderLayerImpl(rDevice, aJsonWriter);
+                }
+                else
+                {
+                    aJsonWriter.put("type", "placeholder");
+                    aJsonWriter.put("placeholderId", sPlaceholderType);
+                }
+                bDoRendering = false;
+                msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+                maJsonMsgList.push_back(msLastJsonMessage);
+                ++mnMPLayerIndex;
+                return;
+            }
+        }
+    }
+    if (bDoRendering)
+    {
+        renderLayerImpl(rDevice, aJsonWriter);
+    }
+    msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+    maJsonMsgList.push_back(msLastJsonMessage);
+
+    mbMasterPageRenderingDone = true;
+}
+
+void LOKSlideRenderer::renderTextFieldsImpl(VirtualDevice& rDevice)
+{
+    while( !mpTFShapesFunctor->isImportDone() )
+    {
+        ShapeSharedPtr const& rShape(mpTFShapesFunctor->importShape());
+        uno::Reference<drawing::XShape> xShape = rShape->getXShape();
+        if (xShape.is())
+        {
+            OUString sShapeType = xShape->getShapeType();
+            OUString sPlaceholderType = getPlaceholderType(sShapeType);
+            if (!sPlaceholderType.isEmpty())
+            {
+                mpLayerManager->addShape(rShape);
+
+                // render and collect bitmap
+                renderLayerBitmapImpl(rDevice);
+                BitmapEx aBitmapEx(rDevice.GetBitmapEx(Point(0, 0), 
rDevice.GetOutputSizePixel()));
+                BitmapChecksum nChecksum = aBitmapEx.GetChecksum();
+                maBitmapMap[nChecksum] = aBitmapEx;
+
+                // json
+                OUString sLayerId = 
OUString::fromUtf8(GetInterfaceHash(mxMasterPage)) + "." + sPlaceholderType;
+                tools::JsonWriter aJsonWriter;
+                aJsonWriter.put("group", "TextFields");
+                aJsonWriter.put("id", sLayerId);
+                mbIsBitmapLayer = true;
+                aJsonWriter.put("type", "bitmap");
+                aJsonWriter.put("checksum", std::to_string(nChecksum));
+
+                msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+                maJsonMsgList.push_back(msLastJsonMessage);
+
+                // clean up
+                rDevice.Erase();
+                mpLayerManager->removeShape(rShape);
+                return;
+            }
+        }
+    }
+    mbTextFieldsRenderingDone = true;
+}
+
+void LOKSlideRenderer::renderLayerImpl(VirtualDevice& rDevice, 
tools::JsonWriter& rJsonWriter)
+{
+    // render and collect bitmap
+    renderLayerBitmapImpl(rDevice);
+    BitmapEx aBitmapEx(rDevice.GetBitmapEx(Point(0, 0), 
rDevice.GetOutputSizePixel()));
+    BitmapChecksum nChecksum = aBitmapEx.GetChecksum();
+    maBitmapMap[nChecksum] = aBitmapEx;
+
+    // json
+    mbIsBitmapLayer = true;
+    rJsonWriter.put("type", "bitmap");
+    rJsonWriter.put("checksum", std::to_string(nChecksum));
+
+    // clean up
+    rDevice.Erase();
+    mpLayerManager->removeAllShapes();
+}
+
+void LOKSlideRenderer::renderDrawPageImpl(VirtualDevice& rDevice)
+{
+    if (mpShapesFunctor->isImportDone())
+        mbDrawPageRenderingDone = true;
+
+    if (mbDrawPageRenderingDone)
+        return;
+
+    tools::JsonWriter aJsonWriter;
+    aJsonWriter.put("group", "DrawPage");
+    std::string sLayerId = GetInterfaceHash(mxDrawPage) + "." + 
std::to_string(mnDPLayerIndex);
+    aJsonWriter.put("id", sLayerId);
+
+    if (mpDPLastAnimatedShape)
+    {
+        renderAnimatedShapeImpl(rDevice, mpDPLastAnimatedShape, aJsonWriter);
+        mpDPLastAnimatedShape.reset();
+        msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+        maJsonMsgList.push_back(msLastJsonMessage);
+        ++mnDPLayerIndex;
+        return;
+    }
+
+    bool bDoRendering = false;
+    while (!mpShapesFunctor->isImportDone())
+    {
+        ShapeSharedPtr const& rShape(mpShapesFunctor->importShape());
+        if (rShape)
+        {
+            std::string sShapeId = GetInterfaceHash(rShape->getXShape());
+            const auto& rIter = maAnimatedShapeVisibilityMap.find(sShapeId);
+            bool bIsAnimated = rIter != maAnimatedShapeVisibilityMap.end();
+            if (!bIsAnimated)
+            {
+                mpLayerManager->addShape(rShape);
+                bDoRendering = true;
+            }
+            else
+            {
+                if (bDoRendering)
+                {
+                    mpDPLastAnimatedShape = rShape;
+                    renderLayerImpl(rDevice, aJsonWriter);
+                }
+                else
+                {
+                    renderAnimatedShapeImpl(rDevice, rShape, aJsonWriter);
+                }
+                msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+                maJsonMsgList.push_back(msLastJsonMessage);
+                ++mnDPLayerIndex;
+                return;
+            }
+        }
+    }
+    if (bDoRendering)
+    {
+        renderLayerImpl(rDevice, aJsonWriter);
+    }
+    msLastJsonMessage = aJsonWriter.finishAndGetAsOString();
+    maJsonMsgList.push_back(msLastJsonMessage);
+
+    mbDrawPageRenderingDone = true;
+}
+
+void LOKSlideRenderer::renderAnimatedShapeImpl(VirtualDevice& rDevice,
+                                               const std::shared_ptr<Shape>& 
pShape,
+                                               tools::JsonWriter& rJsonWriter)
+{
+    rJsonWriter.put("type", "animated");
+
+    std::string sShapeId = GetInterfaceHash(pShape->getXShape());
+    rJsonWriter.put("shapeHash", sShapeId);
+
+    bool bIsInitVisible = maAnimatedShapeVisibilityMap.at(sShapeId);
+    rJsonWriter.put("initVisible", bIsInitVisible);
+    tools::ScopedJsonWriterNode aData = rJsonWriter.startNode("data");
+    if (bIsInitVisible)
+    {
+        mpLayerManager->addShape(pShape);
+        renderLayerImpl(rDevice, rJsonWriter);
+    }
+}
+
+void LOKSlideRenderer::renderImpl(LayerGroupType eLayersSet, unsigned char* 
pBuffer)
+{
+    VclPtr<VirtualDevice> pDevice = 
VclPtr<VirtualDevice>::Create(DeviceFormat::WITH_ALPHA);
+    pDevice->SetBackground(Wallpaper(COL_TRANSPARENT));
+    pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer(
+        maDeviceSize, Fraction(1.0),
+        Point(), pBuffer);
+
+    pDevice->Erase();
+    OSL_ASSERT(pDevice->GetCanvas().is());
+    mbIsBitmapLayer = false;
+    msLastJsonMessage = ""_ostr;
+    try
+    {
+        switch (eLayersSet)
+        {
+            case LayerGroupType::BACKGROUND: return 
renderBackgroundImpl(*pDevice);
+            case LayerGroupType::MASTER_PAGE: return 
renderMasterPageImpl(*pDevice);
+            case LayerGroupType::DRAW_PAGE: return 
renderDrawPageImpl(*pDevice);
+            case LayerGroupType::TEXT_FIELDS: return 
renderTextFieldsImpl(*pDevice);
+        }
+    }
+    catch (uno::RuntimeException&)
+    {
+        throw;
+    }
+    catch (ShapeLoadFailedException&)
+    {
+        // TODO(E2): Error handling. For now, bail out
+        TOOLS_WARN_EXCEPTION( "slideshow", "SlideImpl::loadShapes(): caught 
ShapeLoadFailedException" );
+        return;
+    }
+    catch (uno::Exception&)
+    {
+        TOOLS_WARN_EXCEPTION( "slideshow", "Geenral Exception");
+        return;
+    }
+}
+
+SlideBitmapSharedPtr LOKSlideRenderer::createLayerBitmap(const 
::cppcanvas::CanvasSharedPtr& pCanvas,
+                                                         const 
::basegfx::B2ISize& rBmpSize ) const
+{
+    ::cppcanvas::BitmapSharedPtr pBitmap(
+        ::cppcanvas::BaseGfxFactory::createBitmap(
+            pCanvas,
+            rBmpSize ) );
+
+    ENSURE_OR_THROW(pBitmap,
+                    "LOKSlideRenderer::createCurrentSlideBitmap(): Cannot 
create page bitmap");
+
+    ::cppcanvas::BitmapCanvasSharedPtr 
pBitmapCanvas(pBitmap->getBitmapCanvas());
+
+    ENSURE_OR_THROW( pBitmapCanvas,
+                    "LOKSlideRenderer::createCurrentSlideBitmap(): Cannot 
create page bitmap canvas" );
+
+    // apply linear part of destination canvas transformation (linear means in 
this context:
+    // transformation without any translational components)
+    ::basegfx::B2DHomMatrix aLinearTransform(maTransformation);
+    aLinearTransform.set( 0, 2, 0.0 );
+    aLinearTransform.set( 1, 2, 0.0 );
+    pBitmapCanvas->setTransformation( aLinearTransform );
+
+    initSlideBackground( pBitmapCanvas, rBmpSize );
+    mpLayerManager->renderTo( pBitmapCanvas );
+
+    return std::make_shared<SlideBitmap>( pBitmap );
+}
+
+void LOKSlideRenderer::renderLayerBitmapImpl(VirtualDevice& rDevice)
+{
+    auto aSize = getSlideSizePixel(basegfx::B2DVector(maSlideSize.getWidth(), 
maSlideSize.getHeight()),
+                                   maTransformation);
+    const basegfx::B2ISize rSlideSize(aSize.getX(), aSize.getY());
+
+    ::cppcanvas::CanvasSharedPtr pCanvas = 
cppcanvas::VCLFactory::createCanvas(rDevice.GetCanvas());
+
+    SlideBitmapSharedPtr pBitmap = createLayerBitmap(pCanvas, rSlideSize);
+
+    // setup a canvas with device coordinate space, the slide
+    // bitmap already has the correct dimension.
+    //    const ::basegfx::B2DPoint aOutPosPixel( rTransformation * 
::basegfx::B2DPoint() );
+    ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() );
+
+    // render at given output position
+    //    pBitmap->move( aOutPosPixel );
+
+    // clear clip (might have been changed, e.g. from comb
+    // transition)
+    pBitmap->clip( ::basegfx::B2DPolyPolygon() );
+    pBitmap->draw( pDevicePixelCanvas );
+}
+
+void LOKSlideRenderer::collectAnimatedShapes()
+{
+    if (!mxRootNode.is())
+        return;
+
+    const uno::Sequence< animations::TargetProperties > aProps(
+        TargetPropertiesCreator::createTargetProperties( mxRootNode, true /* 
Initial */ ) );
+
+    for (const auto& rProp : aProps)
+    {
+        uno::Reference<drawing::XShape> xShape(rProp.Target, uno::UNO_QUERY);
+
+        if (!xShape.is())
+        {
+            // not a shape target. Maybe a ParagraphTarget?
+            presentation::ParagraphTarget aParaTarget;
+
+            if (rProp.Target >>= aParaTarget)
+            {
+                // yep, ParagraphTarget found - extract shape
+                // and index
+                xShape = aParaTarget.Shape;
+            }
+        }
+
+        if( xShape.is() )
+        {
+            const uno::Sequence< beans::NamedValue >& rShapeProps( 
rProp.Properties );
+            for (const auto& rShapeProp : rShapeProps)
+            {
+                bool bVisible = false;
+                if (rShapeProp.Name.equalsIgnoreAsciiCase("visibility") &&
+                    extractValue( bVisible,
+                                 rShapeProp.Value,
+                                 nullptr,
+                                 basegfx::B2DVector() ))
+                {
+                    maAnimatedShapeVisibilityMap[GetInterfaceHash(xShape)] = 
bVisible;
+                }
+                else
+                {
+                    OSL_FAIL( "LOKSlideRenderer::collectAnimatedShapes:(): 
Unexpected "
+                             "(and unimplemented) property encountered" );
+                }
+            }
+        }
+    }
+}
 
 class SlideImpl : public Slide,
                   public CursorManager,
@@ -85,7 +754,7 @@ public:
                double                                            
dUserPaintStrokeWidth,
                bool                                              
bUserPaintEnabled,
                bool                                              
bIntrinsicAnimationsAllowed,
-               bool                                              
bDisableAnimationZOrder );
+               bool                                              
bDisableAnimationZOrder);
 
     virtual ~SlideImpl() override;
 
@@ -111,6 +780,13 @@ public:
     // but on canvas-independent basegfx bitmaps
     virtual SlideBitmapSharedPtr getCurrentSlideBitmap( const 
UnoViewSharedPtr& rView ) const override;
 
+    virtual Size createLOKSlideRenderer(int nViewWidth, int nViewHeight,
+                                        bool bRenderBackground,
+                                        bool bRenderMasterPageObjects) 
override;
+
+    virtual bool renderNextLOKSlideLayer(unsigned char* buffer,
+                                         bool& bIsBitmapLayer,
+                                         OString& rJsonMsg) override;
 
 private:
     // ViewEventHandler
@@ -209,6 +885,8 @@ private:
     SlideAnimations                                     maAnimations;
     PolyPolygonVector                                   maPolygons;
 
+    std::shared_ptr<LOKSlideRenderer> mpLOKRenderer;
+
     RGBColor                                            maUserPaintColor;
     double                                              mdUserPaintStrokeWidth;
     UserPaintOverlaySharedPtr                           mpPaintOverlay;
@@ -306,7 +984,7 @@ SlideImpl::SlideImpl( const uno::Reference< 
drawing::XDrawPage >&           xDra
                       double                                                
dUserPaintStrokeWidth,
                       bool                                                  
bUserPaintEnabled,
                       bool                                                  
bIntrinsicAnimationsAllowed,
-                      bool                                                  
bDisableAnimationZOrder ) :
+                      bool                                                  
bDisableAnimationZOrder) :
     mxDrawPage( xDrawPage ),
     mxDrawPagesSupplier(std::move( xDrawPages )),
     mxRootNode(std::move( xRootNode )),
@@ -644,6 +1322,42 @@ bool SlideImpl::isAnimated()
     return mbHaveAnimations && maAnimations.isAnimated();
 }
 
+Size SlideImpl::createLOKSlideRenderer(int nViewWidth, int nViewHeight,
+                                       bool bRenderBackground, bool 
bRenderMasterPageObjects)
+{
+    if (!mpLOKRenderer)
+    {
+        Size aViewSize(nViewWidth, nViewHeight);
+        Size aSlideSize(getSlideSize().getWidth(), getSlideSize().getHeight());
+        mpLOKRenderer = std::make_shared<LOKSlideRenderer>(aViewSize, 
aSlideSize,
+                                                           bRenderBackground,
+                                                           
bRenderMasterPageObjects,
+                                                           mxDrawPage, 
mxDrawPagesSupplier,
+                                                           mxRootNode, 
maContext, mpLayerManager);
+        if (mpLOKRenderer)
+        {
+            return mpLOKRenderer->getDeviceSize();
+        }
+    }
+    return {};
+}
+
+bool SlideImpl::renderNextLOKSlideLayer(unsigned char* buffer, bool& 
bIsBitmapLayer, OString& rJsonMsg)
+{
+    if (mpLOKRenderer)
+    {
+        if (!mpLOKRenderer->isSlideRenderingDone())
+        {
+            mpLOKRenderer->renderNextLayer(buffer);
+            bIsBitmapLayer = mpLOKRenderer->isBitmapLayer();
+            rJsonMsg = mpLOKRenderer->getJsonMessage();
+        }
+
+        return mpLOKRenderer->isSlideRenderingDone();
+    }
+    return true;
+}
+
 SlideBitmapSharedPtr SlideImpl::createCurrentSlideBitmap( const 
UnoViewSharedPtr&   rView,
                                                           const 
::basegfx::B2ISize& rBmpSize ) const
 {
diff --git a/slideshow/source/engine/slideshowimpl.cxx 
b/slideshow/source/engine/slideshowimpl.cxx
index 5e0dbbb8074e..c2a33837e8af 100644
--- a/slideshow/source/engine/slideshowimpl.cxx
+++ b/slideshow/source/engine/slideshowimpl.cxx
@@ -38,6 +38,8 @@
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/utils/canvastools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 #include <sal/log.hxx>
 
@@ -77,6 +79,7 @@
 #include <slideview.hxx>
 #include <tools.hxx>
 #include <unoview.hxx>
+#include <vcl/virdev.hxx>
 #include "rehearsetimingsactivity.hxx"
 #include "waitsymbol.hxx"
 #include "effectrewinder.hxx"
@@ -307,6 +310,16 @@ private:
     virtual void SAL_CALL setShapeCursor(
         uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape 
) override;
 
+    virtual sal_Bool SAL_CALL createLOKSlideRenderer(
+        sal_Int32& nViewWidth, sal_Int32& nViewHeight,
+        sal_Bool bRenderMasterPage, sal_Bool bRenderBackground,
+        const uno::Reference<drawing::XDrawPage>& xSlide,
+        const uno::Reference<drawing::XDrawPagesSupplier>& xDrawPages,
+        const uno::Reference<animations::XAnimationNode>& xRootNode) override;
+
+    virtual sal_Bool SAL_CALL renderNextLOKSlideLayer(
+        sal_Int64 nBufferPointer, sal_Bool& bIsBitmapLayer, OUString& 
rJsonMsg) override;
+
     // CursorManager
 
 
@@ -1061,6 +1074,68 @@ private:
     bool& mrbSkipSlideTransition;
 };
 
+sal_Bool SlideShowImpl::createLOKSlideRenderer(
+    sal_Int32& nViewWidth, sal_Int32& nViewHeight,
+    sal_Bool bRenderMasterPage, sal_Bool bRenderBackground,
+    uno::Reference<drawing::XDrawPage> const& xDrawPage,
+    uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
+    uno::Reference<animations::XAnimationNode> const&  xRootNode)
+{
+    if (!xDrawPage.is())
+        return false;
+
+    //Retrieve polygons for the current slide
+    PolygonMap::iterator aIter = findPolygons(xDrawPage);
+
+    mpCurrentSlide = createSlide(xDrawPage,
+                                xDrawPages,
+                                xRootNode,
+                                maEventQueue,
+                                maEventMultiplexer,
+                                maScreenUpdater,
+                                maActivitiesQueue,
+                                maUserEventQueue,
+                                *this,
+                                *this,
+                                maViewContainer,
+                                mxComponentContext,
+                                maShapeEventListeners,
+                                maShapeCursors,
+                                (aIter != maPolygons.end()) ? aIter->second :  
PolyPolygonVector(),
+                                maUserPaintColor ? *maUserPaintColor : 
RGBColor(),
+                                maUserPaintStrokeWidth,
+                                !!maUserPaintColor,
+                                mbImageAnimationsAllowed,
+                                mbDisableAnimationZOrder);
+
+    if (!mpCurrentSlide)
+        return false;
+
+    const Size& rDeviceSize = 
mpCurrentSlide->createLOKSlideRenderer(nViewWidth, nViewHeight,
+                                                                     
bRenderBackground,
+                                                                     
bRenderMasterPage);
+    nViewWidth = rDeviceSize.getWidth();
+    nViewHeight = rDeviceSize.getHeight();
+
+    return (nViewWidth > 0 && nViewHeight > 0);
+}
+
+sal_Bool SlideShowImpl::renderNextLOKSlideLayer(sal_Int64 nBufferPointer, 
sal_Bool& bIsBitmapLayer, OUString& rJsonMsg)
+{
+    if (!mpCurrentSlide)
+        return true;
+
+    auto pBuffer = reinterpret_cast<unsigned char*>(nBufferPointer);
+    bool bBitmapRendered = false;
+    OString sMsg;
+    bool bDone = mpCurrentSlide->renderNextLOKSlideLayer(pBuffer, 
bBitmapRendered, sMsg);
+
+    bIsBitmapLayer = bBitmapRendered;
+    rJsonMsg = OUString::fromUtf8(sMsg);
+
+    return bDone;
+}
+
 void SlideShowImpl::displaySlide(
     uno::Reference<drawing::XDrawPage> const& xSlide,
     uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
diff --git a/slideshow/source/inc/shapeimporter.hxx 
b/slideshow/source/inc/shapeimporter.hxx
index 37598aa476bf..f4463e39c425 100644
--- a/slideshow/source/inc/shapeimporter.hxx
+++ b/slideshow/source/inc/shapeimporter.hxx
@@ -95,6 +95,17 @@ public:
     const PolyPolygonVector& getPolygons() const;
 
     double getImportedShapesCount() const{ return mnAscendingPrio; }
+
+    void setMasterPageObjectsOnly(bool bMasterPageObjectsOnly)
+    {
+        mbMasterPageObjectsOnly = bMasterPageObjectsOnly;
+    }
+
+    void setTextFieldsOnly(bool bTextFieldsOnly)
+    {
+        mbTextFieldsOnly = bTextFieldsOnly;
+    }
+
 private:
     bool isSkip( css::uno::Reference<css::beans::XPropertySet> const& xPropSet,
                  std::u16string_view shapeType,
@@ -132,6 +143,8 @@ private:
     ::std::stack<XShapesEntry>                maShapesStack;
     double                                    mnAscendingPrio;
     bool                                      mbConvertingMasterPage;
+    bool mbMasterPageObjectsOnly;
+    bool mbTextFieldsOnly;
 };
 
 } // namespace presentation::internal
diff --git a/slideshow/source/inc/slide.hxx b/slideshow/source/inc/slide.hxx
index ea460582d120..f49a4713d30f 100644
--- a/slideshow/source/inc/slide.hxx
+++ b/slideshow/source/inc/slide.hxx
@@ -44,6 +44,8 @@ namespace basegfx
     class B2IVector;
 }
 
+class Size;
+
 /* Definition of Slide interface */
 
 namespace slideshow::internal
@@ -141,6 +143,14 @@ namespace slideshow::internal
             virtual SlideBitmapSharedPtr
                 getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const = 
0;
 
+            virtual Size createLOKSlideRenderer(int nViewWidth, int 
nViewHeight,
+                                                bool bRenderBackground,
+                                                bool bRenderMasterPageObjects) 
= 0;
+
+            virtual bool renderNextLOKSlideLayer(unsigned char* buffer,
+                                                 bool& bIsBitmapLayer,
+                                                 OString& rJsonMsg) = 0;
+
         protected:
             ~Slide() {}
         };

Reply via email to