summaryrefslogtreecommitdiff
path: root/slideshow/source
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2024-06-24 15:26:18 +0900
committerMiklos Vajna <vmiklos@collabora.com>2024-07-10 08:05:56 +0200
commit1f0fd06bc0cfe5036661ce2c23911f34eccf678a (patch)
treee18e8ec47b4b788c9cf3e5eb62021e5df6d6c3ed /slideshow/source
parent6f96e7720f765d4e5e8fdef6a2a2b8cbb75c81ef (diff)
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/+/170214 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'slideshow/source')
-rw-r--r--slideshow/source/engine/shapes/shapeimporter.cxx30
-rw-r--r--slideshow/source/engine/slide/slideimpl.cxx718
-rw-r--r--slideshow/source/engine/slideshowimpl.cxx75
-rw-r--r--slideshow/source/inc/shapeimporter.hxx13
-rw-r--r--slideshow/source/inc/slide.hxx10
5 files changed, 839 insertions, 7 deletions
diff --git a/slideshow/source/engine/shapes/shapeimporter.cxx b/slideshow/source/engine/shapes/shapeimporter.cxx
index 42eed1dc9952..bca8cc3f06ca 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 );
@@ -318,7 +327,7 @@ ShapeSharedPtr ShapeImporter::createShape(
aGraphAttrs ) );
return DrawShape::create( xCurrShape,
- mxPage,
+ xPage,
mnAscendingPrio,
std::move(pGraphic),
mrContext );
@@ -326,7 +335,7 @@ ShapeSharedPtr ShapeImporter::createShape(
else
{
return DrawShape::create( xCurrShape,
- mxPage,
+ xPage,
mnAscendingPrio,
false,
mrContext );
@@ -392,6 +401,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;
}
@@ -543,7 +561,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 436822f0ae2a..28597322ecbc 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);
+ auto 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 61f2f6345d1f..7a6d5e8f34d3 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() {}
};