1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include "PresenterPaneBorderPainter.hxx"
21 #include "PresenterCanvasHelper.hxx"
22 #include "PresenterGeometryHelper.hxx"
23 #include "PresenterTheme.hxx"
24 #include <com/sun/star/awt/Point.hpp>
25 #include <com/sun/star/awt/Rectangle.hpp>
26 #include <com/sun/star/drawing/XPresenterHelper.hpp>
27 #include <com/sun/star/rendering/CompositeOperation.hpp>
28 #include <com/sun/star/rendering/FillRule.hpp>
29 #include <com/sun/star/rendering/TextDirection.hpp>
30 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
31 #include <map>
32 #include <memory>
33 #include <vector>
34
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
37
38 namespace sdext::presenter {
39
40 namespace {
41 class BorderSize
42 {
43 public:
44 BorderSize();
45 sal_Int32 mnLeft;
46 sal_Int32 mnTop;
47 sal_Int32 mnRight;
48 sal_Int32 mnBottom;
49 };
50
51 class RendererPaneStyle
52 {
53 public:
54 RendererPaneStyle (
55 const std::shared_ptr<PresenterTheme>& rpTheme,
56 const OUString& rsStyleName);
57
58 awt::Rectangle AddBorder (
59 const awt::Rectangle& rBox,
60 drawing::framework::BorderType eBorderType) const;
61 awt::Rectangle RemoveBorder (
62 const awt::Rectangle& rBox,
63 drawing::framework::BorderType eBorderType) const;
64 Reference<rendering::XCanvasFont> GetFont (
65 const Reference<rendering::XCanvas>& rxCanvas) const;
66
67 SharedBitmapDescriptor mpTopLeft;
68 SharedBitmapDescriptor mpTop;
69 SharedBitmapDescriptor mpTopRight;
70 SharedBitmapDescriptor mpLeft;
71 SharedBitmapDescriptor mpRight;
72 SharedBitmapDescriptor mpBottomLeft;
73 SharedBitmapDescriptor mpBottom;
74 SharedBitmapDescriptor mpBottomRight;
75 SharedBitmapDescriptor mpBottomCallout;
76 SharedBitmapDescriptor mpEmpty;
77 PresenterTheme::SharedFontDescriptor mpFont;
78 sal_Int32 mnFontXOffset;
79 sal_Int32 mnFontYOffset;
80 enum class Anchor { Left, Right, Center };
81 Anchor meFontAnchor;
82 BorderSize maInnerBorderSize;
83 BorderSize maOuterBorderSize;
84 BorderSize maTotalBorderSize;
85 private:
86 void UpdateBorderSizes();
87 SharedBitmapDescriptor GetBitmap(
88 const std::shared_ptr<PresenterTheme>& rpTheme,
89 const OUString& rsStyleName,
90 const OUString& rsBitmapName);
91 };
92 }
93
94 class PresenterPaneBorderPainter::Renderer
95 {
96 public:
97 Renderer (
98 const Reference<XComponentContext>& rxContext,
99 const std::shared_ptr<PresenterTheme>& rpTheme);
100
101 void SetCanvas (const Reference<rendering::XCanvas>& rxCanvas);
102 void PaintBorder (
103 const OUString& rsTitle,
104 const awt::Rectangle& rBBox,
105 const awt::Rectangle& rUpdateBox,
106 const OUString& rsPaneURL);
107 void PaintTitle (
108 const OUString& rsTitle,
109 const std::shared_ptr<RendererPaneStyle>& rpStyle,
110 const awt::Rectangle& rUpdateBox,
111 const awt::Rectangle& rOuterBox,
112 const awt::Rectangle& rInnerBox);
113 void SetupClipping (
114 const awt::Rectangle& rUpdateBox,
115 const awt::Rectangle& rOuterBox,
116 const OUString& rsPaneStyleName);
117 std::shared_ptr<RendererPaneStyle> GetRendererPaneStyle (const OUString& rsResourceURL);
118 void SetCalloutAnchor (
119 const awt::Point& rCalloutAnchor);
120
121 private:
122 std::shared_ptr<PresenterTheme> mpTheme;
123 typedef ::std::map<OUString, std::shared_ptr<RendererPaneStyle> > RendererPaneStyleContainer;
124 RendererPaneStyleContainer maRendererPaneStyles;
125 Reference<rendering::XCanvas> mxCanvas;
126 Reference<drawing::XPresenterHelper> mxPresenterHelper;
127 css::rendering::ViewState maViewState;
128 Reference<rendering::XPolyPolygon2D> mxViewStateClip;
129 bool mbHasCallout;
130 awt::Point maCalloutAnchor;
131
132 void PaintBitmap(
133 const awt::Rectangle& rBox,
134 const awt::Rectangle& rUpdateBox,
135 const sal_Int32 nXPosition,
136 const sal_Int32 nYPosition,
137 const sal_Int32 nStartOffset,
138 const sal_Int32 nEndOffset,
139 const bool bExpand,
140 const SharedBitmapDescriptor& rpBitmap);
141 };
142
143 // ===== PresenterPaneBorderPainter ===========================================
144
PresenterPaneBorderPainter(const Reference<XComponentContext> & rxContext)145 PresenterPaneBorderPainter::PresenterPaneBorderPainter (
146 const Reference<XComponentContext>& rxContext)
147 : PresenterPaneBorderPainterInterfaceBase(m_aMutex),
148 mxContext(rxContext),
149 mpTheme(),
150 mpRenderer()
151 {
152 }
153
~PresenterPaneBorderPainter()154 PresenterPaneBorderPainter::~PresenterPaneBorderPainter()
155 {
156 }
157
158 //----- XPaneBorderPainter ----------------------------------------------------
159
addBorder(const OUString & rsPaneBorderStyleName,const css::awt::Rectangle & rRectangle,drawing::framework::BorderType eBorderType)160 awt::Rectangle SAL_CALL PresenterPaneBorderPainter::addBorder (
161 const OUString& rsPaneBorderStyleName,
162 const css::awt::Rectangle& rRectangle,
163 drawing::framework::BorderType eBorderType)
164 {
165 ThrowIfDisposed();
166
167 ProvideTheme();
168
169 return AddBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
170 }
171
removeBorder(const OUString & rsPaneBorderStyleName,const css::awt::Rectangle & rRectangle,drawing::framework::BorderType eBorderType)172 awt::Rectangle SAL_CALL PresenterPaneBorderPainter::removeBorder (
173 const OUString& rsPaneBorderStyleName,
174 const css::awt::Rectangle& rRectangle,
175 drawing::framework::BorderType eBorderType)
176 {
177 ThrowIfDisposed();
178
179 ProvideTheme();
180
181 return RemoveBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
182 }
183
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)184 void SAL_CALL PresenterPaneBorderPainter::paintBorder (
185 const OUString& rsPaneBorderStyleName,
186 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
187 const css::awt::Rectangle& rOuterBorderRectangle,
188 const css::awt::Rectangle& rRepaintArea,
189 const OUString& rsTitle)
190 {
191 ThrowIfDisposed();
192
193 // Early reject paints completely outside the repaint area.
194 if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
195 || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
196 || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
197 || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
198 {
199 return;
200 }
201 ProvideTheme(rxCanvas);
202
203 if (mpRenderer == nullptr)
204 return;
205
206 mpRenderer->SetCanvas(rxCanvas);
207 mpRenderer->SetupClipping(
208 rRepaintArea,
209 rOuterBorderRectangle,
210 rsPaneBorderStyleName);
211 mpRenderer->PaintBorder(
212 rsTitle,
213 rOuterBorderRectangle,
214 rRepaintArea,
215 rsPaneBorderStyleName);
216 }
217
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)218 void SAL_CALL PresenterPaneBorderPainter::paintBorderWithCallout (
219 const OUString& rsPaneBorderStyleName,
220 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
221 const css::awt::Rectangle& rOuterBorderRectangle,
222 const css::awt::Rectangle& rRepaintArea,
223 const OUString& rsTitle,
224 const css::awt::Point& rCalloutAnchor)
225 {
226 ThrowIfDisposed();
227
228 // Early reject paints completely outside the repaint area.
229 if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
230 || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
231 || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
232 || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
233 {
234 return;
235 }
236 ProvideTheme(rxCanvas);
237
238 if (mpRenderer == nullptr)
239 return;
240
241 mpRenderer->SetCanvas(rxCanvas);
242 mpRenderer->SetupClipping(
243 rRepaintArea,
244 rOuterBorderRectangle,
245 rsPaneBorderStyleName);
246 mpRenderer->SetCalloutAnchor(rCalloutAnchor);
247 mpRenderer->PaintBorder(
248 rsTitle,
249 rOuterBorderRectangle,
250 rRepaintArea,
251 rsPaneBorderStyleName);
252 }
253
getCalloutOffset(const OUString & rsPaneBorderStyleName)254 awt::Point SAL_CALL PresenterPaneBorderPainter::getCalloutOffset (
255 const OUString& rsPaneBorderStyleName)
256 {
257 ThrowIfDisposed();
258 ProvideTheme();
259 if (mpRenderer != nullptr)
260 {
261 const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(
262 mpRenderer->GetRendererPaneStyle(rsPaneBorderStyleName));
263 if (pRendererPaneStyle != nullptr && pRendererPaneStyle->mpBottomCallout)
264 {
265 return awt::Point (
266 0,
267 pRendererPaneStyle->mpBottomCallout->mnHeight
268 - pRendererPaneStyle->mpBottomCallout->mnYHotSpot);
269 }
270 }
271
272 return awt::Point(0,0);
273 }
274
275
ProvideTheme(const Reference<rendering::XCanvas> & rxCanvas)276 bool PresenterPaneBorderPainter::ProvideTheme (const Reference<rendering::XCanvas>& rxCanvas)
277 {
278 bool bModified (false);
279
280 if ( ! mxContext.is())
281 return false;
282
283 if (mpTheme != nullptr)
284 {
285 // Check if the theme already has a canvas.
286 if ( ! mpTheme->HasCanvas())
287 {
288 mpTheme->ProvideCanvas(rxCanvas);
289 bModified = true;
290 }
291 }
292 else
293 {
294 mpTheme = std::make_shared<PresenterTheme>(mxContext, rxCanvas);
295 bModified = true;
296 }
297
298 if (bModified)
299 {
300 if (mpRenderer == nullptr)
301 mpRenderer.reset(new Renderer(mxContext, mpTheme));
302 else
303 mpRenderer->SetCanvas(rxCanvas);
304 }
305
306 return bModified;
307 }
308
ProvideTheme()309 void PresenterPaneBorderPainter::ProvideTheme()
310 {
311 if (mpTheme == nullptr)
312 {
313 // Create a theme without bitmaps (no canvas => no bitmaps).
314 ProvideTheme(nullptr);
315 }
316 // When there already is a theme then without a canvas we can not
317 // add anything new.
318 }
319
SetTheme(const std::shared_ptr<PresenterTheme> & rpTheme)320 void PresenterPaneBorderPainter::SetTheme (const std::shared_ptr<PresenterTheme>& rpTheme)
321 {
322 mpTheme = rpTheme;
323 if (mpRenderer == nullptr)
324 mpRenderer.reset(new Renderer(mxContext, mpTheme));
325 }
326
AddBorder(const OUString & rsPaneURL,const awt::Rectangle & rInnerBox,const css::drawing::framework::BorderType eBorderType) const327 awt::Rectangle PresenterPaneBorderPainter::AddBorder (
328 const OUString& rsPaneURL,
329 const awt::Rectangle& rInnerBox,
330 const css::drawing::framework::BorderType eBorderType) const
331 {
332 if (mpRenderer != nullptr)
333 {
334 const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
335 if (pRendererPaneStyle != nullptr)
336 return pRendererPaneStyle->AddBorder(rInnerBox, eBorderType);
337 }
338 return rInnerBox;
339 }
340
RemoveBorder(const OUString & rsPaneURL,const css::awt::Rectangle & rOuterBox,const css::drawing::framework::BorderType eBorderType) const341 awt::Rectangle PresenterPaneBorderPainter::RemoveBorder (
342 const OUString& rsPaneURL,
343 const css::awt::Rectangle& rOuterBox,
344 const css::drawing::framework::BorderType eBorderType) const
345 {
346 if (mpRenderer != nullptr)
347 {
348 const std::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
349 if (pRendererPaneStyle != nullptr)
350 return pRendererPaneStyle->RemoveBorder(rOuterBox, eBorderType);
351 }
352 return rOuterBox;
353 }
354
ThrowIfDisposed() const355 void PresenterPaneBorderPainter::ThrowIfDisposed() const
356 {
357 if (rBHelper.bDisposed || rBHelper.bInDispose)
358 {
359 throw lang::DisposedException (
360 "PresenterPaneBorderPainter object has already been disposed",
361 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
362 }
363 }
364
365 //===== PresenterPaneBorderPainter::Renderer =====================================
366
Renderer(const Reference<XComponentContext> & rxContext,const std::shared_ptr<PresenterTheme> & rpTheme)367 PresenterPaneBorderPainter::Renderer::Renderer (
368 const Reference<XComponentContext>& rxContext,
369 const std::shared_ptr<PresenterTheme>& rpTheme)
370 : mpTheme(rpTheme),
371 maRendererPaneStyles(),
372 mxCanvas(),
373 mxPresenterHelper(),
374 maViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), nullptr),
375 mxViewStateClip(),
376 mbHasCallout(false),
377 maCalloutAnchor()
378 {
379 Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager());
380 if (xFactory.is())
381 {
382 mxPresenterHelper.set(
383 xFactory->createInstanceWithContext(
384 "com.sun.star.comp.Draw.PresenterHelper",
385 rxContext),
386 UNO_QUERY_THROW);
387 }
388 }
389
SetCanvas(const Reference<rendering::XCanvas> & rxCanvas)390 void PresenterPaneBorderPainter::Renderer::SetCanvas (const Reference<rendering::XCanvas>& rxCanvas)
391 {
392 if (mxCanvas != rxCanvas)
393 {
394 mxCanvas = rxCanvas;
395 }
396 }
397
PaintBorder(const OUString & rsTitle,const awt::Rectangle & rBBox,const awt::Rectangle & rUpdateBox,const OUString & rsPaneURL)398 void PresenterPaneBorderPainter::Renderer::PaintBorder (
399 const OUString& rsTitle,
400 const awt::Rectangle& rBBox,
401 const awt::Rectangle& rUpdateBox,
402 const OUString& rsPaneURL)
403 {
404 if ( ! mxCanvas.is())
405 return;
406
407 // Create the outer and inner border of the, ahm, border.
408 std::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneURL));
409 if (pStyle == nullptr)
410 return;
411
412 awt::Rectangle aOuterBox (rBBox);
413 awt::Rectangle aCenterBox (
414 pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_OUTER_BORDER));
415 awt::Rectangle aInnerBox (
416 pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
417
418 // Prepare references for all used bitmaps.
419 SharedBitmapDescriptor pTop (pStyle->mpTop);
420 SharedBitmapDescriptor pTopLeft (pStyle->mpTopLeft);
421 SharedBitmapDescriptor pTopRight (pStyle->mpTopRight);
422 SharedBitmapDescriptor pLeft (pStyle->mpLeft);
423 SharedBitmapDescriptor pRight (pStyle->mpRight);
424 SharedBitmapDescriptor pBottomLeft (pStyle->mpBottomLeft);
425 SharedBitmapDescriptor pBottomRight (pStyle->mpBottomRight);
426 SharedBitmapDescriptor pBottom (pStyle->mpBottom);
427
428 // Paint the sides.
429 PaintBitmap(aCenterBox, rUpdateBox, 0,-1,
430 pTopLeft->mnXOffset, pTopRight->mnXOffset, true, pTop);
431 PaintBitmap(aCenterBox, rUpdateBox, -1,0,
432 pTopLeft->mnYOffset, pBottomLeft->mnYOffset, true, pLeft);
433 PaintBitmap(aCenterBox, rUpdateBox, +1,0,
434 pTopRight->mnYOffset, pBottomRight->mnYOffset, true, pRight);
435 if (mbHasCallout && pStyle->mpBottomCallout->GetNormalBitmap().is())
436 {
437 const sal_Int32 nCalloutWidth (pStyle->mpBottomCallout->mnWidth);
438 sal_Int32 nCalloutX (maCalloutAnchor.X - pStyle->mpBottomCallout->mnXHotSpot
439 - (aCenterBox.X - aOuterBox.X));
440 if (nCalloutX < pBottomLeft->mnXOffset + aCenterBox.X)
441 nCalloutX = pBottomLeft->mnXOffset + aCenterBox.X;
442 if (nCalloutX > pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width)
443 nCalloutX = pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width;
444 // Paint bottom callout.
445 PaintBitmap(aCenterBox, rUpdateBox, 0,+1, nCalloutX,0, false, pStyle->mpBottomCallout);
446 // Paint regular bottom bitmap left and right.
447 PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
448 pBottomLeft->mnXOffset, nCalloutX-aCenterBox.Width, true, pBottom);
449 PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
450 nCalloutX+nCalloutWidth, pBottomRight->mnXOffset, true, pBottom);
451 }
452 else
453 {
454 // Stretch the bottom bitmap over the full width.
455 PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
456 pBottomLeft->mnXOffset, pBottomRight->mnXOffset, true, pBottom);
457 }
458
459 // Paint the corners.
460 PaintBitmap(aCenterBox, rUpdateBox, -1,-1, 0,0, false, pTopLeft);
461 PaintBitmap(aCenterBox, rUpdateBox, +1,-1, 0,0, false, pTopRight);
462 PaintBitmap(aCenterBox, rUpdateBox, -1,+1, 0,0, false, pBottomLeft);
463 PaintBitmap(aCenterBox, rUpdateBox, +1,+1, 0,0, false, pBottomRight);
464
465 // Paint the title.
466 PaintTitle(rsTitle, pStyle, rUpdateBox, aOuterBox, aInnerBox);
467
468 // In a double buffering environment request to make the changes visible.
469 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
470 if (xSpriteCanvas.is())
471 xSpriteCanvas->updateScreen(false);
472 }
473
PaintTitle(const OUString & rsTitle,const std::shared_ptr<RendererPaneStyle> & rpStyle,const awt::Rectangle & rUpdateBox,const awt::Rectangle & rOuterBox,const awt::Rectangle & rInnerBox)474 void PresenterPaneBorderPainter::Renderer::PaintTitle (
475 const OUString& rsTitle,
476 const std::shared_ptr<RendererPaneStyle>& rpStyle,
477 const awt::Rectangle& rUpdateBox,
478 const awt::Rectangle& rOuterBox,
479 const awt::Rectangle& rInnerBox)
480 {
481 if ( ! mxCanvas.is())
482 return;
483
484 if (rsTitle.isEmpty())
485 return;
486
487 Reference<rendering::XCanvasFont> xFont (rpStyle->GetFont(mxCanvas));
488 if ( ! xFont.is())
489 return;
490
491 rendering::StringContext aContext (
492 rsTitle,
493 0,
494 rsTitle.getLength());
495 Reference<rendering::XTextLayout> xLayout (xFont->createTextLayout(
496 aContext,
497 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
498 0));
499 if ( ! xLayout.is())
500 return;
501
502 /// this is responsible of the texts above the slide windows
503 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
504 const double nTextHeight = aBox.Y2 - aBox.Y1;
505 const double nTextWidth = aBox.X1 + aBox.X2;
506 const sal_Int32 nTitleBarHeight = rInnerBox.Y - rOuterBox.Y - 1;
507 double nY = rOuterBox.Y + (nTitleBarHeight - nTextHeight) / 2 - aBox.Y1;
508 if (nY >= rInnerBox.Y)
509 nY = rInnerBox.Y - 1;
510 double nX;
511 switch (rpStyle->meFontAnchor)
512 {
513 case RendererPaneStyle::Anchor::Left:
514 nX = rInnerBox.X;
515 break;
516 case RendererPaneStyle::Anchor::Right:
517 nX = rInnerBox.X + rInnerBox.Width - nTextWidth;
518 break;
519 default: // RendererPaneStyle::Anchor::Center
520 nX = rInnerBox.X + (rInnerBox.Width - nTextWidth)/2;
521 break;
522 }
523 nX += rpStyle->mnFontXOffset;
524 nY += rpStyle->mnFontYOffset;
525
526 if (rUpdateBox.X >= nX+nTextWidth
527 || rUpdateBox.Y >= nY+nTextHeight
528 || rUpdateBox.X+rUpdateBox.Width <= nX
529 || rUpdateBox.Y+rUpdateBox.Height <= nY)
530 {
531 return;
532 }
533
534 rendering::RenderState aRenderState(
535 geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
536 nullptr,
537 Sequence<double>(4),
538 rendering::CompositeOperation::SOURCE);
539
540 PresenterCanvasHelper::SetDeviceColor(
541 aRenderState,
542 rpStyle->mpFont->mnColor);
543
544 mxCanvas->drawTextLayout (
545 xLayout,
546 maViewState,
547 aRenderState);
548 }
549
550 std::shared_ptr<RendererPaneStyle>
GetRendererPaneStyle(const OUString & rsResourceURL)551 PresenterPaneBorderPainter::Renderer::GetRendererPaneStyle (const OUString& rsResourceURL)
552 {
553 OSL_ASSERT(mpTheme != nullptr);
554
555 RendererPaneStyleContainer::const_iterator iStyle (maRendererPaneStyles.find(rsResourceURL));
556 if (iStyle == maRendererPaneStyles.end())
557 {
558 OUString sPaneStyleName ("DefaultRendererPaneStyle");
559
560 // Get pane layout name for resource URL.
561 const OUString sStyleName (mpTheme->GetStyleName(rsResourceURL));
562 if (!sStyleName.isEmpty())
563 sPaneStyleName = sStyleName;
564
565 // Create a new pane style object and initialize it with bitmaps.
566 auto pStyle = std::make_shared<RendererPaneStyle>(mpTheme,sPaneStyleName);
567 iStyle = maRendererPaneStyles.emplace(rsResourceURL, pStyle).first;
568 }
569 if (iStyle != maRendererPaneStyles.end())
570 return iStyle->second;
571 else
572 return std::shared_ptr<RendererPaneStyle>();
573 }
574
SetCalloutAnchor(const awt::Point & rCalloutAnchor)575 void PresenterPaneBorderPainter::Renderer::SetCalloutAnchor (
576 const awt::Point& rCalloutAnchor)
577 {
578 mbHasCallout = true;
579 maCalloutAnchor = rCalloutAnchor;
580 }
581
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)582 void PresenterPaneBorderPainter::Renderer::PaintBitmap(
583 const awt::Rectangle& rBox,
584 const awt::Rectangle& rUpdateBox,
585 const sal_Int32 nXPosition,
586 const sal_Int32 nYPosition,
587 const sal_Int32 nStartOffset,
588 const sal_Int32 nEndOffset,
589 const bool bExpand,
590 const SharedBitmapDescriptor& rpBitmap)
591 {
592 bool bUseCanvas (mxCanvas.is());
593 if ( ! bUseCanvas)
594 return;
595
596 if (rpBitmap->mnWidth<=0 || rpBitmap->mnHeight<=0)
597 return;
598
599 Reference<rendering::XBitmap> xBitmap = rpBitmap->GetNormalBitmap();
600 if ( ! xBitmap.is())
601 return;
602
603 // Calculate position, and for side bitmaps, the size.
604 sal_Int32 nX = 0;
605 sal_Int32 nY = 0;
606 sal_Int32 nW = rpBitmap->mnWidth;
607 sal_Int32 nH = rpBitmap->mnHeight;
608 if (nXPosition < 0)
609 {
610 nX = rBox.X - rpBitmap->mnWidth + rpBitmap->mnXOffset;
611 }
612 else if (nXPosition > 0)
613 {
614 nX = rBox.X + rBox.Width + rpBitmap->mnXOffset;
615 }
616 else
617 {
618 nX = rBox.X + nStartOffset;
619 if (bExpand)
620 nW = rBox.Width - nStartOffset + nEndOffset;
621 }
622
623 if (nYPosition < 0)
624 {
625 nY = rBox.Y - rpBitmap->mnHeight + rpBitmap->mnYOffset;
626 }
627 else if (nYPosition > 0)
628 {
629 nY = rBox.Y + rBox.Height + rpBitmap->mnYOffset;
630 }
631 else
632 {
633 nY = rBox.Y + nStartOffset;
634 if (bExpand)
635 nH = rBox.Height - nStartOffset + nEndOffset;
636 }
637
638 // Do not paint when bitmap area does not intersect with update box.
639 if (nX >= rUpdateBox.X + rUpdateBox.Width
640 || nX+nW <= rUpdateBox.X
641 || nY >= rUpdateBox.Y + rUpdateBox.Height
642 || nY+nH <= rUpdateBox.Y)
643 {
644 return;
645 }
646
647 /*
648 Reference<rendering::XBitmap> xMaskedBitmap (
649 PresenterBitmapHelper::FillMaskedWithColor (
650 mxCanvas,
651 Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
652 rBitmap.mxMaskBitmap,
653 0x00ff0000,
654 rBackgroundBitmap.maReplacementColor));
655 if (xMaskedBitmap.is())
656 xBitmap = xMaskedBitmap;
657 else if (rBitmap.mxMaskBitmap.is() && mxPresenterHelper.is())
658 {
659 const static sal_Int32 nOutsideMaskColor (0x00ff0000);
660 Reference<rendering::XIntegerBitmap> xMask (
661 mxPresenterHelper->createMask(
662 mxCanvas,
663 rBitmap.mxMaskBitmap,
664 nOutsideMaskColor,
665 false));
666 xBitmap = mxPresenterHelper->applyBitmapMaskWithColor(
667 mxCanvas,
668 Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
669 xMask,
670 rBackgroundBitmap.maReplacementColor);
671 }
672 */
673 rendering::RenderState aRenderState (
674 geometry::AffineMatrix2D(
675 double(nW)/rpBitmap->mnWidth, 0, nX,
676 0, double(nH)/rpBitmap->mnHeight, nY),
677 nullptr,
678 Sequence<double>(4),
679 rendering::CompositeOperation::OVER);
680
681 if (xBitmap.is())
682 mxCanvas->drawBitmap(
683 xBitmap,
684 maViewState,
685 aRenderState);
686 }
687
SetupClipping(const awt::Rectangle & rUpdateBox,const awt::Rectangle & rOuterBox,const OUString & rsPaneStyleName)688 void PresenterPaneBorderPainter::Renderer::SetupClipping (
689 const awt::Rectangle& rUpdateBox,
690 const awt::Rectangle& rOuterBox,
691 const OUString& rsPaneStyleName)
692 {
693 mxViewStateClip = nullptr;
694 maViewState.Clip = nullptr;
695
696 if ( ! mxCanvas.is())
697 return;
698
699 std::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneStyleName));
700 if (pStyle == nullptr)
701 {
702 mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
703 rUpdateBox,
704 mxCanvas->getDevice());
705 }
706 else
707 {
708 awt::Rectangle aInnerBox (
709 pStyle->RemoveBorder(rOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
710 ::std::vector<awt::Rectangle> aRectangles;
711 aRectangles.push_back(PresenterGeometryHelper::Intersection(rUpdateBox, rOuterBox));
712 aRectangles.push_back(PresenterGeometryHelper::Intersection(rUpdateBox, aInnerBox));
713 mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
714 aRectangles,
715 mxCanvas->getDevice());
716 if (mxViewStateClip.is())
717 mxViewStateClip->setFillRule(rendering::FillRule_EVEN_ODD);
718 }
719 maViewState.Clip = mxViewStateClip;
720 }
721
722 namespace {
723
724 //===== BorderSize ============================================================
725
BorderSize()726 BorderSize::BorderSize()
727 : mnLeft(0),
728 mnTop(0),
729 mnRight(0),
730 mnBottom(0)
731 {
732 }
733
734 //===== RendererPaneStyle ============================================================
735
RendererPaneStyle(const std::shared_ptr<PresenterTheme> & rpTheme,const OUString & rsStyleName)736 RendererPaneStyle::RendererPaneStyle (
737 const std::shared_ptr<PresenterTheme>& rpTheme,
738 const OUString& rsStyleName)
739 : mpTopLeft(),
740 mpTop(),
741 mpTopRight(),
742 mpLeft(),
743 mpRight(),
744 mpBottomLeft(),
745 mpBottom(),
746 mpBottomRight(),
747 mpBottomCallout(),
748 mpEmpty(std::make_shared<PresenterBitmapDescriptor>()),
749 mpFont(),
750 mnFontXOffset(0),
751 mnFontYOffset(0),
752 meFontAnchor(Anchor::Center),
753 maInnerBorderSize(),
754 maOuterBorderSize(),
755 maTotalBorderSize()
756 {
757 if (rpTheme == nullptr)
758 return;
759
760 mpTopLeft = GetBitmap(rpTheme, rsStyleName, "TopLeft");
761 mpTop = GetBitmap(rpTheme, rsStyleName, "Top");
762 mpTopRight = GetBitmap(rpTheme, rsStyleName, "TopRight");
763 mpLeft = GetBitmap(rpTheme, rsStyleName,"Left");
764 mpRight = GetBitmap(rpTheme, rsStyleName, "Right");
765 mpBottomLeft = GetBitmap(rpTheme, rsStyleName, "BottomLeft");
766 mpBottom = GetBitmap(rpTheme, rsStyleName, "Bottom");
767 mpBottomRight = GetBitmap(rpTheme, rsStyleName, "BottomRight");
768 mpBottomCallout = GetBitmap(rpTheme, rsStyleName, "BottomCallout");
769
770 // Get font description.
771 mpFont = rpTheme->GetFont(rsStyleName);
772
773 OUString sAnchor ("Left");
774 if (mpFont)
775 {
776 sAnchor = mpFont->msAnchor;
777 mnFontXOffset = mpFont->mnXOffset;
778 mnFontYOffset = mpFont->mnYOffset;
779 }
780
781 if ( sAnchor == "Left" )
782 meFontAnchor = Anchor::Left;
783 else if ( sAnchor == "Right" )
784 meFontAnchor = Anchor::Right;
785 else
786 meFontAnchor = Anchor::Center;
787
788 // Get border sizes.
789 try
790 {
791 ::std::vector<sal_Int32> aInnerBorder (rpTheme->GetBorderSize(rsStyleName, false));
792 OSL_ASSERT(aInnerBorder.size()==4);
793 maInnerBorderSize.mnLeft = aInnerBorder[0];
794 maInnerBorderSize.mnTop = aInnerBorder[1];
795 maInnerBorderSize.mnRight = aInnerBorder[2];
796 maInnerBorderSize.mnBottom = aInnerBorder[3];
797
798 ::std::vector<sal_Int32> aOuterBorder (rpTheme->GetBorderSize(rsStyleName, true));
799 OSL_ASSERT(aOuterBorder.size()==4);
800 maOuterBorderSize.mnLeft = aOuterBorder[0];
801 maOuterBorderSize.mnTop = aOuterBorder[1];
802 maOuterBorderSize.mnRight = aOuterBorder[2];
803 maOuterBorderSize.mnBottom = aOuterBorder[3];
804 }
805 catch(beans::UnknownPropertyException&)
806 {
807 OSL_ASSERT(false);
808 }
809
810 UpdateBorderSizes();
811 }
812
AddBorder(const awt::Rectangle & rBox,const drawing::framework::BorderType eBorderType) const813 awt::Rectangle RendererPaneStyle::AddBorder (
814 const awt::Rectangle& rBox,
815 const drawing::framework::BorderType eBorderType) const
816 {
817 const BorderSize* pBorderSize = nullptr;
818 switch (eBorderType)
819 {
820 case drawing::framework::BorderType_INNER_BORDER:
821 pBorderSize = &maInnerBorderSize;
822 break;
823 case drawing::framework::BorderType_OUTER_BORDER:
824 pBorderSize = &maOuterBorderSize;
825 break;
826 case drawing::framework::BorderType_TOTAL_BORDER:
827 pBorderSize = &maTotalBorderSize;
828 break;
829 default:
830 return rBox;
831 }
832 return awt::Rectangle (
833 rBox.X - pBorderSize->mnLeft,
834 rBox.Y - pBorderSize->mnTop,
835 rBox.Width + pBorderSize->mnLeft + pBorderSize->mnRight,
836 rBox.Height + pBorderSize->mnTop + pBorderSize->mnBottom);
837 }
838
RemoveBorder(const awt::Rectangle & rBox,const css::drawing::framework::BorderType eBorderType) const839 awt::Rectangle RendererPaneStyle::RemoveBorder (
840 const awt::Rectangle& rBox,
841 const css::drawing::framework::BorderType eBorderType) const
842 {
843 const BorderSize* pBorderSize = nullptr;
844 switch (eBorderType)
845 {
846 case drawing::framework::BorderType_INNER_BORDER:
847 pBorderSize = &maInnerBorderSize;
848 break;
849 case drawing::framework::BorderType_OUTER_BORDER:
850 pBorderSize = &maOuterBorderSize;
851 break;
852 case drawing::framework::BorderType_TOTAL_BORDER:
853 pBorderSize = &maTotalBorderSize;
854 break;
855 default:
856 return rBox;
857 }
858 return awt::Rectangle (
859 rBox.X + pBorderSize->mnLeft,
860 rBox.Y + pBorderSize->mnTop,
861 rBox.Width - pBorderSize->mnLeft - pBorderSize->mnRight,
862 rBox.Height - pBorderSize->mnTop - pBorderSize->mnBottom);
863 }
864
GetFont(const Reference<rendering::XCanvas> & rxCanvas) const865 Reference<rendering::XCanvasFont> RendererPaneStyle::GetFont (
866 const Reference<rendering::XCanvas>& rxCanvas) const
867 {
868 if (mpFont)
869 {
870 mpFont->PrepareFont(rxCanvas);
871 return mpFont->mxFont;
872 }
873 return Reference<rendering::XCanvasFont>();
874 }
875
UpdateBorderSizes()876 void RendererPaneStyle::UpdateBorderSizes()
877 {
878 maTotalBorderSize.mnLeft = maInnerBorderSize.mnLeft + maOuterBorderSize.mnLeft;
879 maTotalBorderSize.mnTop = maInnerBorderSize.mnTop + maOuterBorderSize.mnTop;
880 maTotalBorderSize.mnRight = maInnerBorderSize.mnRight + maOuterBorderSize.mnRight;
881 maTotalBorderSize.mnBottom = maInnerBorderSize.mnBottom + maOuterBorderSize.mnBottom;
882 }
883
GetBitmap(const std::shared_ptr<PresenterTheme> & rpTheme,const OUString & rsStyleName,const OUString & rsBitmapName)884 SharedBitmapDescriptor RendererPaneStyle::GetBitmap(
885 const std::shared_ptr<PresenterTheme>& rpTheme,
886 const OUString& rsStyleName,
887 const OUString& rsBitmapName)
888 {
889 SharedBitmapDescriptor pDescriptor (rpTheme->GetBitmap(rsStyleName, rsBitmapName));
890 if (pDescriptor)
891 return pDescriptor;
892 else
893 return mpEmpty;
894 }
895
896 } // end of anonymous namespace
897
898 } // end of namespace ::sd::presenter
899
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
901