summaryrefslogtreecommitdiffstats
path: root/sd/source/ui/presenter
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/ui/presenter
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/presenter')
-rw-r--r--sd/source/ui/presenter/CanvasUpdateRequester.cxx131
-rw-r--r--sd/source/ui/presenter/CanvasUpdateRequester.hxx72
-rw-r--r--sd/source/ui/presenter/PresenterCanvas.cxx790
-rw-r--r--sd/source/ui/presenter/PresenterCanvas.hxx320
-rw-r--r--sd/source/ui/presenter/PresenterHelper.cxx466
-rw-r--r--sd/source/ui/presenter/PresenterHelper.hxx93
-rw-r--r--sd/source/ui/presenter/PresenterPreviewCache.cxx360
-rw-r--r--sd/source/ui/presenter/PresenterPreviewCache.hxx97
-rw-r--r--sd/source/ui/presenter/PresenterTextView.cxx466
-rw-r--r--sd/source/ui/presenter/PresenterTextView.hxx71
-rw-r--r--sd/source/ui/presenter/SlideRenderer.cxx201
-rw-r--r--sd/source/ui/presenter/SlideRenderer.hxx94
12 files changed, 3161 insertions, 0 deletions
diff --git a/sd/source/ui/presenter/CanvasUpdateRequester.cxx b/sd/source/ui/presenter/CanvasUpdateRequester.cxx
new file mode 100644
index 000000000..2271ba781
--- /dev/null
+++ b/sd/source/ui/presenter/CanvasUpdateRequester.cxx
@@ -0,0 +1,131 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CanvasUpdateRequester.hxx"
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <cppuhelper/weakref.hxx>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== CanvasUpdateRequester::Deleter ========================================
+
+class CanvasUpdateRequester::Deleter
+{
+public:
+ void operator() (CanvasUpdateRequester* pObject) { delete pObject; }
+};
+
+//===== CanvasUpdateRequester =================================================
+
+std::shared_ptr<CanvasUpdateRequester> CanvasUpdateRequester::Instance (
+ const Reference<rendering::XSpriteCanvas>& rxSharedCanvas)
+{
+ // this global must not own anything or we crash on shutdown
+ static std::vector<std::pair<
+ uno::WeakReference<rendering::XSpriteCanvas>,
+ std::weak_ptr<CanvasUpdateRequester>>> s_RequesterMap;
+ for (auto it = s_RequesterMap.begin(); it != s_RequesterMap.end(); )
+ {
+ uno::Reference<rendering::XSpriteCanvas> const xCanvas(it->first);
+ if (!xCanvas.is())
+ {
+ it = s_RequesterMap.erase(it); // remove stale entry
+ }
+ else if (xCanvas == rxSharedCanvas)
+ {
+ std::shared_ptr<CanvasUpdateRequester> pRequester(it->second);
+ if (pRequester)
+ {
+ return pRequester;
+ }
+ else
+ {
+ std::shared_ptr<CanvasUpdateRequester> const pNew(
+ new CanvasUpdateRequester(rxSharedCanvas), Deleter());
+ it->second = pNew;
+ return pNew;
+ }
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ // No requester for the given canvas found. Create a new one.
+ std::shared_ptr<CanvasUpdateRequester> pRequester (
+ new CanvasUpdateRequester(rxSharedCanvas), Deleter());
+ s_RequesterMap.emplace_back(rxSharedCanvas, pRequester);
+ return pRequester;
+}
+
+
+CanvasUpdateRequester::CanvasUpdateRequester (
+ const Reference<rendering::XSpriteCanvas>& rxCanvas)
+ : mxCanvas(rxCanvas)
+ , m_pUserEventId(nullptr)
+ , mbUpdateFlag(false)
+{
+ Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
+ if (xComponent.is())
+ {
+ //xComponent->addEventListener(this);
+ }
+}
+
+CanvasUpdateRequester::~CanvasUpdateRequester()
+{
+ assert(m_pUserEventId == nullptr);
+}
+
+void CanvasUpdateRequester::RequestUpdate (const bool bUpdateAll)
+{
+ if (m_pUserEventId == nullptr)
+ {
+ m_pThis = shared_from_this(); // keep instance alive until dispatch
+ mbUpdateFlag = bUpdateAll;
+ m_pUserEventId = Application::PostUserEvent(LINK(this, CanvasUpdateRequester, Callback));
+ }
+ else
+ {
+ mbUpdateFlag |= bUpdateAll;
+ }
+}
+
+IMPL_LINK_NOARG(CanvasUpdateRequester, Callback, void*, void)
+{
+ m_pUserEventId = nullptr;
+ if (mxCanvas.is())
+ {
+ mxCanvas->updateScreen(mbUpdateFlag);
+ mbUpdateFlag = false;
+ }
+ assert(m_pThis);
+ m_pThis.reset(); // possibly delete "this"
+}
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/CanvasUpdateRequester.hxx b/sd/source/ui/presenter/CanvasUpdateRequester.hxx
new file mode 100644
index 000000000..ebb582ead
--- /dev/null
+++ b/sd/source/ui/presenter/CanvasUpdateRequester.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <tools/link.hxx>
+#include <memory>
+
+namespace com::sun::star::rendering
+{
+class XSpriteCanvas;
+}
+
+struct ImplSVEvent;
+
+namespace sd::presenter
+{
+/** Each UpdateRequester handles update requests (calls to
+ XCanvas::updateScreen()) for one shared canvas (a canvas that has one or
+ more PresenterCanvas wrappers). Multiple calls are collected and lead
+ to a single call to updateScreen.
+*/
+class CanvasUpdateRequester : public std::enable_shared_from_this<CanvasUpdateRequester>
+{
+public:
+ CanvasUpdateRequester(const CanvasUpdateRequester&) = delete;
+ CanvasUpdateRequester& operator=(const CanvasUpdateRequester&) = delete;
+
+ /** @return the Canvas UpdateRequester object for the given shared canvas.
+ A new object is created when it does not already exist.
+ */
+ static std::shared_ptr<CanvasUpdateRequester>
+ Instance(const css::uno::Reference<css::rendering::XSpriteCanvas>& rxCanvas);
+
+ void RequestUpdate(const bool bUpdateAll);
+
+private:
+ explicit CanvasUpdateRequester(
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxCanvas);
+ ~CanvasUpdateRequester();
+ class Deleter;
+ friend class Deleter;
+
+ /// keep instance alive waiting for event dispatch
+ std::shared_ptr<CanvasUpdateRequester> m_pThis;
+ css::uno::Reference<css::rendering::XSpriteCanvas> mxCanvas;
+ ImplSVEvent* m_pUserEventId;
+ bool mbUpdateFlag;
+
+ DECL_LINK(Callback, void*, void);
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterCanvas.cxx b/sd/source/ui/presenter/PresenterCanvas.cxx
new file mode 100644
index 000000000..f586969bc
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterCanvas.cxx
@@ -0,0 +1,790 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterCanvas.hxx"
+#include "CanvasUpdateRequester.hxx"
+
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <com/sun/star/awt/XWindow.hpp>
+#include <comphelper/compbase.hxx>
+#include <rtl/ref.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== PresenterCustomSprite =================================================
+
+/** Wrapper around a sprite that is displayed on a PresenterCanvas.
+*/
+namespace {
+ typedef comphelper::WeakComponentImplHelper <
+ css::rendering::XCustomSprite
+ > PresenterCustomSpriteInterfaceBase;
+
+class PresenterCustomSprite final
+ : public PresenterCustomSpriteInterfaceBase
+{
+public:
+ PresenterCustomSprite (
+ const rtl::Reference<PresenterCanvas>& rpCanvas,
+ const Reference<rendering::XCustomSprite>& rxSprite,
+ const Reference<awt::XWindow>& rxBaseWindow);
+ PresenterCustomSprite(const PresenterCustomSprite&) = delete;
+ PresenterCustomSprite& operator=(const PresenterCustomSprite&) = delete;
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ // XSprite
+
+ virtual void SAL_CALL setAlpha (double nAlpha) override;
+
+ virtual void SAL_CALL move (const geometry::RealPoint2D& rNewPos,
+ const rendering::ViewState& rViewState,
+ const rendering::RenderState& rRenderState) override;
+
+ virtual void SAL_CALL transform (const geometry::AffineMatrix2D& rTransformation) override;
+
+ virtual void SAL_CALL clip (const Reference<rendering::XPolyPolygon2D>& rClip) override;
+
+ virtual void SAL_CALL setPriority (double nPriority) override;
+
+ virtual void SAL_CALL show() override;
+
+ virtual void SAL_CALL hide() override;
+
+ // XCustomSprite
+
+ virtual Reference<rendering::XCanvas> SAL_CALL getContentCanvas() override;
+
+private:
+ rtl::Reference<PresenterCanvas> mpCanvas;
+ Reference<rendering::XCustomSprite> mxSprite;
+ Reference<awt::XWindow> mxBaseWindow;
+ geometry::RealPoint2D maPosition;
+
+ /// @throws css::lang::DisposedException
+ void ThrowIfDisposed();
+};
+
+}
+
+//===== PresenterCanvas =======================================================
+
+PresenterCanvas::PresenterCanvas (
+ const Reference<rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const Reference<awt::XWindow>& rxUpdateWindow,
+ const Reference<rendering::XCanvas>& rxSharedCanvas,
+ const Reference<awt::XWindow>& rxSharedWindow,
+ const Reference<awt::XWindow>& rxWindow)
+ : mxUpdateCanvas(rxUpdateCanvas),
+ mxUpdateWindow(rxUpdateWindow),
+ mxSharedCanvas(rxSharedCanvas),
+ mxSharedWindow(rxSharedWindow),
+ mxWindow(rxWindow),
+ mbOffsetUpdatePending(true)
+{
+ if (mxWindow.is())
+ mxWindow->addWindowListener(this);
+
+ if (mxUpdateCanvas.is())
+ {
+ m_pUpdateRequester = CanvasUpdateRequester::Instance(mxUpdateCanvas);
+ }
+}
+
+PresenterCanvas::~PresenterCanvas()
+{
+}
+
+void PresenterCanvas::disposing(std::unique_lock<std::mutex>&)
+{
+ if (mxWindow.is())
+ {
+ mxWindow->removeWindowListener(this);
+ mxWindow.clear();
+ }
+}
+
+//----- XCanvas ---------------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::clear()
+{
+ ThrowIfDisposed();
+ // ToDo: Clear the area covered by the child window. A simple forward
+ // would clear the whole shared canvas.
+}
+
+void SAL_CALL PresenterCanvas::drawPoint (
+ const css::geometry::RealPoint2D& aPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawPoint(aPoint,MergeViewState(aViewState),aRenderState);
+}
+
+void SAL_CALL PresenterCanvas::drawLine (
+ const css::geometry::RealPoint2D& aStartPoint,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawLine(aStartPoint,aEndPoint,MergeViewState(aViewState),aRenderState);
+}
+
+void SAL_CALL PresenterCanvas::drawBezier (
+ const css::geometry::RealBezierSegment2D& aBezierSegment,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ mxSharedCanvas->drawBezier(aBezierSegment,aEndPoint,MergeViewState(aViewState),aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL PresenterCanvas::drawPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL PresenterCanvas::strokePolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokePolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::strokeTexturedPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& aTextures,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokeTexturedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aTextures, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::strokeTextureMappedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& aTextures,
+ const css::uno::Reference<css::geometry::XMapping2D>& xMapping,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->strokeTextureMappedPolyPolygon(
+ xPolyPolygon,
+ MergeViewState(aViewState),
+ aRenderState,
+ aTextures,
+ xMapping,
+ aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XPolyPolygon2D> SAL_CALL
+ PresenterCanvas::queryStrokeShapes(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->queryStrokeShapes(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, aStrokeAttributes);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillTexturedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& xTextures)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillTexturedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, xTextures);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::fillTextureMappedPolyPolygon(
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& xTextures,
+ const css::uno::Reference< css::geometry::XMapping2D >& xMapping)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->fillTextureMappedPolyPolygon(
+ xPolyPolygon, MergeViewState(aViewState), aRenderState, xTextures, xMapping);
+}
+
+css::uno::Reference<css::rendering::XCanvasFont> SAL_CALL
+ PresenterCanvas::createFont(
+ const css::rendering::FontRequest& aFontRequest,
+ const css::uno::Sequence< css::beans::PropertyValue >& aExtraFontProperties,
+ const css::geometry::Matrix2D& aFontMatrix)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->createFont(
+ aFontRequest, aExtraFontProperties, aFontMatrix);
+}
+
+css::uno::Sequence<css::rendering::FontInfo> SAL_CALL
+ PresenterCanvas::queryAvailableFonts(
+ const css::rendering::FontInfo& aFilter,
+ const css::uno::Sequence< css::beans::PropertyValue >& aFontProperties)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->queryAvailableFonts(aFilter, aFontProperties);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawText(
+ const css::rendering::StringContext& aText,
+ const css::uno::Reference< css::rendering::XCanvasFont >& xFont,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ ::sal_Int8 nTextDirection)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawText(
+ aText, xFont, MergeViewState(aViewState), aRenderState, nTextDirection);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawTextLayout(
+ const css::uno::Reference< css::rendering::XTextLayout >& xLayoutetText,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawTextLayout(
+ xLayoutetText, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawBitmap(
+ const css::uno::Reference< css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawBitmap(
+ xBitmap, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ PresenterCanvas::drawBitmapModulated(
+ const css::uno::Reference< css::rendering::XBitmap>& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState)
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->drawBitmapModulated(
+ xBitmap, MergeViewState(aViewState), aRenderState);
+}
+
+css::uno::Reference<css::rendering::XGraphicDevice> SAL_CALL
+ PresenterCanvas::getDevice()
+{
+ ThrowIfDisposed();
+ return mxSharedCanvas->getDevice();
+}
+
+//----- XSpriteCanvas ---------------------------------------------------------
+
+Reference<rendering::XAnimatedSprite> SAL_CALL
+ PresenterCanvas::createSpriteFromAnimation (
+ const css::uno::Reference<css::rendering::XAnimation>& rAnimation)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createSpriteFromAnimation(rAnimation);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XAnimatedSprite> SAL_CALL
+ PresenterCanvas::createSpriteFromBitmaps (
+ const css::uno::Sequence<
+ css::uno::Reference< css::rendering::XBitmap > >& rAnimationBitmaps,
+ ::sal_Int8 nInterpolationMode)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createSpriteFromBitmaps(rAnimationBitmaps, nInterpolationMode);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XCustomSprite> SAL_CALL
+ PresenterCanvas::createCustomSprite (
+ const css::geometry::RealSize2D& rSpriteSize)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return new PresenterCustomSprite(
+ this,
+ xSpriteCanvas->createCustomSprite(rSpriteSize),
+ mxSharedWindow);
+ else if (mxUpdateCanvas.is())
+ return new PresenterCustomSprite(
+ this,
+ mxUpdateCanvas->createCustomSprite(rSpriteSize),
+ mxUpdateWindow);
+ else
+ return nullptr;
+}
+
+Reference<rendering::XSprite> SAL_CALL
+ PresenterCanvas::createClonedSprite (
+ const css::uno::Reference< css::rendering::XSprite >& rxOriginal)
+{
+ ThrowIfDisposed();
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxSharedCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ return xSpriteCanvas->createClonedSprite(rxOriginal);
+ if (mxUpdateCanvas.is())
+ return mxUpdateCanvas->createClonedSprite(rxOriginal);
+ return nullptr;
+}
+
+sal_Bool SAL_CALL PresenterCanvas::updateScreen (sal_Bool bUpdateAll)
+{
+ ThrowIfDisposed();
+
+ mbOffsetUpdatePending = true;
+ if (m_pUpdateRequester != nullptr)
+ {
+ m_pUpdateRequester->RequestUpdate(bUpdateAll);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//----- XEventListener --------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::disposing (const css::lang::EventObject& rEvent)
+{
+ ThrowIfDisposed();
+ if (rEvent.Source == mxWindow)
+ mxWindow = nullptr;
+}
+
+//----- XWindowListener -------------------------------------------------------
+
+void SAL_CALL PresenterCanvas::windowResized (const css::awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowMoved (const css::awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowShown (const css::lang::EventObject&)
+{
+ ThrowIfDisposed();
+ mbOffsetUpdatePending = true;
+}
+
+void SAL_CALL PresenterCanvas::windowHidden (const css::lang::EventObject&)
+{
+ ThrowIfDisposed();
+}
+
+//----- XBitmap ---------------------------------------------------------------
+
+geometry::IntegerSize2D SAL_CALL PresenterCanvas::getSize()
+{
+ ThrowIfDisposed();
+
+ if (mxWindow.is())
+ {
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ return geometry::IntegerSize2D(aWindowBox.Width, aWindowBox.Height);
+ }
+ else
+ return geometry::IntegerSize2D(0,0);
+}
+
+sal_Bool SAL_CALL PresenterCanvas::hasAlpha()
+{
+ Reference<rendering::XBitmap> xBitmap (mxSharedCanvas, UNO_QUERY);
+ if (xBitmap.is())
+ return xBitmap->hasAlpha();
+ else
+ return false;
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterCanvas::getScaledBitmap(
+ const css::geometry::RealSize2D&,
+ sal_Bool)
+{
+ ThrowIfDisposed();
+
+ // Not implemented.
+
+ return nullptr;
+}
+
+rendering::ViewState PresenterCanvas::MergeViewState (
+ const rendering::ViewState& rViewState)
+{
+ // Make sure the offset is up-to-date.
+ if (mbOffsetUpdatePending)
+ maOffset = GetOffset(mxSharedWindow);
+ return MergeViewState(rViewState, maOffset);
+}
+
+css::rendering::ViewState PresenterCanvas::MergeViewState (
+ const css::rendering::ViewState& rViewState,
+ const css::awt::Point& rOffset)
+{
+ // Early rejects.
+ if ( ! mxSharedCanvas.is())
+ return rViewState;
+
+ Reference<rendering::XGraphicDevice> xDevice (mxSharedCanvas->getDevice());
+ if ( ! xDevice.is())
+ return rViewState;
+
+ // Create a modifiable copy of the given view state.
+ rendering::ViewState aViewState (rViewState);
+
+ // Prepare the local clip rectangle.
+ ::basegfx::B2DRectangle aWindowRange (GetClipRectangle(aViewState.AffineTransform, rOffset));
+
+ // Adapt the offset of the view state.
+ aViewState.AffineTransform.m02 += rOffset.X;
+ aViewState.AffineTransform.m12 += rOffset.Y;
+
+ // Adapt the clip polygon.
+ if ( ! aViewState.Clip.is())
+ {
+ // Cancel out the later multiplication with the view state
+ // transformation.
+ aViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(aWindowRange)));
+ }
+ else
+ {
+ // Have to compute the intersection of the given clipping polygon in
+ // the view state and the local clip rectangle.
+
+ // Clip the view state clipping polygon against the local clip rectangle.
+ const ::basegfx::B2DPolyPolygon aClipPolygon (
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(
+ aViewState.Clip));
+ const ::basegfx::B2DPolyPolygon aClippedClipPolygon (
+ ::basegfx::utils::clipPolyPolygonOnRange(
+ aClipPolygon,
+ aWindowRange,
+ true, /* bInside */
+ false /* bStroke */));
+
+ aViewState.Clip = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ aClippedClipPolygon);
+ }
+
+ return aViewState;
+}
+
+awt::Point PresenterCanvas::GetOffset (const Reference<awt::XWindow>& rxBaseWindow)
+{
+ mbOffsetUpdatePending = false;
+ if (mxWindow.is() && rxBaseWindow.is())
+ {
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ VclPtr<vcl::Window> pSharedWindow = VCLUnoHelper::GetWindow(rxBaseWindow);
+ if (pWindow && pSharedWindow)
+ {
+ ::tools::Rectangle aBox = pWindow->GetWindowExtentsRelative(pSharedWindow);
+
+ // Calculate offset of this canvas with respect to the shared
+ // canvas.
+ return awt::Point(aBox.Left(), aBox.Top());
+ }
+ }
+
+ return awt::Point(0, 0);
+}
+
+::basegfx::B2DRectangle PresenterCanvas::GetClipRectangle (
+ const css::geometry::AffineMatrix2D& rViewTransform,
+ const awt::Point& rOffset)
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(mxWindow);
+ if (!pWindow)
+ return ::basegfx::B2DRectangle();
+
+ VclPtr<vcl::Window> pSharedWindow = VCLUnoHelper::GetWindow(mxSharedWindow);
+ if (!pSharedWindow)
+ return ::basegfx::B2DRectangle();
+
+ // Get the bounding box of the window and create a range in the
+ // coordinate system of the child window.
+ // Use the window extents.
+ ::tools::Rectangle aLocalClip = pWindow->GetWindowExtentsRelative(pSharedWindow);
+
+ // The local clip rectangle is used to clip the view state clipping
+ // polygon.
+ ::basegfx::B2DRectangle aWindowRectangle (
+ aLocalClip.Left() - rOffset.X,
+ aLocalClip.Top() - rOffset.Y,
+ aLocalClip.Right() - rOffset.X + 1,
+ aLocalClip.Bottom() - rOffset.Y + 1);
+
+ // Calculate the inverted view state transformation to cancel out a
+ // later transformation of the local clip polygon with the view state
+ // transformation.
+ ::basegfx::B2DHomMatrix aInvertedViewStateTransformation;
+ ::basegfx::unotools::homMatrixFromAffineMatrix(
+ aInvertedViewStateTransformation,
+ rViewTransform);
+ if (aInvertedViewStateTransformation.invert())
+ {
+ // Cancel out the later multiplication with the view state
+ // transformation.
+ aWindowRectangle.transform(aInvertedViewStateTransformation);
+ }
+
+ return aWindowRectangle;
+}
+
+Reference<rendering::XPolyPolygon2D> PresenterCanvas::UpdateSpriteClip (
+ const Reference<rendering::XPolyPolygon2D>& rxOriginalClip,
+ const geometry::RealPoint2D& rLocation)
+{
+ // Check used resources and just return the original clip when not
+ // every one of them is available.
+ if ( ! mxWindow.is())
+ return rxOriginalClip;
+
+ Reference<rendering::XGraphicDevice> xDevice (mxSharedCanvas->getDevice());
+ if ( ! xDevice.is())
+ return rxOriginalClip;
+
+ // Determine the bounds of the clip rectangle (the window border) in the
+ // coordinate system of the sprite.
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ const double nMinX (-rLocation.X);
+ const double nMinY (-rLocation.Y);
+ const double nMaxX (aWindowBox.Width-rLocation.X);
+ const double nMaxY (aWindowBox.Height-rLocation.Y);
+
+ // Create a clip polygon.
+ Reference<rendering::XPolyPolygon2D> xPolygon;
+ if (rxOriginalClip.is())
+ {
+ // Combine the original clip with the window clip.
+ const ::basegfx::B2DPolyPolygon aOriginalClip (
+ ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rxOriginalClip));
+ ::basegfx::B2DRectangle aWindowRange (nMinX, nMinY, nMaxX, nMaxY);
+ const ::basegfx::B2DPolyPolygon aClippedClipPolygon (
+ ::basegfx::utils::clipPolyPolygonOnRange(
+ aOriginalClip,
+ aWindowRange,
+ true, /* bInside */
+ false /* bStroke */));
+ xPolygon = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ xDevice,
+ aClippedClipPolygon);
+ }
+ else
+ {
+ // Create a new clip polygon from the window clip rectangle.
+ Sequence<Sequence<geometry::RealPoint2D> > aPoints
+ {
+ {
+ { nMinX,nMinY },
+ { nMaxX,nMinY },
+ { nMaxX,nMaxY },
+ { nMinX,nMaxY }
+ }
+ };
+ Reference<rendering::XLinePolyPolygon2D> xLinePolygon(
+ xDevice->createCompatibleLinePolyPolygon(aPoints));
+ if (xLinePolygon.is())
+ xLinePolygon->setClosed(0, true);
+ xPolygon = xLinePolygon;
+ }
+
+ return xPolygon;
+}
+
+void PresenterCanvas::ThrowIfDisposed()
+{
+ if (m_bDisposed || ! mxSharedCanvas.is())
+ {
+ throw lang::DisposedException ("PresenterCanvas object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== PresenterCustomSprite =================================================
+
+PresenterCustomSprite::PresenterCustomSprite (
+ const rtl::Reference<PresenterCanvas>& rpCanvas,
+ const Reference<rendering::XCustomSprite>& rxSprite,
+ const Reference<awt::XWindow>& rxBaseWindow)
+ : mpCanvas(rpCanvas),
+ mxSprite(rxSprite),
+ mxBaseWindow(rxBaseWindow),
+ maPosition(0,0)
+{
+}
+
+void PresenterCustomSprite::disposing(std::unique_lock<std::mutex>&)
+{
+ Reference<XComponent> xComponent (mxSprite, UNO_QUERY);
+ mxSprite = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ mpCanvas.clear();
+}
+
+//----- XSprite ---------------------------------------------------------------
+
+void SAL_CALL PresenterCustomSprite::setAlpha (const double nAlpha)
+{
+ ThrowIfDisposed();
+ mxSprite->setAlpha(nAlpha);
+}
+
+void SAL_CALL PresenterCustomSprite::move (
+ const geometry::RealPoint2D& rNewPos,
+ const rendering::ViewState& rViewState,
+ const rendering::RenderState& rRenderState)
+{
+ ThrowIfDisposed();
+ maPosition = rNewPos;
+ mxSprite->move(
+ rNewPos,
+ mpCanvas->MergeViewState(rViewState, mpCanvas->GetOffset(mxBaseWindow)),
+ rRenderState);
+ // Clip sprite against window bounds. This call is necessary because
+ // sprite clipping is done in the coordinate system of the sprite.
+ // Therefore, after each change of the sprites location the window
+ // bounds have to be transformed into the sprites coordinate system.
+ clip(nullptr);
+}
+
+void SAL_CALL PresenterCustomSprite::transform (const geometry::AffineMatrix2D& rTransformation)
+{
+ ThrowIfDisposed();
+ mxSprite->transform(rTransformation);
+}
+
+void SAL_CALL PresenterCustomSprite::clip (const Reference<rendering::XPolyPolygon2D>& rxClip)
+{
+ ThrowIfDisposed();
+ // The clip region is expected in the coordinate system of the sprite.
+ // UpdateSpriteClip() integrates the window bounds, transformed into the
+ // sprites coordinate system, with the given clip.
+ mxSprite->clip(mpCanvas->UpdateSpriteClip(rxClip, maPosition));
+}
+
+void SAL_CALL PresenterCustomSprite::setPriority (const double nPriority)
+{
+ ThrowIfDisposed();
+ mxSprite->setPriority(nPriority);
+}
+
+void SAL_CALL PresenterCustomSprite::show()
+{
+ ThrowIfDisposed();
+ mxSprite->show();
+}
+
+void SAL_CALL PresenterCustomSprite::hide()
+{
+ ThrowIfDisposed();
+ mxSprite->hide();
+}
+
+//----- XCustomSprite ---------------------------------------------------------
+
+Reference<rendering::XCanvas> PresenterCustomSprite::getContentCanvas()
+{
+ ThrowIfDisposed();
+ return mxSprite->getContentCanvas();
+}
+
+void PresenterCustomSprite::ThrowIfDisposed()
+{
+ if (m_bDisposed || ! mxSprite.is())
+ {
+ throw lang::DisposedException ("PresenterCustomSprite object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterCanvas.hxx b/sd/source/ui/presenter/PresenterCanvas.hxx
new file mode 100644
index 000000000..da2f51a79
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterCanvas.hxx
@@ -0,0 +1,320 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <basegfx/range/b2drectangle.hxx>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <com/sun/star/rendering/XBitmap.hpp>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace sd::presenter { class CanvasUpdateRequester; }
+namespace com::sun::star::awt { class XWindow; }
+namespace com::sun::star::geometry { struct AffineMatrix2D; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::rendering::XSpriteCanvas,
+ css::rendering::XBitmap,
+ css::awt::XWindowListener
+> PresenterCanvasInterfaceBase;
+
+/** Wrapper around a shared canvas that forwards most of its methods to the
+ shared canvas. Most notable differences are:
+ 1. The transformation of the ViewState of forwarded calls is modified by adding
+ an offset.
+ 2. The clip polygon of the ViewState of forwarded calls is intersected
+ with a clip rectangle that can be set via SetClip().
+ 3. Calls to updateScreen() are collected. One call to the updateScreen()
+ method of the shared canvas is made asynchronously.
+
+ The canvas can use different canvases for sharing and for sprite
+ construction. This allows the shared canvas to be a canvas of sprite itself.
+*/
+class PresenterCanvas
+ : public PresenterCanvasInterfaceBase
+{
+public:
+ /** This constructor is used when a PresenterCanvas object is created
+ directly, typically by the PresenterCanvasFactory.
+ @param rxUpdateCanvas
+ This canvas is used to call updateScreen() at and to create
+ sprites. In the typical case this canvas is identical to the
+ rxSharedCanvas argument.
+ @param rxUpdateWindow
+ The window that belongs to the canvas given by the
+ rxUpdateCanvas argument.
+ @param rxSharedCanvas
+ The canvas that is wrapped by the new instance of this class.
+ Typically this is a regular XSpriteCanvas and then is identical
+ to the one given by the rxUpdateCanvas argument. It may be the
+ canvas of a sprite which does not support the XSpriteCanvas
+ interface. In that case the canvas that created the sprite can
+ be given as rxUpdateCanvas argument to allow to create further
+ sprites and to have proper calls to updateScreen().
+ @param rxSharedWindow
+ The window that belongs to the canvas given by the
+ rxSharedCanvas argument.
+ @param rxWindow
+ The window that is represented by the new PresenterCanvas
+ object. It is expected to be a direct descendant of
+ rxSharedWindow. Its position inside rxSharedWindow defines the
+ offset of the canvas implemented by the new PresenterCanvas
+ object and rxSharedCanvas.
+ */
+ PresenterCanvas (
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxUpdateWindow,
+ const css::uno::Reference<css::rendering::XCanvas>& rxSharedCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxSharedWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxWindow);
+ virtual ~PresenterCanvas() override;
+ PresenterCanvas(const PresenterCanvas&) = delete;
+ PresenterCanvas& operator=(const PresenterCanvas&) = delete;
+
+ virtual void disposing(std::unique_lock<std::mutex>&) override;
+
+ css::awt::Point GetOffset (const css::uno::Reference<css::awt::XWindow>& rxBaseWindow);
+
+ /** Merge the given view state with the view state that translates the
+ (virtual) child canvas to the shared canvas.
+ */
+ css::rendering::ViewState MergeViewState (
+ const css::rendering::ViewState& rViewState,
+ const css::awt::Point& raOffset);
+
+ /** Called by custom sprites to update their clip polygon so that they
+ are clipped at the borders of the canvas. This method has to be
+ called after each change of the sprite location so that the bounds
+ of the canvas can be transformed into the coordinate system of the
+ sprite.
+ */
+ css::uno::Reference<css::rendering::XPolyPolygon2D> UpdateSpriteClip (
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& rxOriginalClip,
+ const css::geometry::RealPoint2D& rLocation);
+
+ // XCanvas
+
+ virtual void SAL_CALL clear() override;
+
+ virtual void SAL_CALL drawPoint (
+ const css::geometry::RealPoint2D& aPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual void SAL_CALL drawLine (
+ const css::geometry::RealPoint2D& aStartPoint,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual void SAL_CALL drawBezier (
+ const css::geometry::RealBezierSegment2D& aBezierSegment,
+ const css::geometry::RealPoint2D& aEndPoint,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL drawPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL strokePolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ strokeTexturedPolyPolygon (
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& aTextures,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ strokeTextureMappedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& aTextures,
+ const css::uno::Reference<css::geometry::XMapping2D>& xMapping,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XPolyPolygon2D> SAL_CALL
+ queryStrokeShapes(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::rendering::StrokeAttributes& aStrokeAttributes) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillTexturedPolyPolygon(
+ const css::uno::Reference<css::rendering::XPolyPolygon2D>& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence<css::rendering::Texture>& xTextures) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ fillTextureMappedPolyPolygon(
+ const css::uno::Reference< css::rendering::XPolyPolygon2D >& xPolyPolygon,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ const css::uno::Sequence< css::rendering::Texture >& xTextures,
+ const css::uno::Reference< css::geometry::XMapping2D >& xMapping) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvasFont> SAL_CALL
+ createFont(
+ const css::rendering::FontRequest& aFontRequest,
+ const css::uno::Sequence< css::beans::PropertyValue >& aExtraFontProperties,
+ const css::geometry::Matrix2D& aFontMatrix) override;
+
+ virtual css::uno::Sequence<css::rendering::FontInfo> SAL_CALL
+ queryAvailableFonts(
+ const css::rendering::FontInfo& aFilter,
+ const css::uno::Sequence< css::beans::PropertyValue >& aFontProperties) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawText(
+ const css::rendering::StringContext& aText,
+ const css::uno::Reference< css::rendering::XCanvasFont >& xFont,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState,
+ ::sal_Int8 nTextDirection) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawTextLayout(
+ const css::uno::Reference< css::rendering::XTextLayout >& xLayoutetText,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawBitmap(
+ const css::uno::Reference< css::rendering::XBitmap >& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XCachedPrimitive> SAL_CALL
+ drawBitmapModulated(
+ const css::uno::Reference< css::rendering::XBitmap>& xBitmap,
+ const css::rendering::ViewState& aViewState,
+ const css::rendering::RenderState& aRenderState) override;
+
+ virtual css::uno::Reference<css::rendering::XGraphicDevice> SAL_CALL
+ getDevice() override;
+
+ // XSpriteCanvas
+
+ css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL
+ createSpriteFromAnimation (
+ const css::uno::Reference< css::rendering::XAnimation >& animation) override;
+
+ css::uno::Reference< css::rendering::XAnimatedSprite > SAL_CALL
+ createSpriteFromBitmaps (
+ const css::uno::Sequence<
+ css::uno::Reference< css::rendering::XBitmap > >& animationBitmaps,
+ ::sal_Int8 interpolationMode) override;
+
+ css::uno::Reference< css::rendering::XCustomSprite > SAL_CALL
+ createCustomSprite (
+ const css::geometry::RealSize2D& spriteSize) override;
+
+ css::uno::Reference< css::rendering::XSprite > SAL_CALL
+ createClonedSprite (
+ const css::uno::Reference< css::rendering::XSprite >& original) override;
+
+ sal_Bool SAL_CALL updateScreen (sal_Bool bUpdateAll) override;
+
+ // XEventListener
+
+ virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) override;
+
+ // XWindowListener
+
+ virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) override;
+
+ virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) override;
+
+ virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) override;
+
+ // XBitmap
+
+ virtual css::geometry::IntegerSize2D SAL_CALL getSize() override;
+
+ virtual sal_Bool SAL_CALL hasAlpha() override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL getScaledBitmap(
+ const css::geometry::RealSize2D& rNewSize,
+ sal_Bool bFast) override;
+
+private:
+ css::uno::Reference<css::rendering::XSpriteCanvas> mxUpdateCanvas;
+ css::uno::Reference<css::awt::XWindow> mxUpdateWindow;
+ css::uno::Reference<css::rendering::XCanvas> mxSharedCanvas;
+ css::uno::Reference<css::awt::XWindow> mxSharedWindow;
+
+ /** The window for which a canvas is emulated.
+ */
+ css::uno::Reference<css::awt::XWindow> mxWindow;
+
+ /** Offset of the emulated canvas with respect to the shared canvas.
+ */
+ css::awt::Point maOffset;
+
+ /** The UpdateRequester is used by updateScreen() to schedule
+ updateScreen() calls at the shared canvas.
+ */
+ std::shared_ptr<CanvasUpdateRequester> m_pUpdateRequester;
+
+ /** When this flag is true (it is set to true after every call to
+ updateScreen()) then the next call to MergeViewState updates the
+ maOffset member. A possible optimization would set this flag only
+ to true when one of the windows between mxWindow and mxSharedWindow
+ changes its position.
+ */
+ bool mbOffsetUpdatePending;
+
+ ::basegfx::B2DRectangle GetClipRectangle (
+ const css::geometry::AffineMatrix2D& rViewTransform,
+ const css::awt::Point& rOffset);
+
+ css::rendering::ViewState MergeViewState (const css::rendering::ViewState& rViewState);
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterHelper.cxx b/sd/source/ui/presenter/PresenterHelper.cxx
new file mode 100644
index 000000000..a93113a75
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterHelper.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstddef>
+
+#include "PresenterHelper.hxx"
+#include "PresenterCanvas.hxx"
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+#include <vcl/wrkwin.hxx>
+
+
+#include <bitmaps.hlst>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== PresenterHelper =======================================================
+
+PresenterHelper::PresenterHelper (
+ const Reference<XComponentContext>& rxContext)
+ : mxComponentContext(rxContext)
+{
+}
+
+PresenterHelper::~PresenterHelper()
+{
+}
+
+//----- XInitialize -----------------------------------------------------------
+
+void SAL_CALL PresenterHelper::initialize (const Sequence<Any>&) {}
+
+//----- XPaneHelper ----------------------------------------------------
+
+Reference<awt::XWindow> SAL_CALL PresenterHelper::createWindow (
+ const Reference<awt::XWindow>& rxParentWindow,
+ sal_Bool bCreateSystemChildWindow,
+ sal_Bool bInitiallyVisible,
+ sal_Bool bEnableChildTransparentMode,
+ sal_Bool bEnableParentClip)
+{
+ VclPtr<vcl::Window> pParentWindow(VCLUnoHelper::GetWindow(rxParentWindow));
+
+ // Create a new window.
+ VclPtr<vcl::Window> pWindow;
+ if (bCreateSystemChildWindow)
+ {
+ pWindow = VclPtr<WorkWindow>::Create(pParentWindow, WB_SYSTEMCHILDWINDOW);
+ }
+ else
+ {
+ pWindow = VclPtr<vcl::Window>::Create(pParentWindow);
+ }
+ Reference<awt::XWindow> xWindow (pWindow->GetComponentInterface(), UNO_QUERY);
+
+ if (bEnableChildTransparentMode)
+ {
+ // Make the frame window transparent and make the parent able to
+ // draw behind it.
+ if (pParentWindow)
+ pParentWindow->EnableChildTransparentMode();
+ }
+
+ pWindow->Show(bInitiallyVisible);
+
+ pWindow->SetMapMode(MapMode(MapUnit::MapPixel));
+ pWindow->SetBackground();
+ if ( ! bEnableParentClip)
+ {
+ pWindow->SetParentClipMode(ParentClipMode::NoClip);
+ pWindow->SetPaintTransparent(true);
+ }
+ else
+ {
+ pWindow->SetParentClipMode(ParentClipMode::Clip);
+ pWindow->SetPaintTransparent(false);
+ }
+
+ return xWindow;
+}
+
+Reference<rendering::XCanvas> SAL_CALL PresenterHelper::createSharedCanvas (
+ const Reference<rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const Reference<awt::XWindow>& rxUpdateWindow,
+ const Reference<rendering::XCanvas>& rxSharedCanvas,
+ const Reference<awt::XWindow>& rxSharedWindow,
+ const Reference<awt::XWindow>& rxWindow)
+{
+ if ( ! rxSharedCanvas.is()
+ || ! rxSharedWindow.is()
+ || ! rxWindow.is())
+ {
+ throw RuntimeException("illegal argument", static_cast<XWeak*>(this));
+ }
+
+ if (rxWindow == rxSharedWindow)
+ return rxSharedCanvas;
+ else
+ return new PresenterCanvas(
+ rxUpdateCanvas,
+ rxUpdateWindow,
+ rxSharedCanvas,
+ rxSharedWindow,
+ rxWindow);
+}
+
+Reference<rendering::XCanvas> SAL_CALL PresenterHelper::createCanvas (
+ const Reference<awt::XWindow>& rxWindow,
+ sal_Int16,
+ const OUString& rsOptionalCanvasServiceName)
+{
+ // No shared window is given or an explicit canvas service name is
+ // specified. Create a new canvas.
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (!pWindow)
+ throw RuntimeException();
+
+ Sequence<Any> aArg{ // common: first any is VCL pointer to window (for VCL canvas)
+ Any(reinterpret_cast<sal_Int64>(pWindow.get())),
+ Any(css::awt::Rectangle()),
+ Any(false),
+ Any(rxWindow)
+ };
+
+ Reference<lang::XMultiServiceFactory> xFactory (
+ mxComponentContext->getServiceManager(), UNO_QUERY_THROW);
+ return Reference<rendering::XCanvas>(
+ xFactory->createInstanceWithArguments(
+ !rsOptionalCanvasServiceName.isEmpty()
+ ? rsOptionalCanvasServiceName
+ : OUString("com.sun.star.rendering.Canvas.VCL"),
+ aArg),
+ UNO_QUERY);
+}
+
+void SAL_CALL PresenterHelper::toTop (
+ const Reference<awt::XWindow>& rxWindow)
+{
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow)
+ {
+ pWindow->ToTop();
+ pWindow->SetZOrder(nullptr, ZOrderFlags::Last);
+ }
+}
+
+namespace {
+
+struct IdMapEntry {
+ char const * sid;
+ rtl::OUStringConstExpr bmpid;
+};
+
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterHelper::loadBitmap (
+ const OUString& id,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ if ( ! rxCanvas.is())
+ return nullptr;
+
+ static IdMapEntry const map[] = {
+ { "bitmaps/Background.png", BMP_PRESENTERSCREEN_BACKGROUND },
+ { "bitmaps/Animation.png",
+ BMP_PRESENTERSCREEN_ANIMATION },
+ { "bitmaps/Transition.png",
+ BMP_PRESENTERSCREEN_TRANSITION },
+ { "bitmaps/BorderActiveBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM },
+ { "bitmaps/BorderActiveBottomCallout.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_CALLOUT },
+ { "bitmaps/BorderActiveBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_LEFT },
+ { "bitmaps/BorderActiveBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_BOTTOM_RIGHT },
+ { "bitmaps/BorderActiveLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_LEFT },
+ { "bitmaps/BorderActiveRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_RIGHT },
+ { "bitmaps/BorderActiveTop.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP },
+ { "bitmaps/BorderActiveTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP_LEFT },
+ { "bitmaps/BorderActiveTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_ACTIVE_TOP_RIGHT },
+ { "bitmaps/BorderBottom.png", BMP_PRESENTERSCREEN_BORDER_BOTTOM },
+ { "bitmaps/BorderBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_BOTTOM_LEFT },
+ { "bitmaps/BorderBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_BOTTOM_RIGHT },
+ { "bitmaps/BorderCurrentSlideBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM },
+ { "bitmaps/BorderCurrentSlideBottomLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM_LEFT },
+ { "bitmaps/BorderCurrentSlideBottomRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_BOTTOM_RIGHT },
+ { "bitmaps/BorderCurrentSlideLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_LEFT },
+ { "bitmaps/BorderCurrentSlideRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_RIGHT },
+ { "bitmaps/BorderCurrentSlideTop.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP },
+ { "bitmaps/BorderCurrentSlideTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP_LEFT },
+ { "bitmaps/BorderCurrentSlideTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_CURRENT_SLIDE_TOP_RIGHT },
+ { "bitmaps/BorderLeft.png", BMP_PRESENTERSCREEN_BORDER_LEFT },
+ { "bitmaps/BorderRight.png", BMP_PRESENTERSCREEN_BORDER_RIGHT },
+ { "bitmaps/BorderToolbarBottom.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_BOTTOM },
+ { "bitmaps/BorderToolbarLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_LEFT },
+ { "bitmaps/BorderToolbarRight.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_RIGHT },
+ { "bitmaps/BorderToolbarTop.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP },
+ { "bitmaps/BorderToolbarTopLeft.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP_LEFT },
+ { "bitmaps/BorderToolbarTopRight.png",
+ BMP_PRESENTERSCREEN_BORDER_TOOLBAR_TOP_RIGHT },
+ { "bitmaps/BorderTop.png", BMP_PRESENTERSCREEN_BORDER_TOP },
+ { "bitmaps/BorderTopLeft.png", BMP_PRESENTERSCREEN_BORDER_TOP_LEFT },
+ { "bitmaps/BorderTopRight.png", BMP_PRESENTERSCREEN_BORDER_TOP_RIGHT },
+ { "bitmaps/ButtonEffectNextDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_DISABLED },
+ { "bitmaps/ButtonEffectNextMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_MOUSE_OVER },
+ { "bitmaps/ButtonEffectNextNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_NORMAL },
+ { "bitmaps/ButtonEffectNextSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_EFFECT_NEXT_SELECTED },
+ { "bitmaps/ButtonFrameCenterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_CENTER_MOUSE_OVER },
+ { "bitmaps/ButtonFrameCenterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_CENTER_NORMAL },
+ { "bitmaps/ButtonFrameLeftMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_LEFT_MOUSE_OVER },
+ { "bitmaps/ButtonFrameLeftNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_LEFT_NORMAL },
+ { "bitmaps/ButtonFrameRightMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_RIGHT_MOUSE_OVER },
+ { "bitmaps/ButtonFrameRightNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_FRAME_RIGHT_NORMAL },
+ { "bitmaps/ButtonHelpDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_DISABLED },
+ { "bitmaps/ButtonHelpMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_MOUSE_OVER },
+ { "bitmaps/ButtonHelpNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_NORMAL },
+ { "bitmaps/ButtonHelpSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_HELP_SELECTED },
+ { "bitmaps/ButtonExitPresenterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_EXIT_PRESENTER_MOUSE_OVER },
+ { "bitmaps/ButtonExitPresenterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_EXIT_PRESENTER_NORMAL },
+ { "bitmaps/ButtonMinusDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_DISABLED },
+ { "bitmaps/ButtonMinusMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_MOUSE_OVER },
+ { "bitmaps/ButtonMinusNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_NORMAL },
+ { "bitmaps/ButtonMinusSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_MINUS_SELECTED },
+ { "bitmaps/ButtonNotesDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_DISABLED },
+ { "bitmaps/ButtonNotesMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_MOUSE_OVER },
+ { "bitmaps/ButtonNotesNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_NORMAL },
+ { "bitmaps/ButtonNotesSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_NOTES_SELECTED },
+ { "bitmaps/ButtonPlusDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_DISABLED },
+ { "bitmaps/ButtonPlusMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_MOUSE_OVER },
+ { "bitmaps/ButtonPlusNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_NORMAL },
+ { "bitmaps/ButtonPlusSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_PLUS_SELECTED },
+ { "bitmaps/ButtonSlideNextDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_DISABLED },
+ { "bitmaps/ButtonSlideNextMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_MOUSE_OVER },
+ { "bitmaps/ButtonSlideNextNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_NEXT_NORMAL },
+ { "bitmaps/ButtonSlidePreviousDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_DISABLED },
+ { "bitmaps/ButtonSlidePreviousMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_MOUSE_OVER },
+ { "bitmaps/ButtonSlidePreviousNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_NORMAL },
+ { "bitmaps/ButtonSlidePreviousSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_PREVIOUS_SELECTED },
+ { "bitmaps/ButtonSlideSorterDisabled.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_DISABLED },
+ { "bitmaps/ButtonSlideSorterMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_MOUSE_OVER },
+ { "bitmaps/ButtonSlideSorterNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_NORMAL },
+ { "bitmaps/ButtonSlideSorterSelected.png",
+ BMP_PRESENTERSCREEN_BUTTON_SLIDE_SORTER_SELECTED },
+ { "bitmaps/ButtonSwitchMonitorMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_SWITCH_MONITOR_MOUSE_OVER },
+ { "bitmaps/ButtonSwitchMonitorNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_SWITCH_MONITOR_NORMAL },
+ { "bitmaps/ButtonRestartTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESTART_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonRestartTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESTART_TIMER_NORMAL },
+ { "bitmaps/ButtonPauseTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_PAUSE_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonPauseTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_PAUSE_TIMER_NORMAL },
+ { "bitmaps/ButtonResumeTimerMouseOver.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESUME_TIMER_MOUSE_OVER },
+ { "bitmaps/ButtonResumeTimerNormal.png",
+ BMP_PRESENTERSCREEN_BUTTON_RESUME_TIMER_NORMAL },
+ { "bitmaps/LabelMouseOverCenter.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_CENTER },
+ { "bitmaps/LabelMouseOverLeft.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_LEFT },
+ { "bitmaps/LabelMouseOverRight.png",
+ BMP_PRESENTERSCREEN_LABEL_MOUSE_OVER_RIGHT },
+ { "bitmaps/ScrollbarArrowDownDisabled.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_DISABLED },
+ { "bitmaps/ScrollbarArrowDownMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_MOUSE_OVER },
+ { "bitmaps/ScrollbarArrowDownNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_NORMAL },
+ { "bitmaps/ScrollbarArrowDownSelected.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_DOWN_SELECTED },
+ { "bitmaps/ScrollbarArrowUpDisabled.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_DISABLED },
+ { "bitmaps/ScrollbarArrowUpMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_MOUSE_OVER },
+ { "bitmaps/ScrollbarArrowUpNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_NORMAL },
+ { "bitmaps/ScrollbarArrowUpSelected.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_ARROW_UP_SELECTED },
+ { "bitmaps/ScrollbarPagerMiddleMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_PAGER_MIDDLE_MOUSE_OVER },
+ { "bitmaps/ScrollbarPagerMiddleNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_PAGER_MIDDLE_NORMAL },
+ { "bitmaps/ScrollbarThumbBottomMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_BOTTOM_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbBottomNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_BOTTOM_NORMAL },
+ { "bitmaps/ScrollbarThumbMiddleMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_MIDDLE_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbMiddleNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_MIDDLE_NORMAL },
+ { "bitmaps/ScrollbarThumbTopMouseOver.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_TOP_MOUSE_OVER },
+ { "bitmaps/ScrollbarThumbTopNormal.png",
+ BMP_PRESENTERSCREEN_SCROLLBAR_THUMB_TOP_NORMAL },
+ { "bitmaps/ViewBackground.png", BMP_PRESENTERSCREEN_VIEW_BACKGROUND },
+ { "bitmaps/Separator.png",
+ BMP_PRESENTERSCREEN_SEPARATOR }
+ };
+ OUString bmpid;
+ for (std::size_t i = 0; i != SAL_N_ELEMENTS(map); ++i) {
+ if (id.equalsAscii(map[i].sid)) {
+ bmpid = map[i].bmpid;
+ break;
+ }
+ }
+ if (bmpid.isEmpty()) {
+ return nullptr;
+ }
+
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ const cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+
+ if (pCanvas)
+ {
+ BitmapEx aBitmapEx(bmpid);
+ cppcanvas::BitmapSharedPtr xBitmap(
+ cppcanvas::VCLFactory::createBitmap(pCanvas,
+ aBitmapEx));
+ if (!xBitmap)
+ return nullptr;
+ return xBitmap->getUNOBitmap();
+ }
+
+ return nullptr;
+}
+
+void SAL_CALL PresenterHelper::captureMouse (
+ const Reference<awt::XWindow>& rxWindow)
+{
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ // Capture the mouse (if not already done.)
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow && ! pWindow->IsMouseCaptured())
+ {
+ pWindow->CaptureMouse();
+ }
+}
+
+void SAL_CALL PresenterHelper::releaseMouse (const Reference<awt::XWindow>& rxWindow)
+{
+ ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
+
+ // Release the mouse (if not already done.)
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow(rxWindow);
+ if (pWindow && pWindow->IsMouseCaptured())
+ {
+ pWindow->ReleaseMouse();
+ }
+}
+
+awt::Rectangle PresenterHelper::getWindowExtentsRelative (
+ const Reference<awt::XWindow>& rxChildWindow,
+ const Reference<awt::XWindow>& rxParentWindow)
+{
+ VclPtr<vcl::Window> pChildWindow = VCLUnoHelper::GetWindow(rxChildWindow);
+ VclPtr<vcl::Window> pParentWindow = VCLUnoHelper::GetWindow(rxParentWindow);
+ if (pChildWindow && pParentWindow)
+ {
+ ::tools::Rectangle aBox (pChildWindow->GetWindowExtentsRelative(pParentWindow));
+ return awt::Rectangle(aBox.Left(),aBox.Top(),aBox.GetWidth(),aBox.GetHeight());
+ }
+ else
+ return awt::Rectangle();
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterHelper_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterHelper(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterHelper.hxx b/sd/source/ui/presenter/PresenterHelper.hxx
new file mode 100644
index 000000000..cee7e39fb
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterHelper.hxx
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/XPresenterHelper.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::lang::XInitialization,
+ css::drawing::XPresenterHelper
+> PresenterHelperInterfaceBase;
+
+/** Implementation of the XPresenterHelper interface: functionality that can
+ not be implemented in an extension.
+*/
+class PresenterHelper final
+ : public PresenterHelperInterfaceBase
+{
+public:
+ explicit PresenterHelper (const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ virtual ~PresenterHelper() override;
+ PresenterHelper(const PresenterHelper&) = delete;
+ PresenterHelper& operator=(const PresenterHelper&) = delete;
+
+ // XInitialize
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XPresenterHelper
+
+ virtual css::uno::Reference<css::awt::XWindow> SAL_CALL createWindow (
+ const css::uno::Reference<css::awt::XWindow>& rxParentWindow,
+ sal_Bool bCreateSystemChildWindow,
+ sal_Bool bInitiallyVisible,
+ sal_Bool bEnableChildTransparentMode,
+ sal_Bool bEnableParentClip) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvas> SAL_CALL createSharedCanvas (
+ const css::uno::Reference<css::rendering::XSpriteCanvas>& rxUpdateCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxUpdateWindow,
+ const css::uno::Reference<css::rendering::XCanvas>& rxSharedCanvas,
+ const css::uno::Reference<css::awt::XWindow>& rxSharedWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::uno::Reference<css::rendering::XCanvas> SAL_CALL createCanvas (
+ const css::uno::Reference<css::awt::XWindow>& rxWindow,
+ sal_Int16 nRequestedCanvasFeatures,
+ const OUString& rsOptionalCanvasServiceName) override;
+
+ virtual void SAL_CALL toTop (
+ const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL loadBitmap (
+ const OUString& rsURL,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual void SAL_CALL captureMouse (const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual void SAL_CALL releaseMouse (const css::uno::Reference<css::awt::XWindow>& rxWindow) override;
+
+ virtual css::awt::Rectangle SAL_CALL getWindowExtentsRelative (
+ const css::uno::Reference<css::awt::XWindow>& rxChildWindow,
+ const css::uno::Reference<css::awt::XWindow>& rxParentWindow) override;
+
+private:
+ css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterPreviewCache.cxx b/sd/source/ui/presenter/PresenterPreviewCache.cxx
new file mode 100644
index 000000000..fd29cdbfa
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterPreviewCache.cxx
@@ -0,0 +1,360 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterPreviewCache.hxx"
+
+#include <cache/SlsPageCache.hxx>
+#include <cache/SlsCacheContext.hxx>
+#include <vcl/bitmapex.hxx>
+#include <sdpage.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <osl/diagnose.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::sd::slidesorter::cache;
+
+namespace sd::presenter {
+
+class PresenterPreviewCache::PresenterCacheContext : public CacheContext
+{
+public:
+ PresenterCacheContext();
+
+ void SetDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument);
+ void SetVisibleSlideRange (
+ const sal_Int32 nFirstVisibleSlideIndex,
+ const sal_Int32 nLastVisibleSlideIndex);
+ const SdrPage* GetPage (const sal_Int32 nSlideIndex) const;
+ void AddPreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
+ void RemovePreviewCreationNotifyListener (const Reference<drawing::XSlidePreviewCacheListener>& rxListener);
+
+ // CacheContext
+ virtual void NotifyPreviewCreation (CacheKey aKey) override;
+ virtual bool IsIdle() override;
+ virtual bool IsVisible (CacheKey aKey) override;
+ virtual const SdrPage* GetPage (CacheKey aKey) override;
+ virtual std::shared_ptr<std::vector<CacheKey> > GetEntryList (bool bVisible) override;
+ virtual sal_Int32 GetPriority (CacheKey aKey) override;
+ virtual css::uno::Reference<css::uno::XInterface> GetModel() override;
+
+private:
+ Reference<container::XIndexAccess> mxSlides;
+ Reference<XInterface> mxDocument;
+ sal_Int32 mnFirstVisibleSlideIndex;
+ sal_Int32 mnLastVisibleSlideIndex;
+ typedef ::std::vector<css::uno::Reference<css::drawing::XSlidePreviewCacheListener> > ListenerContainer;
+ ListenerContainer maListeners;
+
+ void CallListeners (const sal_Int32 nSlideIndex);
+};
+
+//===== PresenterPreviewCache =================================================
+
+PresenterPreviewCache::PresenterPreviewCache ()
+ : maPreviewSize(Size(200,200)),
+ mpCacheContext(std::make_shared<PresenterCacheContext>()),
+ mpCache(std::make_shared<PageCache>(maPreviewSize, Bitmap::HasFastScale(), mpCacheContext))
+{
+}
+
+PresenterPreviewCache::~PresenterPreviewCache()
+{
+}
+
+//----- XInitialize -----------------------------------------------------------
+
+void SAL_CALL PresenterPreviewCache::initialize (const Sequence<Any>& rArguments)
+{
+ if (rArguments.hasElements())
+ throw RuntimeException();
+}
+
+//----- XSlidePreviewCache ----------------------------------------------------
+
+void SAL_CALL PresenterPreviewCache::setDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ mpCacheContext->SetDocumentSlides(rxSlides, rxDocument);
+}
+
+void SAL_CALL PresenterPreviewCache::setVisibleRange (
+ sal_Int32 nFirstVisibleSlideIndex,
+ sal_Int32 nLastVisibleSlideIndex)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ mpCacheContext->SetVisibleSlideRange (nFirstVisibleSlideIndex, nLastVisibleSlideIndex);
+}
+
+void SAL_CALL PresenterPreviewCache::setPreviewSize (
+ const css::geometry::IntegerSize2D& rSize)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+
+ maPreviewSize = Size(rSize.Width, rSize.Height);
+ mpCache->ChangeSize(maPreviewSize, Bitmap::HasFastScale());
+}
+
+Reference<rendering::XBitmap> SAL_CALL PresenterPreviewCache::getSlidePreview (
+ sal_Int32 nSlideIndex,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCacheContext != nullptr);
+
+ cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+
+ const SdrPage* pPage = mpCacheContext->GetPage(nSlideIndex);
+ if (pPage == nullptr)
+ throw RuntimeException();
+
+ const BitmapEx aPreview (mpCache->GetPreviewBitmap(pPage,true));
+ if (aPreview.IsEmpty())
+ return nullptr;
+ else
+ return cppcanvas::VCLFactory::createBitmap(
+ pCanvas,
+ aPreview)->getUNOBitmap();
+}
+
+void SAL_CALL PresenterPreviewCache::addPreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ if (m_bDisposed)
+ return;
+ if (rxListener.is())
+ mpCacheContext->AddPreviewCreationNotifyListener(rxListener);
+}
+
+void SAL_CALL PresenterPreviewCache::removePreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ ThrowIfDisposed();
+ mpCacheContext->RemovePreviewCreationNotifyListener(rxListener);
+}
+
+void SAL_CALL PresenterPreviewCache::pause()
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+ mpCache->Pause();
+}
+
+void SAL_CALL PresenterPreviewCache::resume()
+{
+ ThrowIfDisposed();
+ OSL_ASSERT(mpCache != nullptr);
+ mpCache->Resume();
+}
+
+void PresenterPreviewCache::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("PresenterPreviewCache object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== PresenterPreviewCache::PresenterCacheContext ==========================
+
+PresenterPreviewCache::PresenterCacheContext::PresenterCacheContext()
+ : mnFirstVisibleSlideIndex(-1),
+ mnLastVisibleSlideIndex(-1)
+{
+}
+
+void PresenterPreviewCache::PresenterCacheContext::SetDocumentSlides (
+ const Reference<container::XIndexAccess>& rxSlides,
+ const Reference<XInterface>& rxDocument)
+{
+ mxSlides = rxSlides;
+ mxDocument = rxDocument;
+ mnFirstVisibleSlideIndex = -1;
+ mnLastVisibleSlideIndex = -1;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::SetVisibleSlideRange (
+ const sal_Int32 nFirstVisibleSlideIndex,
+ const sal_Int32 nLastVisibleSlideIndex)
+{
+ if (nFirstVisibleSlideIndex > nLastVisibleSlideIndex || nFirstVisibleSlideIndex<0)
+ {
+ mnFirstVisibleSlideIndex = -1;
+ mnLastVisibleSlideIndex = -1;
+ }
+ else
+ {
+ mnFirstVisibleSlideIndex = nFirstVisibleSlideIndex;
+ mnLastVisibleSlideIndex = nLastVisibleSlideIndex;
+ }
+ if (mxSlides.is() && mnLastVisibleSlideIndex >= mxSlides->getCount())
+ mnLastVisibleSlideIndex = mxSlides->getCount() - 1;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::AddPreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ maListeners.push_back(rxListener);
+}
+
+void PresenterPreviewCache::PresenterCacheContext::RemovePreviewCreationNotifyListener (
+ const Reference<drawing::XSlidePreviewCacheListener>& rxListener)
+{
+ auto iListener = std::find(maListeners.begin(), maListeners.end(), rxListener);
+ if (iListener != maListeners.end())
+ maListeners.erase(iListener);
+}
+
+//----- CacheContext ----------------------------------------------------------
+
+void PresenterPreviewCache::PresenterCacheContext::NotifyPreviewCreation (
+ CacheKey aKey)
+{
+ if ( ! mxSlides.is())
+ return;
+ const sal_Int32 nCount(mxSlides->getCount());
+ for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ CallListeners(nIndex);
+}
+
+bool PresenterPreviewCache::PresenterCacheContext::IsIdle()
+{
+ return true;
+}
+
+bool PresenterPreviewCache::PresenterCacheContext::IsVisible (CacheKey aKey)
+{
+ if (mnFirstVisibleSlideIndex < 0)
+ return false;
+ for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
+ {
+ const SdrPage* pPage = GetPage(nIndex);
+ if (pPage == aKey)
+ return true;
+ }
+ return false;
+}
+
+const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (CacheKey aKey)
+{
+ return aKey;
+}
+
+std::shared_ptr<std::vector<CacheKey> >
+ PresenterPreviewCache::PresenterCacheContext::GetEntryList (bool bVisible)
+{
+ auto pKeys = std::make_shared<std::vector<CacheKey>>();
+
+ if ( ! mxSlides.is())
+ return pKeys;
+
+ const sal_Int32 nFirstIndex (bVisible ? mnFirstVisibleSlideIndex : 0);
+ const sal_Int32 nLastIndex (bVisible ? mnLastVisibleSlideIndex : mxSlides->getCount()-1);
+
+ if (nFirstIndex < 0)
+ return pKeys;
+
+ for (sal_Int32 nIndex=nFirstIndex; nIndex<=nLastIndex; ++nIndex)
+ {
+ pKeys->push_back(GetPage(nIndex));
+ }
+
+ return pKeys;
+}
+
+sal_Int32 PresenterPreviewCache::PresenterCacheContext::GetPriority (CacheKey aKey)
+{
+ if ( ! mxSlides.is())
+ return 0;
+
+ const sal_Int32 nCount (mxSlides->getCount());
+
+ for (sal_Int32 nIndex=mnFirstVisibleSlideIndex; nIndex<=mnLastVisibleSlideIndex; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ return -nCount-1+nIndex;
+
+ for (sal_Int32 nIndex=0; nIndex<=nCount; ++nIndex)
+ if (aKey == GetPage(nIndex))
+ return nIndex;
+
+ return 0;
+}
+
+Reference<XInterface> PresenterPreviewCache::PresenterCacheContext::GetModel()
+{
+ return mxDocument;
+}
+
+const SdrPage* PresenterPreviewCache::PresenterCacheContext::GetPage (
+ const sal_Int32 nSlideIndex) const
+{
+ if ( ! mxSlides.is())
+ return nullptr;
+ if (nSlideIndex < 0 || nSlideIndex >= mxSlides->getCount())
+ return nullptr;
+
+ Reference<drawing::XDrawPage> xSlide (mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
+ const SdPage* pPage = SdPage::getImplementation(xSlide);
+ return pPage;
+}
+
+void PresenterPreviewCache::PresenterCacheContext::CallListeners (
+ const sal_Int32 nIndex)
+{
+ ListenerContainer aListeners (maListeners);
+ for (const auto& rxListener : aListeners)
+ {
+ try
+ {
+ rxListener->notifyPreviewCreation(nIndex);
+ }
+ catch (lang::DisposedException&)
+ {
+ RemovePreviewCreationNotifyListener(rxListener);
+ }
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterPreviewCache_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterPreviewCache);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterPreviewCache.hxx b/sd/source/ui/presenter/PresenterPreviewCache.hxx
new file mode 100644
index 000000000..4f8c52280
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterPreviewCache.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/XSlidePreviewCache.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <tools/gen.hxx>
+#include <comphelper/compbase.hxx>
+#include <memory>
+
+namespace sd::slidesorter::cache { class PageCache; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper<
+ css::lang::XInitialization,
+ css::drawing::XSlidePreviewCache
+> PresenterPreviewCacheInterfaceBase;
+
+/** Uno API wrapper around the slide preview cache.
+*/
+class PresenterPreviewCache final
+ : public PresenterPreviewCacheInterfaceBase
+{
+public:
+ PresenterPreviewCache ();
+ virtual ~PresenterPreviewCache() override;
+ PresenterPreviewCache(const PresenterPreviewCache&) = delete;
+ PresenterPreviewCache& operator=(const PresenterPreviewCache&) = delete;
+
+ // XInitialize
+
+ /** Accepts no arguments. All values that are necessary to set up a
+ preview cache can be provided via methods.
+ */
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ // XSlidePreviewCache
+
+ virtual void SAL_CALL setDocumentSlides (
+ const css::uno::Reference<css::container::XIndexAccess>& rxSlides,
+ const css::uno::Reference<css::uno::XInterface>& rxDocument) override;
+
+ virtual void SAL_CALL setVisibleRange (
+ sal_Int32 nFirstVisibleSlideIndex,
+ sal_Int32 nLastVisibleSlideIndex) override;
+
+ virtual void SAL_CALL setPreviewSize (
+ const css::geometry::IntegerSize2D& rSize) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL
+ getSlidePreview (
+ sal_Int32 nSlideIndex,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual void SAL_CALL addPreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener) override;
+
+ virtual void SAL_CALL removePreviewCreationNotifyListener (
+ const css::uno::Reference<css::drawing::XSlidePreviewCacheListener>& rxListener) override;
+
+ virtual void SAL_CALL pause() override;
+
+ virtual void SAL_CALL resume() override;
+
+private:
+ class PresenterCacheContext;
+ Size maPreviewSize;
+ std::shared_ptr<PresenterCacheContext> mpCacheContext;
+ std::shared_ptr<sd::slidesorter::cache::PageCache> mpCache;
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterTextView.cxx b/sd/source/ui/presenter/PresenterTextView.cxx
new file mode 100644
index 000000000..affa21b03
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterTextView.cxx
@@ -0,0 +1,466 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "PresenterTextView.hxx"
+
+#include <i18nlangtag/mslangid.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <svl/itempool.hxx>
+#include <unotools/lingucfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+
+constexpr OUStringLiteral gsTextPropertyName(u"Text");
+constexpr OUStringLiteral gsBitmapPropertyName(u"Bitmap");
+constexpr OUStringLiteral gsSizePropertyName(u"Size");
+constexpr OUStringLiteral gsBackgroundColorPropertyName(u"BackgroundColor");
+constexpr OUStringLiteral gsTextColorPropertyName(u"TextColor");
+constexpr OUStringLiteral gsFontDescriptorPropertyName(u"FontDescriptor");
+constexpr OUStringLiteral gsTopPropertyName(u"Top");
+constexpr OUStringLiteral gsTopRelativePropertyName(u"RelativeTop");
+constexpr OUStringLiteral gsTotalHeightPropertyName(u"TotalHeight");
+
+namespace sd::presenter {
+
+// PresenterTextView::Implementation
+class PresenterTextView::Implementation
+{
+public:
+ Implementation();
+ ~Implementation();
+
+ void SetCanvas (const cppcanvas::CanvasSharedPtr& rCanvas);
+ void SetSize (const Size aSize);
+ void SetBackgroundColor (const Color aColor);
+ void SetTextColor (const Color aColor);
+ void SetFontDescriptor (const awt::FontDescriptor& rFontDescriptor);
+ sal_Int32 GetTop() const { return mnTop;}
+ void SetTop (const sal_Int32 nTop);
+ void SetText (const OUString& Text);
+ sal_Int32 ParseDistance (const OUString& rsDistance) const;
+ Reference<rendering::XBitmap> const & GetBitmap();
+ sal_Int32 GetTotalHeight();
+
+private:
+ Reference<rendering::XBitmap> mxBitmap;
+ cppcanvas::CanvasSharedPtr mpCanvas;
+ VclPtr<VirtualDevice> mpOutputDevice;
+ std::unique_ptr<EditEngine> mpEditEngine;
+ rtl::Reference<SfxItemPool> mpEditEngineItemPool;
+ Size maSize;
+ OUString msText;
+ sal_Int32 mnTop;
+ sal_Int32 mnTotalHeight;
+
+ void CheckTop();
+};
+
+// PresenterTextView
+PresenterTextView::PresenterTextView ()
+ : mpImplementation(new Implementation())
+{
+}
+
+PresenterTextView::~PresenterTextView()
+{
+}
+
+void SAL_CALL PresenterTextView::disposing()
+{
+ mpImplementation.reset();
+}
+
+// XInitialization
+void SAL_CALL PresenterTextView::initialize (const Sequence<Any>& rArguments)
+{
+ ThrowIfDisposed();
+
+ if (rArguments.getLength() != 1)
+ {
+ throw RuntimeException("PresenterTextView: invalid number of arguments",
+ static_cast<XWeak*>(this));
+ }
+
+ Reference<rendering::XCanvas> xCanvas (rArguments[0], UNO_QUERY_THROW);
+ mpImplementation->SetCanvas(
+ cppcanvas::VCLFactory::createCanvas(xCanvas));
+}
+
+Any PresenterTextView::GetPropertyValue (const OUString& rsPropertyName)
+{
+ ThrowIfDisposed();
+
+ if (rsPropertyName == gsBitmapPropertyName)
+ {
+ return Any(mpImplementation->GetBitmap());
+ }
+ else if (rsPropertyName == gsTopPropertyName)
+ {
+ return Any(mpImplementation->GetTop());
+ }
+ else if (rsPropertyName == gsTotalHeightPropertyName)
+ {
+ return Any(mpImplementation->GetTotalHeight());
+ }
+
+ return Any();
+}
+
+Any PresenterTextView::SetPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rValue)
+{
+ ThrowIfDisposed();
+
+ Any aOldValue;
+ if (rsPropertyName == gsTextPropertyName)
+ {
+ OUString sText;
+ if (rValue >>= sText)
+ mpImplementation->SetText(sText);
+ }
+ else if (rsPropertyName == gsSizePropertyName)
+ {
+ awt::Size aSize;
+ if (rValue >>= aSize)
+ mpImplementation->SetSize(Size(aSize.Width,aSize.Height));
+ }
+ else if (rsPropertyName == gsBackgroundColorPropertyName)
+ {
+ ::Color aColor;
+ if (rValue >>= aColor)
+ mpImplementation->SetBackgroundColor(aColor);
+ }
+ else if (rsPropertyName == gsTextColorPropertyName)
+ {
+ ::Color aColor;
+ if (rValue >>= aColor)
+ mpImplementation->SetTextColor(aColor);
+ }
+ else if (rsPropertyName == gsFontDescriptorPropertyName)
+ {
+ awt::FontDescriptor aFontDescriptor;
+ if (rValue >>= aFontDescriptor)
+ mpImplementation->SetFontDescriptor(aFontDescriptor);
+ }
+ else if (rsPropertyName == gsTopPropertyName)
+ {
+ sal_Int32 nTop = 0;
+ if (rValue >>= nTop)
+ mpImplementation->SetTop(nTop);
+ }
+ else if (rsPropertyName == gsTopRelativePropertyName)
+ {
+ OUString sDistance;
+ if (rValue >>= sDistance)
+ mpImplementation->SetTop(
+ mpImplementation->GetTop()
+ + mpImplementation->ParseDistance(sDistance));
+ }
+ return aOldValue;
+}
+
+void PresenterTextView::ThrowIfDisposed()
+{
+ if (PresenterTextViewInterfaceBase::rBHelper.bDisposed
+ || PresenterTextViewInterfaceBase::rBHelper.bInDispose || mpImplementation == nullptr)
+ {
+ throw lang::DisposedException ("PresenterTextView object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+// PresenterTextView::Implementation
+PresenterTextView::Implementation::Implementation()
+ : mpOutputDevice(VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)),
+ mpEditEngineItemPool(EditEngine::CreatePool()),
+ maSize(100,100),
+ mnTop(0),
+ mnTotalHeight(-1)
+{
+ mpOutputDevice->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ // set fonts to be used
+ SvtLinguOptions aOpt;
+ SvtLinguConfig().GetOptions( aOpt );
+
+ struct FontDta {
+ LanguageType nFallbackLang;
+ LanguageType nLang;
+ DefaultFontType nFontType;
+ sal_uInt16 nFontInfoId;
+ } aTable[3] =
+ {
+ // info to get western font to be used
+ { LANGUAGE_ENGLISH_US, LANGUAGE_NONE,
+ DefaultFontType::SERIF, EE_CHAR_FONTINFO },
+ // info to get CJK font to be used
+ { LANGUAGE_JAPANESE, LANGUAGE_NONE,
+ DefaultFontType::CJK_TEXT, EE_CHAR_FONTINFO_CJK },
+ // info to get CTL font to be used
+ { LANGUAGE_ARABIC_SAUDI_ARABIA, LANGUAGE_NONE,
+ DefaultFontType::CTL_TEXT, EE_CHAR_FONTINFO_CTL }
+ };
+ aTable[0].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage, css::i18n::ScriptType::LATIN);
+ aTable[1].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage_CJK, css::i18n::ScriptType::ASIAN);
+ aTable[2].nLang = MsLangId::resolveSystemLanguageByScriptType(aOpt.nDefaultLanguage_CTL, css::i18n::ScriptType::COMPLEX);
+
+ for (const FontDta & rFntDta : aTable)
+ {
+ LanguageType nLang = (LANGUAGE_NONE == rFntDta.nLang) ?
+ rFntDta.nFallbackLang : rFntDta.nLang;
+ vcl::Font aFont = OutputDevice::GetDefaultFont(
+ rFntDta.nFontType, nLang, GetDefaultFontFlags::OnlyOne);
+ mpEditEngineItemPool->SetPoolDefaultItem(
+ SvxFontItem(
+ aFont.GetFamilyType(),
+ aFont.GetFamilyName(),
+ aFont.GetStyleName(),
+ aFont.GetPitch(),
+ aFont.GetCharSet(),
+ rFntDta.nFontInfoId));
+ }
+
+ mpEditEngine.reset( new EditEngine (mpEditEngineItemPool.get()) );
+
+ mpEditEngine->EnableUndo (true);
+ mpEditEngine->SetDefTab (sal_uInt16(
+ Application::GetDefaultDevice()->GetTextWidth("XXXX")));
+
+ mpEditEngine->SetControlWord(
+ EEControlBits(mpEditEngine->GetControlWord() | EEControlBits::AUTOINDENTING) &
+ EEControlBits(~EEControlBits::UNDOATTRIBS) &
+ EEControlBits(~EEControlBits::PASTESPECIAL) );
+
+ mpEditEngine->SetWordDelimiters (" .=+-*/(){}[];\"");
+ mpEditEngine->SetRefMapMode(MapMode(MapUnit::MapPixel));
+ mpEditEngine->SetPaperSize (Size(800, 0));
+ mpEditEngine->EraseVirtualDevice();
+ mpEditEngine->ClearModifyFlag();
+}
+
+PresenterTextView::Implementation::~Implementation()
+{
+ mpEditEngine.reset();
+ mpEditEngineItemPool.clear();
+ mpOutputDevice.disposeAndClear();
+}
+
+void PresenterTextView::Implementation::SetCanvas (const cppcanvas::CanvasSharedPtr& rpCanvas)
+{
+ mpCanvas = rpCanvas;
+ mxBitmap = nullptr;
+}
+
+void PresenterTextView::Implementation::SetSize (const Size aSize)
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ maSize = aSize;
+ mpEditEngine->SetPaperSize(maSize);
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+}
+
+void PresenterTextView::Implementation::SetBackgroundColor (const Color aColor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+ mpEditEngine->SetBackgroundColor(aColor);
+ mpEditEngine->EnableAutoColor(false);
+ mpEditEngine->ForceAutoColor(false);
+}
+
+void PresenterTextView::Implementation::SetTextColor (const Color aColor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+ mpEditEngineItemPool->SetPoolDefaultItem(SvxColorItem(aColor, EE_CHAR_COLOR));
+}
+
+void PresenterTextView::Implementation::SetFontDescriptor (
+ const awt::FontDescriptor& rFontDescriptor)
+{
+ mxBitmap = nullptr;
+
+ DBG_ASSERT(mpEditEngineItemPool!=nullptr, "EditEngineItemPool missing");
+
+ const sal_Int32 nFontHeight = rFontDescriptor.Height;
+
+ SvxFontHeightItem aFontHeight(
+ Application::GetDefaultDevice()->LogicToPixel(
+ Size(0, nFontHeight), MapMode (MapUnit::MapPoint)).Height(),
+ 100,
+ EE_CHAR_FONTHEIGHT);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+ aFontHeight.SetWhich (EE_CHAR_FONTHEIGHT_CJK);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+ aFontHeight.SetWhich (EE_CHAR_FONTHEIGHT_CTL);
+ mpEditEngineItemPool->SetPoolDefaultItem( aFontHeight);
+
+ SvxFontItem aSvxFontItem (EE_CHAR_FONTINFO);
+ aSvxFontItem.SetFamilyName( rFontDescriptor.Name );
+ mpEditEngineItemPool->SetPoolDefaultItem(aSvxFontItem);
+
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+
+ CheckTop();
+ mnTotalHeight = -1;
+}
+
+void PresenterTextView::Implementation::SetTop (const sal_Int32 nTop)
+{
+ if (nTop == mnTop)
+ return;
+
+ mnTop = nTop;
+ mxBitmap = nullptr;
+ CheckTop();
+}
+
+void PresenterTextView::Implementation::SetText (const OUString& rText)
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ msText = rText;
+ mpEditEngine->SetPaperSize(maSize);
+ mnTotalHeight = -1;
+ mxBitmap = nullptr;
+}
+
+sal_Int32 PresenterTextView::Implementation::ParseDistance (const OUString& rsDistance) const
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+ sal_Int32 nDistance (0);
+ if (rsDistance.endsWith("px"))
+ {
+ nDistance = o3tl::toInt32(rsDistance.subView(0,rsDistance.getLength()-2));
+ }
+ else if (rsDistance.endsWith("l"))
+ {
+ const sal_Int32 nLines (o3tl::toInt32(rsDistance.subView(0,rsDistance.getLength()-1)));
+ // Take the height of the first line as the height of every line.
+ const sal_uInt32 nFirstLineHeight (mpEditEngine->GetLineHeight(0));
+ nDistance = nFirstLineHeight * nLines;
+ }
+
+ return nDistance;
+}
+
+Reference<rendering::XBitmap> const & PresenterTextView::Implementation::GetBitmap()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if ( ! mxBitmap.is())
+ {
+ mpOutputDevice.disposeAndClear();
+ mpOutputDevice = VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(),
+ DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
+ mpOutputDevice->SetMapMode(MapMode(MapUnit::MapPixel));
+ mpOutputDevice->SetOutputSizePixel(maSize);
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetBackground(Wallpaper());
+ mpOutputDevice->Erase();
+
+ MapMode aMapMode (mpOutputDevice->GetMapMode());
+ aMapMode.SetOrigin(Point(0,0));
+ mpOutputDevice->SetMapMode(aMapMode);
+ const ::tools::Rectangle aWindowBox (Point(0,0), maSize);
+ mpOutputDevice->DrawRect(aWindowBox);
+
+ mpEditEngine->Clear();
+ mpEditEngine->SetText(msText);
+ mpEditEngine->SetPaperSize(maSize);
+
+ mpEditEngine->Draw(*mpOutputDevice, aWindowBox, Point(0,mnTop));
+
+ const BitmapEx aBitmap (mpOutputDevice->GetBitmapEx(Point(0,0), maSize));
+ mxBitmap = cppcanvas::VCLFactory::createBitmap(
+ mpCanvas,
+ aBitmap
+ )->getUNOBitmap();
+ }
+ return mxBitmap;
+}
+
+sal_Int32 PresenterTextView::Implementation::GetTotalHeight()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if (mnTotalHeight < 0)
+ {
+ if ( ! mxBitmap.is())
+ GetBitmap();
+ mnTotalHeight = mpEditEngine->GetTextHeight();
+ }
+ return mnTotalHeight;
+}
+
+void PresenterTextView::Implementation::CheckTop()
+{
+ DBG_ASSERT(mpEditEngine!=nullptr, "EditEngine missing");
+
+ if (mpEditEngine!=nullptr && mnTotalHeight < 0)
+ mnTotalHeight = mpEditEngine->GetTextHeight();
+ if (mpEditEngine!=nullptr && mnTop >= mnTotalHeight)
+ mnTop = mnTotalHeight - mpEditEngine->GetLineHeight(0);
+
+ if (mnTotalHeight < maSize.Height())
+ mnTop = 0;
+
+ if (mnTotalHeight - mnTop < maSize.Height())
+ mnTop = mnTotalHeight - maSize.Height();
+
+ if (mnTop < 0)
+ mnTop = 0;
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_PresenterTextView_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::PresenterTextView);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/PresenterTextView.hxx b/sd/source/ui/presenter/PresenterTextView.hxx
new file mode 100644
index 000000000..28b68aaa5
--- /dev/null
+++ b/sd/source/ui/presenter/PresenterTextView.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/PropertySet.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <memory>
+
+namespace sd::presenter {
+
+typedef ::cppu::ImplInheritanceHelper <
+ tools::PropertySet,
+ css::lang::XInitialization
+> PresenterTextViewInterfaceBase;
+
+/** Render text into bitmaps. An edit engine is used to render the text.
+ This service is used by the presenter screen to render the notes view.
+*/
+class PresenterTextView
+ : public PresenterTextViewInterfaceBase
+{
+public:
+ PresenterTextView ();
+ virtual ~PresenterTextView() override;
+ PresenterTextView(const PresenterTextView&) = delete;
+ PresenterTextView& operator=(const PresenterTextView&) = delete;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual css::uno::Any GetPropertyValue (
+ const OUString& rsPropertyName) override;
+ virtual css::uno::Any SetPropertyValue (
+ const OUString& rsPropertyName,
+ const css::uno::Any& rValue) override;
+
+private:
+ class Implementation;
+ std::unique_ptr<Implementation> mpImplementation;
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/SlideRenderer.cxx b/sd/source/ui/presenter/SlideRenderer.cxx
new file mode 100644
index 000000000..1b57b195a
--- /dev/null
+++ b/sd/source/ui/presenter/SlideRenderer.cxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SlideRenderer.hxx"
+#include <sdpage.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/svapp.hxx>
+#include <cppcanvas/vclfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd::presenter {
+
+//===== SlideRenderer ==========================================================
+
+SlideRenderer::SlideRenderer ()
+{
+}
+
+SlideRenderer::~SlideRenderer()
+{
+}
+
+//----- XInitialization -------------------------------------------------------
+
+void SAL_CALL SlideRenderer::initialize (const Sequence<Any>& rArguments)
+{
+ ThrowIfDisposed();
+
+ if (rArguments.hasElements())
+ {
+ throw RuntimeException("SlideRenderer: invalid number of arguments",
+ static_cast<XWeak*>(this));
+ }
+}
+
+OUString SlideRenderer::getImplementationName()
+{
+ return "com.sun.star.comp.Draw.SlideRenderer";
+}
+
+sal_Bool SlideRenderer::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SlideRenderer::getSupportedServiceNames()
+{
+ return {"com.sun.star.drawing.SlideRenderer"};
+}
+
+//----- XSlideRenderer --------------------------------------------------------
+
+Reference<awt::XBitmap> SlideRenderer::createPreview (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor)
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ return VCLUnoHelper::CreateBitmap(
+ CreatePreview(rxSlide, rMaximalSize, nSuperSampleFactor));
+}
+
+Reference<rendering::XBitmap> SlideRenderer::createPreviewForCanvas (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor,
+ const Reference<rendering::XCanvas>& rxCanvas)
+{
+ ThrowIfDisposed();
+ SolarMutexGuard aGuard;
+
+ cppcanvas::CanvasSharedPtr pCanvas (
+ cppcanvas::VCLFactory::createCanvas(rxCanvas));
+ if (pCanvas)
+ return cppcanvas::VCLFactory::createBitmap(
+ pCanvas,
+ CreatePreview(rxSlide, rMaximalSize, nSuperSampleFactor))->getUNOBitmap();
+ else
+ return nullptr;
+}
+
+awt::Size SAL_CALL SlideRenderer::calculatePreviewSize (
+ double nSlideAspectRatio,
+ const awt::Size& rMaximalSize)
+{
+ if (rMaximalSize.Width <= 0
+ || rMaximalSize.Height <= 0
+ || nSlideAspectRatio <= 0)
+ {
+ return awt::Size(0,0);
+ }
+
+ const double nWindowAspectRatio (double(rMaximalSize.Width) / double(rMaximalSize.Height));
+ if (nSlideAspectRatio < nWindowAspectRatio)
+ return awt::Size(
+ sal::static_int_cast<sal_Int32>(rMaximalSize.Height * nSlideAspectRatio),
+ rMaximalSize.Height);
+ else
+ return awt::Size(
+ rMaximalSize.Width,
+ sal::static_int_cast<sal_Int32>(rMaximalSize.Width / nSlideAspectRatio));
+}
+
+BitmapEx SlideRenderer::CreatePreview (
+ const Reference<drawing::XDrawPage>& rxSlide,
+ const awt::Size& rMaximalSize,
+ sal_Int16 nSuperSampleFactor)
+{
+ const SdPage* pPage = SdPage::getImplementation(rxSlide);
+ if (pPage == nullptr)
+ throw lang::IllegalArgumentException("SlideRenderer::createPreview() called with invalid slide",
+ static_cast<XWeak*>(this),
+ 0);
+
+ // Determine the size of the current slide and its aspect ratio.
+ Size aPageSize = pPage->GetSize();
+ if (aPageSize.Height() <= 0)
+ throw lang::IllegalArgumentException("SlideRenderer::createPreview() called with invalid size",
+ static_cast<XWeak*>(this),
+ 1);
+
+ // Compare with the aspect ratio of the window (which rMaximalSize
+ // assumed to be) and calculate the size of the preview so that it
+ // a) will have the aspect ratio of the page and
+ // b) will be as large as possible.
+ awt::Size aPreviewSize (calculatePreviewSize(
+ double(aPageSize.Width()) / double(aPageSize.Height()),
+ rMaximalSize));
+ if (aPreviewSize.Width <= 0 || aPreviewSize.Height <= 0)
+ return BitmapEx();
+
+ // Make sure that the super sample factor has a sane value.
+ sal_Int16 nFactor (nSuperSampleFactor);
+ if (nFactor < 1)
+ nFactor = 1;
+ else if (nFactor > 10)
+ nFactor = 10;
+
+ // Create the preview. When the super sample factor n is greater than 1
+ // then a preview is created in size (n*width, n*height) and then scaled
+ // down to (width, height). This is a poor mans antialiasing for the
+ // time being. When we have true antialiasing support this workaround
+ // can be removed.
+ const Image aPreview = maPreviewRenderer.RenderPage (
+ pPage,
+ Size(aPreviewSize.Width*nFactor, aPreviewSize.Height*nFactor),
+ true);
+ if (nFactor == 1)
+ return aPreview.GetBitmapEx();
+ else
+ {
+ BitmapEx aScaledPreview = aPreview.GetBitmapEx();
+ aScaledPreview.Scale(
+ Size(aPreviewSize.Width,aPreviewSize.Height),
+ BmpScaleFlag::BestQuality);
+ return aScaledPreview;
+ }
+}
+
+void SlideRenderer::ThrowIfDisposed()
+{
+ if (m_bDisposed)
+ {
+ throw lang::DisposedException ("SlideRenderer object has already been disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+} // end of namespace ::sd::presenter
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_Draw_SlideRenderer_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sd::presenter::SlideRenderer);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/ui/presenter/SlideRenderer.hxx b/sd/source/ui/presenter/SlideRenderer.hxx
new file mode 100644
index 000000000..d39434421
--- /dev/null
+++ b/sd/source/ui/presenter/SlideRenderer.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <PreviewRenderer.hxx>
+#include <com/sun/star/drawing/XSlideRenderer.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/compbase.hxx>
+
+namespace com::sun::star::drawing { class XDrawPage; }
+
+namespace sd::presenter {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::drawing::XSlideRenderer,
+ css::lang::XInitialization,
+ css::lang::XServiceInfo
+> SlideRendererInterfaceBase;
+
+/** Render single slides into bitmaps.
+*/
+class SlideRenderer final
+ : public SlideRendererInterfaceBase
+{
+public:
+ SlideRenderer ();
+ virtual ~SlideRenderer() override;
+ SlideRenderer(const SlideRenderer&) = delete;
+ SlideRenderer& operator=(const SlideRenderer&) = delete;
+
+ // XInitialization
+
+ virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XSlideRenderer
+
+ virtual css::uno::Reference<css::awt::XBitmap> SAL_CALL createPreview (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor) override;
+
+ virtual css::uno::Reference<css::rendering::XBitmap> SAL_CALL createPreviewForCanvas (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas) override;
+
+ virtual css::awt::Size SAL_CALL calculatePreviewSize (
+ double nSlideAspectRatio,
+ const css::awt::Size& rMaximumPreviewPixelSize) override;
+
+private:
+ PreviewRenderer maPreviewRenderer;
+
+ /// @throws css::uno::RuntimeException
+ BitmapEx CreatePreview (
+ const css::uno::Reference<css::drawing::XDrawPage>& rxSlide,
+ const css::awt::Size& rMaximumPreviewPixelSize,
+ sal_Int16 nSuperSampleFactor);
+
+ /** @throws css::lang::DisposedException when the object has already been
+ disposed.
+ */
+ void ThrowIfDisposed();
+};
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */