diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sd/source/ui/presenter | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
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.cxx | 131 | ||||
-rw-r--r-- | sd/source/ui/presenter/CanvasUpdateRequester.hxx | 71 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterCanvas.cxx | 789 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterCanvas.hxx | 325 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterHelper.cxx | 454 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterHelper.hxx | 98 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterPreviewCache.cxx | 363 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterPreviewCache.hxx | 102 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterTextView.cxx | 470 | ||||
-rw-r--r-- | sd/source/ui/presenter/PresenterTextView.hxx | 74 | ||||
-rw-r--r-- | sd/source/ui/presenter/SlideRenderer.cxx | 207 | ||||
-rw-r--r-- | sd/source/ui/presenter/SlideRenderer.hxx | 100 |
12 files changed, 3184 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..97da675fb --- /dev/null +++ b/sd/source/ui/presenter/CanvasUpdateRequester.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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_CANVASUPDATEREQUESTER_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_CANVASUPDATEREQUESTER_HXX + +#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 + +#endif + +/* 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..f1f2271a1 --- /dev/null +++ b/sd/source/ui/presenter/PresenterCanvas.cxx @@ -0,0 +1,789 @@ +/* -*- 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 <cppuhelper/basemutex.hxx> +#include <cppuhelper/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 ::cppu::WeakComponentImplHelper < + css::rendering::XCustomSprite + > PresenterCustomSpriteInterfaceBase; + +class PresenterCustomSprite + : protected ::cppu::BaseMutex, + 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 SAL_CALL disposing() 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) + : PresenterCanvasInterfaceBase(m_aMutex), + mxUpdateCanvas(rxUpdateCanvas), + mxUpdateWindow(rxUpdateWindow), + mxSharedCanvas(rxSharedCanvas), + mxSharedWindow(rxSharedWindow), + mxWindow(rxWindow), + maOffset(), + mbOffsetUpdatePending(true) +{ + if (mxWindow.is()) + mxWindow->addWindowListener(this); + + if (mxUpdateCanvas.is()) + { + m_pUpdateRequester = CanvasUpdateRequester::Instance(mxUpdateCanvas); + } +} + +PresenterCanvas::~PresenterCanvas() +{ +} + +void SAL_CALL PresenterCanvas::disposing() +{ + if (mxWindow.is()) + mxWindow->removeWindowListener(this); +} + +//----- 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 (1); + aPoints[0] = Sequence<geometry::RealPoint2D>(4); + aPoints[0][0] = geometry::RealPoint2D(nMinX,nMinY); + aPoints[0][1] = geometry::RealPoint2D(nMaxX,nMinY); + aPoints[0][2] = geometry::RealPoint2D(nMaxX,nMaxY); + aPoints[0][3] = geometry::RealPoint2D(nMinX,nMaxY); + Reference<rendering::XLinePolyPolygon2D> xLinePolygon( + xDevice->createCompatibleLinePolyPolygon(aPoints)); + if (xLinePolygon.is()) + xLinePolygon->setClosed(0, true); + xPolygon = xLinePolygon; + } + + return xPolygon; +} + +void PresenterCanvas::ThrowIfDisposed() +{ + if (rBHelper.bDisposed || rBHelper.bInDispose || ! 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) + : PresenterCustomSpriteInterfaceBase(m_aMutex), + mpCanvas(rpCanvas), + mxSprite(rxSprite), + mxBaseWindow(rxBaseWindow), + maPosition(0,0) +{ +} + +void SAL_CALL PresenterCustomSprite::disposing() +{ + 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 (rBHelper.bDisposed || rBHelper.bInDispose || ! 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..3aaa7ff24 --- /dev/null +++ b/sd/source/ui/presenter/PresenterCanvas.hxx @@ -0,0 +1,325 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERCANVAS_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERCANVAS_HXX + +#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 <cppuhelper/basemutex.hxx> +#include <cppuhelper/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 ::cppu::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 + : private ::cppu::BaseMutex, + 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 SAL_CALL disposing() 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 + +#endif + +/* 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..4fce3397e --- /dev/null +++ b/sd/source/ui/presenter/PresenterHelper.cxx @@ -0,0 +1,454 @@ +/* -*- 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) + : PresenterHelperInterfaceBase(m_aMutex), + 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.get() != nullptr) + 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(4); + + // common: first any is VCL pointer to window (for VCL canvas) + aArg[0] <<= reinterpret_cast<sal_Int64>(pWindow.get()); + aArg[1] <<= css::awt::Rectangle(); + aArg[2] <<= false; + aArg[3] <<= 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; + const char* 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/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/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 } + }; + OUString bmpid; + for (std::size_t i = 0; i != SAL_N_ELEMENTS(map); ++i) { + if (id.equalsAscii(map[i].sid)) { + bmpid = OUString::createFromAscii(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.get() != nullptr) + { + BitmapEx aBitmapEx(bmpid); + cppcanvas::BitmapSharedPtr xBitmap( + cppcanvas::VCLFactory::createBitmap(pCanvas, + aBitmapEx)); + if (xBitmap.get() == nullptr) + 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..2dbc74014 --- /dev/null +++ b/sd/source/ui/presenter/PresenterHelper.hxx @@ -0,0 +1,98 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERHELPER_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERHELPER_HXX + +#include <com/sun/star/drawing/XPresenterHelper.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace sd::presenter { + +typedef ::cppu::WeakComponentImplHelper< + css::lang::XInitialization, + css::drawing::XPresenterHelper +> PresenterHelperInterfaceBase; + +/** Implementation of the XPresenterHelper interface: functionality that can + not be implemented in an extension. +*/ +class PresenterHelper + : private ::cppu::BaseMutex, + 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 + +#endif + +/* 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..c420cf5f9 --- /dev/null +++ b/sd/source/ui/presenter/PresenterPreviewCache.cxx @@ -0,0 +1,363 @@ +/* -*- 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> + +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 () + : PresenterPreviewCacheInterfaceBase(m_aMutex), + 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 (rBHelper.bDisposed || rBHelper.bInDispose) + 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 (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ("PresenterPreviewCache object has already been disposed", + static_cast<uno::XWeak*>(this)); + } +} + +//===== PresenterPreviewCache::PresenterCacheContext ========================== + +PresenterPreviewCache::PresenterCacheContext::PresenterCacheContext() + : mxSlides(), + mxDocument(), + mnFirstVisibleSlideIndex(-1), + mnLastVisibleSlideIndex(-1), + maListeners() +{ +} + +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 dynamic_cast<const SdrPage*>(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..2a10a8d26 --- /dev/null +++ b/sd/source/ui/presenter/PresenterPreviewCache.hxx @@ -0,0 +1,102 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERPREVIEWCACHE_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERPREVIEWCACHE_HXX + +#include <com/sun/star/drawing/XSlidePreviewCache.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <tools/gen.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <memory> + +namespace sd::slidesorter::cache { class PageCache; } + +namespace sd::presenter { + +typedef ::cppu::WeakComponentImplHelper< + css::lang::XInitialization, + css::drawing::XSlidePreviewCache +> PresenterPreviewCacheInterfaceBase; + +/** Uno API wrapper around the slide preview cache. +*/ +class PresenterPreviewCache + : private ::cppu::BaseMutex, + 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 + +#endif + +/* 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..9f4deae53 --- /dev/null +++ b/sd/source/ui/presenter/PresenterTextView.cxx @@ -0,0 +1,470 @@ +/* -*- 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/util/Color.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +static const OUStringLiteral gsTextPropertyName("Text"); +static const OUStringLiteral gsBitmapPropertyName("Bitmap"); +static const OUStringLiteral gsSizePropertyName("Size"); +static const OUStringLiteral gsBackgroundColorPropertyName("BackgroundColor"); +static const OUStringLiteral gsTextColorPropertyName("TextColor"); +static const OUStringLiteral gsFontDescriptorPropertyName("FontDescriptor"); +static const OUStringLiteral gsTopPropertyName("Top"); +static const OUStringLiteral gsTopRelativePropertyName("RelativeTop"); +static const OUStringLiteral gsTotalHeightPropertyName("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; + SfxItemPool* mpEditEngineItemPool; + Size maSize; + OUString msText; + sal_Int32 mnTop; + sal_Int32 mnTotalHeight; + + void CheckTop(); +}; + +// PresenterTextView +PresenterTextView::PresenterTextView () + : PresenterTextViewInterfaceBase(), + 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) + { + util::Color aColor = util::Color(); + if (rValue >>= aColor) + mpImplementation->SetBackgroundColor(Color(aColor)); + } + else if (rsPropertyName == gsTextColorPropertyName) + { + util::Color aColor = util::Color(); + if (rValue >>= aColor) + mpImplementation->SetTextColor(Color(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() + : mxBitmap(), + mpCanvas(), + mpOutputDevice(VclPtr<VirtualDevice>::Create(*Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)), + mpEditEngineItemPool(EditEngine::CreatePool()), + maSize(100,100), + msText(), + 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) ); + + 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(); + SfxItemPool::Free(mpEditEngineItemPool); + 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 = rsDistance.copy(0,rsDistance.getLength()-2).toInt32(); + } + else if (rsDistance.endsWith("l")) + { + const sal_Int32 nLines (rsDistance.copy(0,rsDistance.getLength()-1).toInt32()); + // 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..8f0eb5167 --- /dev/null +++ b/sd/source/ui/presenter/PresenterTextView.hxx @@ -0,0 +1,74 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERTEXTVIEW_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_PRESENTERTEXTVIEW_HXX + +#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 + +#endif + +/* 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..bb4a75209 --- /dev/null +++ b/sd/source/ui/presenter/SlideRenderer.cxx @@ -0,0 +1,207 @@ +/* -*- 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 () + : SlideRendererInterfaceBase(m_aMutex), + maPreviewRenderer() +{ +} + +SlideRenderer::~SlideRenderer() +{ +} + +void SAL_CALL SlideRenderer::disposing() +{ +} + +//----- 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 css::uno::Sequence<OUString>{"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.get() != nullptr) + 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 (SlideRendererInterfaceBase::rBHelper.bDisposed || SlideRendererInterfaceBase::rBHelper.bInDispose) + { + 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..98afe72b7 --- /dev/null +++ b/sd/source/ui/presenter/SlideRenderer.hxx @@ -0,0 +1,100 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_SD_SOURCE_UI_PRESENTER_SLIDERENDERER_HXX +#define INCLUDED_SD_SOURCE_UI_PRESENTER_SLIDERENDERER_HXX + +#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 <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> + +namespace com::sun::star::drawing { class XDrawPage; } + +namespace sd::presenter { + +typedef ::cppu::WeakComponentImplHelper < + css::drawing::XSlideRenderer, + css::lang::XInitialization, + css::lang::XServiceInfo +> SlideRendererInterfaceBase; + +/** Render single slides into bitmaps. +*/ +class SlideRenderer + : protected ::cppu::BaseMutex, + public SlideRendererInterfaceBase +{ +public: + SlideRenderer (); + virtual ~SlideRenderer() override; + SlideRenderer(const SlideRenderer&) = delete; + SlideRenderer& operator=(const SlideRenderer&) = delete; + virtual void SAL_CALL disposing() override; + + // 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 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |