summaryrefslogtreecommitdiffstats
path: root/sdext/source/presenter/PresenterPaneBorderPainter.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sdext/source/presenter/PresenterPaneBorderPainter.cxx')
-rw-r--r--sdext/source/presenter/PresenterPaneBorderPainter.cxx882
1 files changed, 882 insertions, 0 deletions
diff --git a/sdext/source/presenter/PresenterPaneBorderPainter.cxx b/sdext/source/presenter/PresenterPaneBorderPainter.cxx
new file mode 100644
index 000000000..6c0198c7e
--- /dev/null
+++ b/sdext/source/presenter/PresenterPaneBorderPainter.cxx
@@ -0,0 +1,882 @@
+/* -*- 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 "PresenterPaneBorderPainter.hxx"
+#include "PresenterCanvasHelper.hxx"
+#include "PresenterGeometryHelper.hxx"
+#include "PresenterTheme.hxx"
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/drawing/XPresenterHelper.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/FillRule.hpp>
+#include <com/sun/star/rendering/TextDirection.hpp>
+#include <com/sun/star/rendering/XSpriteCanvas.hpp>
+#include <map>
+#include <memory>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sdext::presenter {
+
+namespace {
+ class BorderSize
+ {
+ public:
+ BorderSize();
+ sal_Int32 mnLeft;
+ sal_Int32 mnTop;
+ sal_Int32 mnRight;
+ sal_Int32 mnBottom;
+ };
+
+ class RendererPaneStyle
+ {
+ public:
+ RendererPaneStyle (
+ const std::shared_ptr<PresenterTheme>& rpTheme,
+ const OUString& rsStyleName);
+
+ awt::Rectangle AddBorder (
+ const awt::Rectangle& rBox,
+ drawing::framework::BorderType eBorderType) const;
+ awt::Rectangle RemoveBorder (
+ const awt::Rectangle& rBox,
+ drawing::framework::BorderType eBorderType) const;
+ Reference<rendering::XCanvasFont> GetFont (
+ const Reference<rendering::XCanvas>& rxCanvas) const;
+
+ SharedBitmapDescriptor mpTopLeft;
+ SharedBitmapDescriptor mpTop;
+ SharedBitmapDescriptor mpTopRight;
+ SharedBitmapDescriptor mpLeft;
+ SharedBitmapDescriptor mpRight;
+ SharedBitmapDescriptor mpBottomLeft;
+ SharedBitmapDescriptor mpBottom;
+ SharedBitmapDescriptor mpBottomRight;
+ SharedBitmapDescriptor mpBottomCallout;
+ SharedBitmapDescriptor mpEmpty;
+ PresenterTheme::SharedFontDescriptor mpFont;
+ sal_Int32 mnFontXOffset;
+ sal_Int32 mnFontYOffset;
+ enum class Anchor { Left, Right, Center };
+ Anchor meFontAnchor;
+ BorderSize maInnerBorderSize;
+ BorderSize maOuterBorderSize;
+ BorderSize maTotalBorderSize;
+ private:
+ void UpdateBorderSizes();
+ SharedBitmapDescriptor GetBitmap(
+ const std::shared_ptr<PresenterTheme>& rpTheme,
+ const OUString& rsStyleName,
+ const OUString& rsBitmapName);
+ };
+}
+
+class PresenterPaneBorderPainter::Renderer
+{
+public:
+ Renderer (
+ const Reference<XComponentContext>& rxContext,
+ const std::shared_ptr<PresenterTheme>& rpTheme);
+
+ void SetCanvas (const Reference<rendering::XCanvas>& rxCanvas);
+ void PaintBorder (
+ const OUString& rsTitle,
+ const awt::Rectangle& rBBox,
+ const awt::Rectangle& rUpdateBox,
+ const OUString& rsPaneURL);
+ void PaintTitle (
+ const OUString& rsTitle,
+ const std::shared_ptr<RendererPaneStyle>& rpStyle,
+ const awt::Rectangle& rUpdateBox,
+ const awt::Rectangle& rOuterBox,
+ const awt::Rectangle& rInnerBox);
+ void SetupClipping (
+ const awt::Rectangle& rUpdateBox,
+ const awt::Rectangle& rOuterBox,
+ const OUString& rsPaneStyleName);
+ std::shared_ptr<RendererPaneStyle> GetRendererPaneStyle (const OUString& rsResourceURL);
+ void SetCalloutAnchor (
+ const awt::Point& rCalloutAnchor);
+
+private:
+ std::shared_ptr<PresenterTheme> mpTheme;
+ typedef ::std::map<OUString, std::shared_ptr<RendererPaneStyle> > RendererPaneStyleContainer;
+ RendererPaneStyleContainer maRendererPaneStyles;
+ Reference<rendering::XCanvas> mxCanvas;
+ Reference<drawing::XPresenterHelper> mxPresenterHelper;
+ css::rendering::ViewState maViewState;
+ Reference<rendering::XPolyPolygon2D> mxViewStateClip;
+ bool mbHasCallout;
+ awt::Point maCalloutAnchor;
+
+ void PaintBitmap(
+ const awt::Rectangle& rBox,
+ const awt::Rectangle& rUpdateBox,
+ const sal_Int32 nXPosition,
+ const sal_Int32 nYPosition,
+ const sal_Int32 nStartOffset,
+ const sal_Int32 nEndOffset,
+ const bool bExpand,
+ const SharedBitmapDescriptor& rpBitmap);
+};
+
+// ===== PresenterPaneBorderPainter ===========================================
+
+PresenterPaneBorderPainter::PresenterPaneBorderPainter (
+ const Reference<XComponentContext>& rxContext)
+ : PresenterPaneBorderPainterInterfaceBase(m_aMutex),
+ mxContext(rxContext)
+{
+}
+
+PresenterPaneBorderPainter::~PresenterPaneBorderPainter()
+{
+}
+
+//----- XPaneBorderPainter ----------------------------------------------------
+
+awt::Rectangle SAL_CALL PresenterPaneBorderPainter::addBorder (
+ const OUString& rsPaneBorderStyleName,
+ const css::awt::Rectangle& rRectangle,
+ drawing::framework::BorderType eBorderType)
+{
+ ThrowIfDisposed();
+
+ ProvideTheme();
+
+ return AddBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
+}
+
+awt::Rectangle SAL_CALL PresenterPaneBorderPainter::removeBorder (
+ const OUString& rsPaneBorderStyleName,
+ const css::awt::Rectangle& rRectangle,
+ drawing::framework::BorderType eBorderType)
+{
+ ThrowIfDisposed();
+
+ ProvideTheme();
+
+ return RemoveBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
+}
+
+void SAL_CALL PresenterPaneBorderPainter::paintBorder (
+ const OUString& rsPaneBorderStyleName,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
+ const css::awt::Rectangle& rOuterBorderRectangle,
+ const css::awt::Rectangle& rRepaintArea,
+ const OUString& rsTitle)
+{
+ ThrowIfDisposed();
+
+ // Early reject paints completely outside the repaint area.
+ if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
+ || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
+ || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
+ || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
+ {
+ return;
+ }
+ ProvideTheme(rxCanvas);
+
+ if (mpRenderer == nullptr)
+ return;
+
+ mpRenderer->SetCanvas(rxCanvas);
+ mpRenderer->SetupClipping(
+ rRepaintArea,
+ rOuterBorderRectangle,
+ rsPaneBorderStyleName);
+ mpRenderer->PaintBorder(
+ rsTitle,
+ rOuterBorderRectangle,
+ rRepaintArea,
+ rsPaneBorderStyleName);
+}
+
+void SAL_CALL PresenterPaneBorderPainter::paintBorderWithCallout (
+ const OUString& rsPaneBorderStyleName,
+ const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
+ const css::awt::Rectangle& rOuterBorderRectangle,
+ const css::awt::Rectangle& rRepaintArea,
+ const OUString& rsTitle,
+ const css::awt::Point& rCalloutAnchor)
+{
+ ThrowIfDisposed();
+
+ // Early reject paints completely outside the repaint area.
+ if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
+ || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
+ || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
+ || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
+ {
+ return;
+ }
+ ProvideTheme(rxCanvas);
+
+ if (mpRenderer == nullptr)
+ return;
+
+ mpRenderer->SetCanvas(rxCanvas);
+ mpRenderer->SetupClipping(
+ rRepaintArea,
+ rOuterBorderRectangle,
+ rsPaneBorderStyleName);
+ mpRenderer->SetCalloutAnchor(rCalloutAnchor);
+ mpRenderer->PaintBorder(
+ rsTitle,
+ rOuterBorderRectangle,
+ rRepaintArea,
+ rsPaneBorderStyleName);
+}
+
+awt::Point SAL_CALL PresenterPaneBorderPainter::getCalloutOffset (
+ const OUString& rsPaneBorderStyleName)
+{
+ ThrowIfDisposed();
+ ProvideTheme();
+ if (mpRenderer != nullptr)
+ {
+ const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(
+ mpRenderer->GetRendererPaneStyle(rsPaneBorderStyleName));
+ if (pRendererPaneStyle != nullptr && pRendererPaneStyle->mpBottomCallout)
+ {
+ return awt::Point (
+ 0,
+ pRendererPaneStyle->mpBottomCallout->mnHeight
+ - pRendererPaneStyle->mpBottomCallout->mnYHotSpot);
+ }
+ }
+
+ return awt::Point(0,0);
+}
+
+
+bool PresenterPaneBorderPainter::ProvideTheme (const Reference<rendering::XCanvas>& rxCanvas)
+{
+ bool bModified (false);
+
+ if ( ! mxContext.is())
+ return false;
+
+ if (mpTheme != nullptr)
+ {
+ // Check if the theme already has a canvas.
+ if ( ! mpTheme->HasCanvas())
+ {
+ mpTheme->ProvideCanvas(rxCanvas);
+ bModified = true;
+ }
+ }
+ else
+ {
+ mpTheme = std::make_shared<PresenterTheme>(mxContext, rxCanvas);
+ bModified = true;
+ }
+
+ if (bModified)
+ {
+ if (mpRenderer == nullptr)
+ mpRenderer.reset(new Renderer(mxContext, mpTheme));
+ else
+ mpRenderer->SetCanvas(rxCanvas);
+ }
+
+ return bModified;
+}
+
+void PresenterPaneBorderPainter::ProvideTheme()
+{
+ if (mpTheme == nullptr)
+ {
+ // Create a theme without bitmaps (no canvas => no bitmaps).
+ ProvideTheme(nullptr);
+ }
+ // When there already is a theme then without a canvas we can not
+ // add anything new.
+}
+
+void PresenterPaneBorderPainter::SetTheme (const std::shared_ptr<PresenterTheme>& rpTheme)
+{
+ mpTheme = rpTheme;
+ if (mpRenderer == nullptr)
+ mpRenderer.reset(new Renderer(mxContext, mpTheme));
+}
+
+awt::Rectangle PresenterPaneBorderPainter::AddBorder (
+ const OUString& rsPaneURL,
+ const awt::Rectangle& rInnerBox,
+ const css::drawing::framework::BorderType eBorderType) const
+{
+ if (mpRenderer != nullptr)
+ {
+ const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
+ if (pRendererPaneStyle != nullptr)
+ return pRendererPaneStyle->AddBorder(rInnerBox, eBorderType);
+ }
+ return rInnerBox;
+}
+
+awt::Rectangle PresenterPaneBorderPainter::RemoveBorder (
+ const OUString& rsPaneURL,
+ const css::awt::Rectangle& rOuterBox,
+ const css::drawing::framework::BorderType eBorderType) const
+{
+ if (mpRenderer != nullptr)
+ {
+ const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
+ if (pRendererPaneStyle != nullptr)
+ return pRendererPaneStyle->RemoveBorder(rOuterBox, eBorderType);
+ }
+ return rOuterBox;
+}
+
+void PresenterPaneBorderPainter::ThrowIfDisposed() const
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ throw lang::DisposedException (
+ "PresenterPaneBorderPainter object has already been disposed",
+ const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
+ }
+}
+
+//===== PresenterPaneBorderPainter::Renderer =====================================
+
+PresenterPaneBorderPainter::Renderer::Renderer (
+ const Reference<XComponentContext>& rxContext,
+ const std::shared_ptr<PresenterTheme>& rpTheme)
+ : mpTheme(rpTheme),
+ maViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
+ mbHasCallout(false)
+{
+ Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager());
+ if (xFactory.is())
+ {
+ mxPresenterHelper.set(
+ xFactory->createInstanceWithContext(
+ "com.sun.star.comp.Draw.PresenterHelper",
+ rxContext),
+ UNO_QUERY_THROW);
+ }
+}
+
+void PresenterPaneBorderPainter::Renderer::SetCanvas (const Reference<rendering::XCanvas>& rxCanvas)
+{
+ if (mxCanvas != rxCanvas)
+ {
+ mxCanvas = rxCanvas;
+ }
+}
+
+void PresenterPaneBorderPainter::Renderer::PaintBorder (
+ const OUString& rsTitle,
+ const awt::Rectangle& rBBox,
+ const awt::Rectangle& rUpdateBox,
+ const OUString& rsPaneURL)
+{
+ if ( ! mxCanvas.is())
+ return;
+
+ // Create the outer and inner border of the, ahm, border.
+ std::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneURL));
+ if (pStyle == nullptr)
+ return;
+
+ awt::Rectangle aOuterBox (rBBox);
+ awt::Rectangle aCenterBox (
+ pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_OUTER_BORDER));
+ awt::Rectangle aInnerBox (
+ pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
+
+ // Prepare references for all used bitmaps.
+ SharedBitmapDescriptor pTop (pStyle->mpTop);
+ SharedBitmapDescriptor pTopLeft (pStyle->mpTopLeft);
+ SharedBitmapDescriptor pTopRight (pStyle->mpTopRight);
+ SharedBitmapDescriptor pLeft (pStyle->mpLeft);
+ SharedBitmapDescriptor pRight (pStyle->mpRight);
+ SharedBitmapDescriptor pBottomLeft (pStyle->mpBottomLeft);
+ SharedBitmapDescriptor pBottomRight (pStyle->mpBottomRight);
+ SharedBitmapDescriptor pBottom (pStyle->mpBottom);
+
+ // Paint the sides.
+ PaintBitmap(aCenterBox, rUpdateBox, 0,-1,
+ pTopLeft->mnXOffset, pTopRight->mnXOffset, true, pTop);
+ PaintBitmap(aCenterBox, rUpdateBox, -1,0,
+ pTopLeft->mnYOffset, pBottomLeft->mnYOffset, true, pLeft);
+ PaintBitmap(aCenterBox, rUpdateBox, +1,0,
+ pTopRight->mnYOffset, pBottomRight->mnYOffset, true, pRight);
+ if (mbHasCallout && pStyle->mpBottomCallout->GetNormalBitmap().is())
+ {
+ const sal_Int32 nCalloutWidth (pStyle->mpBottomCallout->mnWidth);
+ sal_Int32 nCalloutX (maCalloutAnchor.X - pStyle->mpBottomCallout->mnXHotSpot
+ - (aCenterBox.X - aOuterBox.X));
+ if (nCalloutX < pBottomLeft->mnXOffset + aCenterBox.X)
+ nCalloutX = pBottomLeft->mnXOffset + aCenterBox.X;
+ if (nCalloutX > pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width)
+ nCalloutX = pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width;
+ // Paint bottom callout.
+ PaintBitmap(aCenterBox, rUpdateBox, 0,+1, nCalloutX,0, false, pStyle->mpBottomCallout);
+ // Paint regular bottom bitmap left and right.
+ PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
+ pBottomLeft->mnXOffset, nCalloutX-aCenterBox.Width, true, pBottom);
+ PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
+ nCalloutX+nCalloutWidth, pBottomRight->mnXOffset, true, pBottom);
+ }
+ else
+ {
+ // Stretch the bottom bitmap over the full width.
+ PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
+ pBottomLeft->mnXOffset, pBottomRight->mnXOffset, true, pBottom);
+ }
+
+ // Paint the corners.
+ PaintBitmap(aCenterBox, rUpdateBox, -1,-1, 0,0, false, pTopLeft);
+ PaintBitmap(aCenterBox, rUpdateBox, +1,-1, 0,0, false, pTopRight);
+ PaintBitmap(aCenterBox, rUpdateBox, -1,+1, 0,0, false, pBottomLeft);
+ PaintBitmap(aCenterBox, rUpdateBox, +1,+1, 0,0, false, pBottomRight);
+
+ // Paint the title.
+ PaintTitle(rsTitle, pStyle, rUpdateBox, aOuterBox, aInnerBox);
+
+ // In a double buffering environment request to make the changes visible.
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ xSpriteCanvas->updateScreen(false);
+}
+
+void PresenterPaneBorderPainter::Renderer::PaintTitle (
+ const OUString& rsTitle,
+ const std::shared_ptr<RendererPaneStyle>& rpStyle,
+ const awt::Rectangle& rUpdateBox,
+ const awt::Rectangle& rOuterBox,
+ const awt::Rectangle& rInnerBox)
+{
+ if ( ! mxCanvas.is())
+ return;
+
+ if (rsTitle.isEmpty())
+ return;
+
+ Reference<rendering::XCanvasFont> xFont (rpStyle->GetFont(mxCanvas));
+ if ( ! xFont.is())
+ return;
+
+ rendering::StringContext aContext (
+ rsTitle,
+ 0,
+ rsTitle.getLength());
+ Reference<rendering::XTextLayout> xLayout (xFont->createTextLayout(
+ aContext,
+ rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
+ 0));
+ if ( ! xLayout.is())
+ return;
+
+ /// this is responsible of the texts above the slide windows
+ geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
+ const double nTextHeight = aBox.Y2 - aBox.Y1;
+ const double nTextWidth = aBox.X1 + aBox.X2;
+ const sal_Int32 nTitleBarHeight = rInnerBox.Y - rOuterBox.Y - 1;
+ double nY = rOuterBox.Y + (nTitleBarHeight - nTextHeight) / 2 - aBox.Y1;
+ if (nY >= rInnerBox.Y)
+ nY = rInnerBox.Y - 1;
+ double nX;
+ switch (rpStyle->meFontAnchor)
+ {
+ case RendererPaneStyle::Anchor::Left:
+ nX = rInnerBox.X;
+ break;
+ case RendererPaneStyle::Anchor::Right:
+ nX = rInnerBox.X + rInnerBox.Width - nTextWidth;
+ break;
+ default: // RendererPaneStyle::Anchor::Center
+ nX = rInnerBox.X + (rInnerBox.Width - nTextWidth)/2;
+ break;
+ }
+ nX += rpStyle->mnFontXOffset;
+ nY += rpStyle->mnFontYOffset;
+
+ if (rUpdateBox.X >= nX+nTextWidth
+ || rUpdateBox.Y >= nY+nTextHeight
+ || rUpdateBox.X+rUpdateBox.Width <= nX
+ || rUpdateBox.Y+rUpdateBox.Height <= nY)
+ {
+ return;
+ }
+
+ rendering::RenderState aRenderState(
+ geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
+ nullptr,
+ Sequence<double>(4),
+ rendering::CompositeOperation::SOURCE);
+
+ PresenterCanvasHelper::SetDeviceColor(
+ aRenderState,
+ rpStyle->mpFont->mnColor);
+
+ mxCanvas->drawTextLayout (
+ xLayout,
+ maViewState,
+ aRenderState);
+}
+
+std::shared_ptr<RendererPaneStyle>
+ PresenterPaneBorderPainter::Renderer::GetRendererPaneStyle (const OUString& rsResourceURL)
+{
+ OSL_ASSERT(mpTheme != nullptr);
+
+ RendererPaneStyleContainer::const_iterator iStyle (maRendererPaneStyles.find(rsResourceURL));
+ if (iStyle == maRendererPaneStyles.end())
+ {
+ OUString sPaneStyleName ("DefaultRendererPaneStyle");
+
+ // Get pane layout name for resource URL.
+ const OUString sStyleName (mpTheme->GetStyleName(rsResourceURL));
+ if (!sStyleName.isEmpty())
+ sPaneStyleName = sStyleName;
+
+ // Create a new pane style object and initialize it with bitmaps.
+ auto pStyle = std::make_shared<RendererPaneStyle>(mpTheme,sPaneStyleName);
+ iStyle = maRendererPaneStyles.emplace(rsResourceURL, pStyle).first;
+ }
+ if (iStyle != maRendererPaneStyles.end())
+ return iStyle->second;
+ else
+ return std::shared_ptr<RendererPaneStyle>();
+}
+
+void PresenterPaneBorderPainter::Renderer::SetCalloutAnchor (
+ const awt::Point& rCalloutAnchor)
+{
+ mbHasCallout = true;
+ maCalloutAnchor = rCalloutAnchor;
+}
+
+void PresenterPaneBorderPainter::Renderer::PaintBitmap(
+ const awt::Rectangle& rBox,
+ const awt::Rectangle& rUpdateBox,
+ const sal_Int32 nXPosition,
+ const sal_Int32 nYPosition,
+ const sal_Int32 nStartOffset,
+ const sal_Int32 nEndOffset,
+ const bool bExpand,
+ const SharedBitmapDescriptor& rpBitmap)
+{
+ bool bUseCanvas (mxCanvas.is());
+ if ( ! bUseCanvas)
+ return;
+
+ if (rpBitmap->mnWidth<=0 || rpBitmap->mnHeight<=0)
+ return;
+
+ Reference<rendering::XBitmap> xBitmap = rpBitmap->GetNormalBitmap();
+ if ( ! xBitmap.is())
+ return;
+
+ // Calculate position, and for side bitmaps, the size.
+ sal_Int32 nX = 0;
+ sal_Int32 nY = 0;
+ sal_Int32 nW = rpBitmap->mnWidth;
+ sal_Int32 nH = rpBitmap->mnHeight;
+ if (nXPosition < 0)
+ {
+ nX = rBox.X - rpBitmap->mnWidth + rpBitmap->mnXOffset;
+ }
+ else if (nXPosition > 0)
+ {
+ nX = rBox.X + rBox.Width + rpBitmap->mnXOffset;
+ }
+ else
+ {
+ nX = rBox.X + nStartOffset;
+ if (bExpand)
+ nW = rBox.Width - nStartOffset + nEndOffset;
+ }
+
+ if (nYPosition < 0)
+ {
+ nY = rBox.Y - rpBitmap->mnHeight + rpBitmap->mnYOffset;
+ }
+ else if (nYPosition > 0)
+ {
+ nY = rBox.Y + rBox.Height + rpBitmap->mnYOffset;
+ }
+ else
+ {
+ nY = rBox.Y + nStartOffset;
+ if (bExpand)
+ nH = rBox.Height - nStartOffset + nEndOffset;
+ }
+
+ // Do not paint when bitmap area does not intersect with update box.
+ if (nX >= rUpdateBox.X + rUpdateBox.Width
+ || nX+nW <= rUpdateBox.X
+ || nY >= rUpdateBox.Y + rUpdateBox.Height
+ || nY+nH <= rUpdateBox.Y)
+ {
+ return;
+ }
+
+ /*
+ Reference<rendering::XBitmap> xMaskedBitmap (
+ PresenterBitmapHelper::FillMaskedWithColor (
+ mxCanvas,
+ Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
+ rBitmap.mxMaskBitmap,
+ 0x00ff0000,
+ rBackgroundBitmap.maReplacementColor));
+ if (xMaskedBitmap.is())
+ xBitmap = xMaskedBitmap;
+ else if (rBitmap.mxMaskBitmap.is() && mxPresenterHelper.is())
+ {
+ const static sal_Int32 nOutsideMaskColor (0x00ff0000);
+ Reference<rendering::XIntegerBitmap> xMask (
+ mxPresenterHelper->createMask(
+ mxCanvas,
+ rBitmap.mxMaskBitmap,
+ nOutsideMaskColor,
+ false));
+ xBitmap = mxPresenterHelper->applyBitmapMaskWithColor(
+ mxCanvas,
+ Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
+ xMask,
+ rBackgroundBitmap.maReplacementColor);
+ }
+ */
+ rendering::RenderState aRenderState (
+ geometry::AffineMatrix2D(
+ double(nW)/rpBitmap->mnWidth, 0, nX,
+ 0, double(nH)/rpBitmap->mnHeight, nY),
+ nullptr,
+ Sequence<double>(4),
+ rendering::CompositeOperation::OVER);
+
+ if (xBitmap.is())
+ mxCanvas->drawBitmap(
+ xBitmap,
+ maViewState,
+ aRenderState);
+}
+
+void PresenterPaneBorderPainter::Renderer::SetupClipping (
+ const awt::Rectangle& rUpdateBox,
+ const awt::Rectangle& rOuterBox,
+ const OUString& rsPaneStyleName)
+{
+ mxViewStateClip = nullptr;
+ maViewState.Clip = nullptr;
+
+ if ( ! mxCanvas.is())
+ return;
+
+ std::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneStyleName));
+ if (pStyle == nullptr)
+ {
+ mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
+ rUpdateBox,
+ mxCanvas->getDevice());
+ }
+ else
+ {
+ awt::Rectangle aInnerBox (
+ pStyle->RemoveBorder(rOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
+ ::std::vector<awt::Rectangle> aRectangles
+ {
+ PresenterGeometryHelper::Intersection(rUpdateBox, rOuterBox),
+ PresenterGeometryHelper::Intersection(rUpdateBox, aInnerBox)
+ };
+ mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
+ aRectangles,
+ mxCanvas->getDevice());
+ if (mxViewStateClip.is())
+ mxViewStateClip->setFillRule(rendering::FillRule_EVEN_ODD);
+ }
+ maViewState.Clip = mxViewStateClip;
+}
+
+namespace {
+
+//===== BorderSize ============================================================
+
+BorderSize::BorderSize()
+ : mnLeft(0),
+ mnTop(0),
+ mnRight(0),
+ mnBottom(0)
+{
+}
+
+//===== RendererPaneStyle ============================================================
+
+RendererPaneStyle::RendererPaneStyle (
+ const std::shared_ptr<PresenterTheme>& rpTheme,
+ const OUString& rsStyleName)
+ : mpEmpty(std::make_shared<PresenterBitmapDescriptor>()),
+ mnFontXOffset(0),
+ mnFontYOffset(0),
+ meFontAnchor(Anchor::Center)
+{
+ if (rpTheme == nullptr)
+ return;
+
+ mpTopLeft = GetBitmap(rpTheme, rsStyleName, "TopLeft");
+ mpTop = GetBitmap(rpTheme, rsStyleName, "Top");
+ mpTopRight = GetBitmap(rpTheme, rsStyleName, "TopRight");
+ mpLeft = GetBitmap(rpTheme, rsStyleName,"Left");
+ mpRight = GetBitmap(rpTheme, rsStyleName, "Right");
+ mpBottomLeft = GetBitmap(rpTheme, rsStyleName, "BottomLeft");
+ mpBottom = GetBitmap(rpTheme, rsStyleName, "Bottom");
+ mpBottomRight = GetBitmap(rpTheme, rsStyleName, "BottomRight");
+ mpBottomCallout = GetBitmap(rpTheme, rsStyleName, "BottomCallout");
+
+ // Get font description.
+ mpFont = rpTheme->GetFont(rsStyleName);
+
+ OUString sAnchor ("Left");
+ if (mpFont)
+ {
+ sAnchor = mpFont->msAnchor;
+ mnFontXOffset = mpFont->mnXOffset;
+ mnFontYOffset = mpFont->mnYOffset;
+ }
+
+ if ( sAnchor == "Left" )
+ meFontAnchor = Anchor::Left;
+ else if ( sAnchor == "Right" )
+ meFontAnchor = Anchor::Right;
+ else
+ meFontAnchor = Anchor::Center;
+
+ // Get border sizes.
+ try
+ {
+ ::std::vector<sal_Int32> aInnerBorder (rpTheme->GetBorderSize(rsStyleName, false));
+ OSL_ASSERT(aInnerBorder.size()==4);
+ maInnerBorderSize.mnLeft = aInnerBorder[0];
+ maInnerBorderSize.mnTop = aInnerBorder[1];
+ maInnerBorderSize.mnRight = aInnerBorder[2];
+ maInnerBorderSize.mnBottom = aInnerBorder[3];
+
+ ::std::vector<sal_Int32> aOuterBorder (rpTheme->GetBorderSize(rsStyleName, true));
+ OSL_ASSERT(aOuterBorder.size()==4);
+ maOuterBorderSize.mnLeft = aOuterBorder[0];
+ maOuterBorderSize.mnTop = aOuterBorder[1];
+ maOuterBorderSize.mnRight = aOuterBorder[2];
+ maOuterBorderSize.mnBottom = aOuterBorder[3];
+ }
+ catch(beans::UnknownPropertyException&)
+ {
+ OSL_ASSERT(false);
+ }
+
+ UpdateBorderSizes();
+}
+
+awt::Rectangle RendererPaneStyle::AddBorder (
+ const awt::Rectangle& rBox,
+ const drawing::framework::BorderType eBorderType) const
+{
+ const BorderSize* pBorderSize = nullptr;
+ switch (eBorderType)
+ {
+ case drawing::framework::BorderType_INNER_BORDER:
+ pBorderSize = &maInnerBorderSize;
+ break;
+ case drawing::framework::BorderType_OUTER_BORDER:
+ pBorderSize = &maOuterBorderSize;
+ break;
+ case drawing::framework::BorderType_TOTAL_BORDER:
+ pBorderSize = &maTotalBorderSize;
+ break;
+ default:
+ return rBox;
+ }
+ return awt::Rectangle (
+ rBox.X - pBorderSize->mnLeft,
+ rBox.Y - pBorderSize->mnTop,
+ rBox.Width + pBorderSize->mnLeft + pBorderSize->mnRight,
+ rBox.Height + pBorderSize->mnTop + pBorderSize->mnBottom);
+}
+
+awt::Rectangle RendererPaneStyle::RemoveBorder (
+ const awt::Rectangle& rBox,
+ const css::drawing::framework::BorderType eBorderType) const
+{
+ const BorderSize* pBorderSize = nullptr;
+ switch (eBorderType)
+ {
+ case drawing::framework::BorderType_INNER_BORDER:
+ pBorderSize = &maInnerBorderSize;
+ break;
+ case drawing::framework::BorderType_OUTER_BORDER:
+ pBorderSize = &maOuterBorderSize;
+ break;
+ case drawing::framework::BorderType_TOTAL_BORDER:
+ pBorderSize = &maTotalBorderSize;
+ break;
+ default:
+ return rBox;
+ }
+ return awt::Rectangle (
+ rBox.X + pBorderSize->mnLeft,
+ rBox.Y + pBorderSize->mnTop,
+ rBox.Width - pBorderSize->mnLeft - pBorderSize->mnRight,
+ rBox.Height - pBorderSize->mnTop - pBorderSize->mnBottom);
+}
+
+Reference<rendering::XCanvasFont> RendererPaneStyle::GetFont (
+ const Reference<rendering::XCanvas>& rxCanvas) const
+{
+ if (mpFont)
+ {
+ mpFont->PrepareFont(rxCanvas);
+ return mpFont->mxFont;
+ }
+ return Reference<rendering::XCanvasFont>();
+}
+
+void RendererPaneStyle::UpdateBorderSizes()
+{
+ maTotalBorderSize.mnLeft = maInnerBorderSize.mnLeft + maOuterBorderSize.mnLeft;
+ maTotalBorderSize.mnTop = maInnerBorderSize.mnTop + maOuterBorderSize.mnTop;
+ maTotalBorderSize.mnRight = maInnerBorderSize.mnRight + maOuterBorderSize.mnRight;
+ maTotalBorderSize.mnBottom = maInnerBorderSize.mnBottom + maOuterBorderSize.mnBottom;
+}
+
+SharedBitmapDescriptor RendererPaneStyle::GetBitmap(
+ const std::shared_ptr<PresenterTheme>& rpTheme,
+ const OUString& rsStyleName,
+ const OUString& rsBitmapName)
+{
+ SharedBitmapDescriptor pDescriptor (rpTheme->GetBitmap(rsStyleName, rsBitmapName));
+ if (pDescriptor)
+ return pDescriptor;
+ else
+ return mpEmpty;
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sd::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */