1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sdext.hxx"
30 
31 #include "PresenterPaneBorderPainter.hxx"
32 #include "PresenterCanvasHelper.hxx"
33 #include "PresenterConfigurationAccess.hxx"
34 #include "PresenterGeometryHelper.hxx"
35 #include "PresenterTheme.hxx"
36 #include <com/sun/star/awt/FontDescriptor.hpp>
37 #include <com/sun/star/awt/Point.hpp>
38 #include <com/sun/star/awt/Rectangle.hpp>
39 #include <com/sun/star/awt/SimpleFontMetric.hpp>
40 #include <com/sun/star/awt/XFont.hpp>
41 #include <com/sun/star/drawing/XPresenterHelper.hpp>
42 #include <com/sun/star/graphic/XGraphic.hpp>
43 #include <com/sun/star/graphic/XGraphicRenderer.hpp>
44 #include <com/sun/star/rendering/CompositeOperation.hpp>
45 #include <com/sun/star/rendering/FillRule.hpp>
46 #include <com/sun/star/rendering/TextDirection.hpp>
47 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
48 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
49 #include <map>
50 #include <vector>
51 #include <boost/shared_ptr.hpp>
52 
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::uno;
55 using ::rtl::OUString;
56 
57 #define A2S(s) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)))
58 
59 namespace sdext { namespace presenter {
60 
61 namespace {
62     class BorderSize
63     {
64     public:
65         BorderSize (void);
66         BorderSize (const BorderSize& rBorderSize);
67         BorderSize& operator= (const BorderSize& rBoderSize);
68         sal_Int32 mnLeft;
69         sal_Int32 mnTop;
70         sal_Int32 mnRight;
71         sal_Int32 mnBottom;
72     };
73 
74     class RendererPaneStyle
75     {
76     public:
77         RendererPaneStyle (
78             const ::boost::shared_ptr<PresenterTheme>& rpTheme,
79             const OUString& rsStyleName);
80 
81         awt::Rectangle AddBorder (
82             const awt::Rectangle& rBox,
83             drawing::framework::BorderType eBorderType) const;
84         awt::Rectangle RemoveBorder (
85             const awt::Rectangle& rBox,
86             drawing::framework::BorderType eBorderType) const;
87         const Reference<rendering::XCanvasFont> GetFont (
88             const Reference<rendering::XCanvas>& rxCanvas) const;
89 
90         SharedBitmapDescriptor mpTopLeft;
91         SharedBitmapDescriptor mpTop;
92         SharedBitmapDescriptor mpTopRight;
93         SharedBitmapDescriptor mpLeft;
94         SharedBitmapDescriptor mpRight;
95         SharedBitmapDescriptor mpBottomLeft;
96         SharedBitmapDescriptor mpBottom;
97         SharedBitmapDescriptor mpBottomRight;
98         SharedBitmapDescriptor mpBottomCallout;
99         SharedBitmapDescriptor mpBackground;
100         SharedBitmapDescriptor mpEmpty;
101         PresenterTheme::SharedFontDescriptor mpFont;
102         sal_Int32 mnFontXOffset;
103         sal_Int32 mnFontYOffset;
104         enum Anchor { AnchorLeft, AnchorRight, AnchorCenter } meFontAnchor;
105         BorderSize maInnerBorderSize;
106         BorderSize maOuterBorderSize;
107         BorderSize maTotalBorderSize;
108         enum Side { Left, Top, Right, Bottom };
109     private:
110         void UpdateBorderSizes (void);
111         SharedBitmapDescriptor GetBitmap(
112             const ::boost::shared_ptr<PresenterTheme>& rpTheme,
113             const OUString& rsStyleName,
114             const OUString& rsBitmapName);
115     };
116 }
117 
118 
119 
120 class  PresenterPaneBorderPainter::Renderer
121 {
122 public:
123     Renderer (
124         const Reference<XComponentContext>& rxContext,
125         const ::boost::shared_ptr<PresenterTheme>& rpTheme);
126     ~Renderer (void);
127 
128     void SetCanvas (const Reference<rendering::XCanvas>& rxCanvas);
129     void PaintBorder (
130         const OUString& rsTitle,
131         const awt::Rectangle& rBBox,
132         const awt::Rectangle& rUpdateBox,
133         const OUString& rsPaneURL);
134     void PaintTitle (
135         const OUString& rsTitle,
136         const ::boost::shared_ptr<RendererPaneStyle>& rpStyle,
137         const awt::Rectangle& rUpdateBox,
138         const awt::Rectangle& rOuterBox,
139         const awt::Rectangle& rInnerBox,
140         const bool bPaintBackground);
141     void SetupClipping (
142         const awt::Rectangle& rUpdateBox,
143         const awt::Rectangle& rOuterBox,
144         const OUString& rsPaneStyleName);
145     ::boost::shared_ptr<RendererPaneStyle> GetRendererPaneStyle (const OUString& rsResourceURL);
146     void SetCalloutAnchor (
147         const awt::Point& rCalloutAnchor);
148 
149 private:
150     ::boost::shared_ptr<PresenterTheme> mpTheme;
151     typedef ::std::map<OUString, ::boost::shared_ptr<RendererPaneStyle> > RendererPaneStyleContainer;
152     RendererPaneStyleContainer maRendererPaneStyles;
153     Reference<rendering::XCanvas> mxCanvas;
154     Reference<drawing::XPresenterHelper> mxPresenterHelper;
155     css::rendering::ViewState maViewState;
156     Reference<rendering::XPolyPolygon2D> mxViewStateClip;
157     bool mbHasCallout;
158     awt::Point maCalloutAnchor;
159 
160     void PaintBitmap(
161         const awt::Rectangle& rBox,
162         const awt::Rectangle& rUpdateBox,
163         const sal_Int32 nXPosition,
164         const sal_Int32 nYPosition,
165         const sal_Int32 nStartOffset,
166         const sal_Int32 nEndOffset,
167         const bool bExpand,
168         const SharedBitmapDescriptor& rpBitmap,
169         const SharedBitmapDescriptor& rpBackgroundBitmap);
170 };
171 
172 
173 
174 
175 // ===== PresenterPaneBorderPainter ===========================================
176 
177 PresenterPaneBorderPainter::PresenterPaneBorderPainter (
178     const Reference<XComponentContext>& rxContext)
179     : PresenterPaneBorderPainterInterfaceBase(m_aMutex),
180       mxContext(rxContext),
181       mpTheme(),
182       mpRenderer()
183 {
184 }
185 
186 
187 
188 
189 PresenterPaneBorderPainter::~PresenterPaneBorderPainter (void)
190 {
191 }
192 
193 
194 
195 
196 //----- XPaneBorderPainter ----------------------------------------------------
197 
198 awt::Rectangle SAL_CALL PresenterPaneBorderPainter::addBorder (
199     const rtl::OUString& rsPaneBorderStyleName,
200     const css::awt::Rectangle& rRectangle,
201     drawing::framework::BorderType eBorderType)
202     throw(css::uno::RuntimeException)
203 {
204     ThrowIfDisposed();
205 
206     ProvideTheme();
207 
208     return AddBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
209 }
210 
211 
212 
213 
214 awt::Rectangle SAL_CALL PresenterPaneBorderPainter::removeBorder (
215     const rtl::OUString& rsPaneBorderStyleName,
216     const css::awt::Rectangle& rRectangle,
217     drawing::framework::BorderType eBorderType)
218     throw(css::uno::RuntimeException)
219 {
220     ThrowIfDisposed();
221 
222     ProvideTheme();
223 
224     return RemoveBorder(rsPaneBorderStyleName, rRectangle, eBorderType);
225 }
226 
227 
228 
229 
230 void SAL_CALL PresenterPaneBorderPainter::paintBorder (
231     const rtl::OUString& rsPaneBorderStyleName,
232     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
233     const css::awt::Rectangle& rOuterBorderRectangle,
234     const css::awt::Rectangle& rRepaintArea,
235     const rtl::OUString& rsTitle)
236     throw(css::uno::RuntimeException)
237 {
238     ThrowIfDisposed();
239 
240     // Early reject paints completely outside the repaint area.
241     if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
242         || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
243         || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
244         || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
245     {
246         return;
247     }
248     ProvideTheme(rxCanvas);
249 
250     if (mpRenderer.get() != NULL)
251     {
252         mpRenderer->SetCanvas(rxCanvas);
253         mpRenderer->SetupClipping(
254             rRepaintArea,
255             rOuterBorderRectangle,
256             rsPaneBorderStyleName);
257         mpRenderer->PaintBorder(
258             rsTitle,
259             rOuterBorderRectangle,
260             rRepaintArea,
261             rsPaneBorderStyleName);
262     }
263 }
264 
265 
266 
267 
268 void SAL_CALL PresenterPaneBorderPainter::paintBorderWithCallout (
269     const rtl::OUString& rsPaneBorderStyleName,
270     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
271     const css::awt::Rectangle& rOuterBorderRectangle,
272     const css::awt::Rectangle& rRepaintArea,
273     const rtl::OUString& rsTitle,
274     const css::awt::Point& rCalloutAnchor)
275     throw(css::uno::RuntimeException)
276 {
277     ThrowIfDisposed();
278 
279     // Early reject paints completely outside the repaint area.
280     if (rRepaintArea.X >= rOuterBorderRectangle.X+rOuterBorderRectangle.Width
281         || rRepaintArea.Y >= rOuterBorderRectangle.Y+rOuterBorderRectangle.Height
282         || rRepaintArea.X+rRepaintArea.Width <= rOuterBorderRectangle.X
283         || rRepaintArea.Y+rRepaintArea.Height <= rOuterBorderRectangle.Y)
284     {
285         return;
286     }
287     ProvideTheme(rxCanvas);
288 
289     if (mpRenderer.get() != NULL)
290     {
291         mpRenderer->SetCanvas(rxCanvas);
292         mpRenderer->SetupClipping(
293             rRepaintArea,
294             rOuterBorderRectangle,
295             rsPaneBorderStyleName);
296         mpRenderer->SetCalloutAnchor(rCalloutAnchor);
297         mpRenderer->PaintBorder(
298             rsTitle,
299             rOuterBorderRectangle,
300             rRepaintArea,
301             rsPaneBorderStyleName);
302     }
303 }
304 
305 
306 
307 
308 awt::Point SAL_CALL PresenterPaneBorderPainter::getCalloutOffset (
309     const rtl::OUString& rsPaneBorderStyleName)
310     throw(css::uno::RuntimeException)
311 {
312     ThrowIfDisposed();
313     ProvideTheme();
314     if (mpRenderer.get() != NULL)
315     {
316         const ::boost::shared_ptr<RendererPaneStyle> pRendererPaneStyle(
317             mpRenderer->GetRendererPaneStyle(rsPaneBorderStyleName));
318         if (pRendererPaneStyle.get() != NULL
319             && pRendererPaneStyle->mpBottomCallout.get() != NULL)
320         {
321             return awt::Point (
322                 0,
323                 pRendererPaneStyle->mpBottomCallout->mnHeight
324                     - pRendererPaneStyle->mpBottomCallout->mnYHotSpot);
325         }
326     }
327 
328     return awt::Point(0,0);
329 }
330 
331 
332 
333 
334 //-----------------------------------------------------------------------------
335 
336 bool PresenterPaneBorderPainter::ProvideTheme (const Reference<rendering::XCanvas>& rxCanvas)
337 {
338     bool bModified (false);
339 
340     if ( ! mxContext.is())
341         return false;
342 
343     if (mpTheme.get() != NULL)
344     {
345         // Check if the theme already has a canvas.
346         if ( ! mpTheme->HasCanvas())
347         {
348             mpTheme->ProvideCanvas(rxCanvas);
349             bModified = true;
350         }
351     }
352     else
353     {
354         mpTheme.reset(new PresenterTheme(mxContext, OUString(), rxCanvas));
355         bModified = true;
356     }
357 
358     if (mpTheme.get() != NULL && bModified)
359     {
360         if (mpRenderer.get() == NULL)
361             mpRenderer.reset(new Renderer(mxContext, mpTheme));
362         else
363             mpRenderer->SetCanvas(rxCanvas);
364     }
365 
366     return bModified;
367 }
368 
369 
370 
371 
372 bool PresenterPaneBorderPainter::ProvideTheme (void)
373 {
374     if (mpTheme.get() == NULL)
375     {
376         // Create a theme without bitmaps (no canvas => no bitmaps).
377         return ProvideTheme(NULL);
378     }
379     else
380     {
381         // When there already is a theme then without a canvas we can not
382         // add anything new.
383         return false;
384     }
385 }
386 
387 
388 
389 
390 bool PresenterPaneBorderPainter::HasTheme (void) const
391 {
392     return mpTheme.get()!=NULL && mpRenderer.get()!=NULL;
393 }
394 
395 
396 
397 
398 void PresenterPaneBorderPainter::SetTheme (const ::boost::shared_ptr<PresenterTheme>& rpTheme)
399 {
400     mpTheme = rpTheme;
401     if (mpRenderer.get() == NULL)
402         mpRenderer.reset(new Renderer(mxContext, mpTheme));
403 }
404 
405 
406 
407 
408 awt::Rectangle PresenterPaneBorderPainter::AddBorder (
409     const ::rtl::OUString& rsPaneURL,
410     const awt::Rectangle& rInnerBox,
411     const css::drawing::framework::BorderType eBorderType) const
412 {
413     if (mpRenderer.get() != NULL)
414     {
415         const ::boost::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
416         if (pRendererPaneStyle.get() != NULL)
417             return pRendererPaneStyle->AddBorder(rInnerBox, eBorderType);
418     }
419     return rInnerBox;
420 }
421 
422 
423 
424 
425 awt::Rectangle PresenterPaneBorderPainter::RemoveBorder (
426     const ::rtl::OUString& rsPaneURL,
427     const css::awt::Rectangle& rOuterBox,
428     const css::drawing::framework::BorderType eBorderType) const
429 {
430     if (mpRenderer.get() != NULL)
431     {
432         const ::boost::shared_ptr<RendererPaneStyle> pRendererPaneStyle(mpRenderer->GetRendererPaneStyle(rsPaneURL));
433         if (pRendererPaneStyle.get() != NULL)
434             return pRendererPaneStyle->RemoveBorder(rOuterBox, eBorderType);
435     }
436     return rOuterBox;
437 }
438 
439 
440 
441 
442 void PresenterPaneBorderPainter::ThrowIfDisposed (void) const
443     throw (::com::sun::star::lang::DisposedException)
444 {
445 	if (rBHelper.bDisposed || rBHelper.bInDispose)
446 	{
447         throw lang::DisposedException (
448             OUString(RTL_CONSTASCII_USTRINGPARAM(
449                 "PresenterPaneBorderPainter object has already been disposed")),
450             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
451     }
452 }
453 
454 
455 
456 
457 //===== PresenterPaneBorderPainter::Renderer =====================================
458 
459 
460 PresenterPaneBorderPainter::Renderer::Renderer (
461     const Reference<XComponentContext>& rxContext,
462     const ::boost::shared_ptr<PresenterTheme>& rpTheme)
463     : mpTheme(rpTheme),
464       maRendererPaneStyles(),
465       mxCanvas(),
466       mxPresenterHelper(),
467       maViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL),
468       mxViewStateClip(),
469       mbHasCallout(false),
470       maCalloutAnchor()
471 {
472     (void)rxContext;
473 
474     Reference<lang::XMultiComponentFactory> xFactory (rxContext->getServiceManager());
475     if (xFactory.is())
476     {
477         mxPresenterHelper = Reference<drawing::XPresenterHelper>(
478             xFactory->createInstanceWithContext(
479                 OUString::createFromAscii("com.sun.star.comp.Draw.PresenterHelper"),
480                 rxContext),
481             UNO_QUERY_THROW);
482     }
483 }
484 
485 
486 
487 
488 PresenterPaneBorderPainter::Renderer::~Renderer (void)
489 {
490 }
491 
492 
493 
494 
495 void PresenterPaneBorderPainter::Renderer::SetCanvas (const Reference<rendering::XCanvas>& rxCanvas)
496 {
497     if (mxCanvas != rxCanvas)
498     {
499         mxCanvas = rxCanvas;
500     }
501 }
502 
503 
504 
505 
506 void PresenterPaneBorderPainter::Renderer::PaintBorder (
507     const OUString& rsTitle,
508     const awt::Rectangle& rBBox,
509     const awt::Rectangle& rUpdateBox,
510     const OUString& rsPaneURL)
511 {
512     if ( ! mxCanvas.is())
513         return;
514 
515     // Create the outer and inner border of the, ahm, border.
516     ::boost::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneURL));
517     if (pStyle.get() == NULL)
518         return;
519 
520     awt::Rectangle aOuterBox (rBBox);
521     awt::Rectangle aCenterBox (
522         pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_OUTER_BORDER));
523     awt::Rectangle aInnerBox (
524         pStyle->RemoveBorder(aOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
525 
526     // Prepare references for all used bitmaps.
527     SharedBitmapDescriptor pTop (pStyle->mpTop);
528     SharedBitmapDescriptor pTopLeft (pStyle->mpTopLeft);
529     SharedBitmapDescriptor pTopRight (pStyle->mpTopRight);
530     SharedBitmapDescriptor pLeft (pStyle->mpLeft);
531     SharedBitmapDescriptor pRight (pStyle->mpRight);
532     SharedBitmapDescriptor pBottomLeft (pStyle->mpBottomLeft);
533     SharedBitmapDescriptor pBottomRight (pStyle->mpBottomRight);
534     SharedBitmapDescriptor pBottom (pStyle->mpBottom);
535     SharedBitmapDescriptor pBackground (pStyle->mpBackground);
536 
537     // Paint the sides.
538     PaintBitmap(aCenterBox, rUpdateBox, 0,-1,
539         pTopLeft->mnXOffset, pTopRight->mnXOffset, true, pTop, pBackground);
540     PaintBitmap(aCenterBox, rUpdateBox, -1,0,
541         pTopLeft->mnYOffset, pBottomLeft->mnYOffset, true, pLeft, pBackground);
542     PaintBitmap(aCenterBox, rUpdateBox, +1,0,
543         pTopRight->mnYOffset, pBottomRight->mnYOffset, true, pRight, pBackground);
544     if (mbHasCallout && pStyle->mpBottomCallout->GetNormalBitmap().is())
545     {
546         const sal_Int32 nCalloutWidth (pStyle->mpBottomCallout->mnWidth);
547         sal_Int32 nCalloutX (maCalloutAnchor.X - pStyle->mpBottomCallout->mnXHotSpot
548             - (aCenterBox.X - aOuterBox.X));
549         if (nCalloutX < pBottomLeft->mnXOffset + aCenterBox.X)
550             nCalloutX = pBottomLeft->mnXOffset + aCenterBox.X;
551         if (nCalloutX > pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width)
552             nCalloutX = pBottomRight->mnXOffset + aCenterBox.X + aCenterBox.Width;
553         // Paint bottom callout.
554         PaintBitmap(aCenterBox, rUpdateBox, 0,+1, nCalloutX,0, false, pStyle->mpBottomCallout, pBackground);
555         // Paint regular bottom bitmap left and right.
556         PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
557             pBottomLeft->mnXOffset, nCalloutX-aCenterBox.Width, true, pBottom, pBackground);
558         PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
559             nCalloutX+nCalloutWidth, pBottomRight->mnXOffset, true, pBottom, pBackground);
560     }
561     else
562     {
563         // Stretch the bottom bitmap over the full width.
564         PaintBitmap(aCenterBox, rUpdateBox, 0,+1,
565             pBottomLeft->mnXOffset, pBottomRight->mnXOffset, true, pBottom, pBackground);
566     }
567 
568     // Paint the corners.
569     PaintBitmap(aCenterBox, rUpdateBox, -1,-1, 0,0, false, pTopLeft, pBackground);
570     PaintBitmap(aCenterBox, rUpdateBox, +1,-1, 0,0, false, pTopRight, pBackground);
571     PaintBitmap(aCenterBox, rUpdateBox, -1,+1, 0,0, false, pBottomLeft, pBackground);
572     PaintBitmap(aCenterBox, rUpdateBox, +1,+1, 0,0, false, pBottomRight, pBackground);
573 
574     // Paint the title.
575     PaintTitle(rsTitle, pStyle, rUpdateBox, aOuterBox, aInnerBox, false);
576 
577     // In a double buffering environment request to make the changes visible.
578     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
579     if (xSpriteCanvas.is())
580         xSpriteCanvas->updateScreen(sal_False);
581 }
582 
583 
584 
585 
586 void PresenterPaneBorderPainter::Renderer::PaintTitle (
587     const OUString& rsTitle,
588     const ::boost::shared_ptr<RendererPaneStyle>& rpStyle,
589     const awt::Rectangle& rUpdateBox,
590     const awt::Rectangle& rOuterBox,
591     const awt::Rectangle& rInnerBox,
592     bool bPaintBackground)
593 {
594     if ( ! mxCanvas.is())
595         return;
596 
597     if (rsTitle.getLength() == 0)
598         return;
599 
600     Reference<rendering::XCanvasFont> xFont (rpStyle->GetFont(mxCanvas));
601     if ( ! xFont.is())
602         return;
603 
604     rendering::StringContext aContext (
605         rsTitle,
606         0,
607         rsTitle.getLength());
608     Reference<rendering::XTextLayout> xLayout (xFont->createTextLayout(
609         aContext,
610         rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
611         0));
612     if ( ! xLayout.is())
613         return;
614 
615     geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
616     const double nTextHeight = aBox.Y2 - aBox.Y1;
617     const double nTextWidth = aBox.X2 - aBox.X1;
618     double nX = rInnerBox.X + (rInnerBox.Width - nTextWidth)/2;
619     const sal_Int32 nTitleBarHeight = rInnerBox.Y - rOuterBox.Y - 1;
620     double nY = rOuterBox.Y + (nTitleBarHeight - nTextHeight) / 2 - aBox.Y1;
621     if (nY >= rInnerBox.Y)
622         nY = rInnerBox.Y - 1;
623     switch (rpStyle->meFontAnchor)
624     {
625         default:
626         case RendererPaneStyle::AnchorLeft:
627             nX = rInnerBox.X;
628             break;
629         case RendererPaneStyle::AnchorRight:
630             nX = rInnerBox.X + rInnerBox.Width - nTextWidth;
631             break;
632         case RendererPaneStyle::AnchorCenter:
633             nX = rInnerBox.X + (rInnerBox.Width - nTextWidth)/2;
634             break;
635     }
636     nX += rpStyle->mnFontXOffset;
637     nY += rpStyle->mnFontYOffset;
638 
639     if (rUpdateBox.X >= nX+nTextWidth
640         || rUpdateBox.Y >= nY+nTextHeight
641         || rUpdateBox.X+rUpdateBox.Width <= nX
642         || rUpdateBox.Y+rUpdateBox.Height <= nY)
643     {
644         return;
645     }
646 
647     rendering::RenderState aRenderState(
648         geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
649         NULL,
650         Sequence<double>(4),
651         rendering::CompositeOperation::SOURCE);
652 
653     if (bPaintBackground)
654     {
655         PresenterCanvasHelper::SetDeviceColor(aRenderState, util::Color(0x00ffffff));
656         Sequence<Sequence<geometry::RealPoint2D> > aPolygons(1);
657         aPolygons[0] = Sequence<geometry::RealPoint2D>(4);
658         aPolygons[0][0] = geometry::RealPoint2D(0, -nTextHeight);
659         aPolygons[0][1] = geometry::RealPoint2D(0, 0);
660         aPolygons[0][2] = geometry::RealPoint2D(nTextWidth, 0);
661         aPolygons[0][3] = geometry::RealPoint2D(nTextWidth, -nTextHeight);
662         Reference<rendering::XPolyPolygon2D> xPolygon (
663             mxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPolygons), UNO_QUERY);
664         if (xPolygon.is())
665             xPolygon->setClosed(0, sal_True);
666         mxCanvas->fillPolyPolygon(
667             xPolygon,
668             maViewState,
669             aRenderState);
670     }
671     else
672     {
673         PresenterCanvasHelper::SetDeviceColor(
674             aRenderState,
675             rpStyle->mpFont->mnColor);
676 
677         mxCanvas->drawText(
678             aContext,
679             xFont,
680             maViewState,
681             aRenderState,
682             rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
683     }
684 }
685 
686 
687 
688 ::boost::shared_ptr<RendererPaneStyle>
689     PresenterPaneBorderPainter::Renderer::GetRendererPaneStyle (const OUString& rsResourceURL)
690 {
691     OSL_ASSERT(mpTheme.get()!=NULL);
692 
693     RendererPaneStyleContainer::const_iterator iStyle (maRendererPaneStyles.find(rsResourceURL));
694     if (iStyle == maRendererPaneStyles.end())
695     {
696         OUString sPaneStyleName (OUString::createFromAscii("DefaultRendererPaneStyle"));
697 
698         // Get pane layout name for resource URL.
699         const OUString sStyleName (mpTheme->GetStyleName(rsResourceURL));
700         if (sStyleName.getLength() > 0)
701             sPaneStyleName = sStyleName;
702 
703         // Create a new pane style object and initialize it with bitmaps.
704         ::boost::shared_ptr<RendererPaneStyle> pStyle (
705             new RendererPaneStyle(mpTheme,sPaneStyleName));
706         iStyle = maRendererPaneStyles.insert(
707             RendererPaneStyleContainer::value_type(rsResourceURL, pStyle)).first;
708     }
709     if (iStyle != maRendererPaneStyles.end())
710         return iStyle->second;
711     else
712         return ::boost::shared_ptr<RendererPaneStyle>();
713 }
714 
715 
716 
717 
718 void PresenterPaneBorderPainter::Renderer::SetCalloutAnchor (
719     const awt::Point& rCalloutAnchor)
720 {
721     mbHasCallout = true;
722     maCalloutAnchor = rCalloutAnchor;
723 }
724 
725 
726 
727 
728 void PresenterPaneBorderPainter::Renderer::PaintBitmap(
729     const awt::Rectangle& rBox,
730     const awt::Rectangle& rUpdateBox,
731     const sal_Int32 nXPosition,
732     const sal_Int32 nYPosition,
733     const sal_Int32 nStartOffset,
734     const sal_Int32 nEndOffset,
735     const bool bExpand,
736     const SharedBitmapDescriptor& rpBitmap,
737     const SharedBitmapDescriptor& rpBackgroundBitmap)
738 {
739     (void)rpBackgroundBitmap;
740 
741     bool bUseCanvas (mxCanvas.is());
742     if ( ! bUseCanvas)
743         return;
744 
745     if (rpBitmap->mnWidth<=0 || rpBitmap->mnHeight<=0)
746         return;
747 
748     Reference<rendering::XBitmap> xBitmap (rpBitmap->GetNormalBitmap(), UNO_QUERY);
749     if ( ! xBitmap.is())
750         return;
751 
752     // Calculate position, and for side bitmaps, the size.
753     sal_Int32 nX = 0;
754     sal_Int32 nY = 0;
755     sal_Int32 nW = rpBitmap->mnWidth;
756     sal_Int32 nH = rpBitmap->mnHeight;
757     if (nXPosition < 0)
758     {
759         nX = rBox.X - rpBitmap->mnWidth + rpBitmap->mnXOffset;
760     }
761     else if (nXPosition > 0)
762     {
763         nX = rBox.X + rBox.Width + rpBitmap->mnXOffset;
764     }
765     else
766     {
767         nX = rBox.X + nStartOffset;
768         if (bExpand)
769             nW = rBox.Width - nStartOffset + nEndOffset;
770     }
771 
772     if (nYPosition < 0)
773     {
774         nY = rBox.Y - rpBitmap->mnHeight + rpBitmap->mnYOffset;
775     }
776     else if (nYPosition > 0)
777     {
778         nY = rBox.Y + rBox.Height + rpBitmap->mnYOffset;
779     }
780     else
781     {
782         nY = rBox.Y + nStartOffset;
783         if (bExpand)
784             nH = rBox.Height - nStartOffset + nEndOffset;
785     }
786 
787     // Do not paint when bitmap area does not intersect with update box.
788     if (nX >= rUpdateBox.X + rUpdateBox.Width
789         || nX+nW <= rUpdateBox.X
790         || nY >= rUpdateBox.Y + rUpdateBox.Height
791         || nY+nH <= rUpdateBox.Y)
792     {
793         return;
794     }
795 
796     /*
797     Reference<rendering::XBitmap> xMaskedBitmap (
798         PresenterBitmapHelper::FillMaskedWithColor (
799             mxCanvas,
800             Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
801             rBitmap.mxMaskBitmap,
802             0x00ff0000,
803             rBackgroundBitmap.maReplacementColor));
804     if (xMaskedBitmap.is())
805         xBitmap = xMaskedBitmap;
806     else if (rBitmap.mxMaskBitmap.is() && mxPresenterHelper.is())
807     {
808         const static sal_Int32 nOutsideMaskColor (0x00ff0000);
809         Reference<rendering::XIntegerBitmap> xMask (
810             mxPresenterHelper->createMask(
811                 mxCanvas,
812                 rBitmap.mxMaskBitmap,
813                 nOutsideMaskColor,
814                 false));
815         xBitmap = mxPresenterHelper->applyBitmapMaskWithColor(
816             mxCanvas,
817             Reference<rendering::XIntegerBitmap>(xBitmap, UNO_QUERY),
818             xMask,
819             rBackgroundBitmap.maReplacementColor);
820     }
821     */
822     rendering::RenderState aRenderState (
823         geometry::AffineMatrix2D(
824             double(nW)/rpBitmap->mnWidth, 0, nX,
825             0, double(nH)/rpBitmap->mnHeight, nY),
826         NULL,
827         Sequence<double>(4),
828         rendering::CompositeOperation::OVER);
829 
830     if (xBitmap.is())
831         mxCanvas->drawBitmap(
832             xBitmap,
833             maViewState,
834             aRenderState);
835 }
836 
837 
838 
839 
840 void PresenterPaneBorderPainter::Renderer::SetupClipping (
841     const awt::Rectangle& rUpdateBox,
842     const awt::Rectangle& rOuterBox,
843     const OUString& rsPaneStyleName)
844 {
845     mxViewStateClip = NULL;
846     maViewState.Clip = NULL;
847 
848     if ( ! mxCanvas.is())
849         return;
850 
851     ::boost::shared_ptr<RendererPaneStyle> pStyle (GetRendererPaneStyle(rsPaneStyleName));
852     if (pStyle.get() == NULL)
853     {
854         mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
855             rUpdateBox,
856             mxCanvas->getDevice());
857     }
858     else
859     {
860         awt::Rectangle aInnerBox (
861             pStyle->RemoveBorder(rOuterBox, drawing::framework::BorderType_TOTAL_BORDER));
862         ::std::vector<awt::Rectangle> aRectangles;
863         aRectangles.push_back(PresenterGeometryHelper::Intersection(rUpdateBox, rOuterBox));
864         aRectangles.push_back(PresenterGeometryHelper::Intersection(rUpdateBox, aInnerBox));
865         mxViewStateClip = PresenterGeometryHelper::CreatePolygon(
866             aRectangles,
867             mxCanvas->getDevice());
868         if (mxViewStateClip.is())
869             mxViewStateClip->setFillRule(rendering::FillRule_EVEN_ODD);
870     }
871     maViewState.Clip = mxViewStateClip;
872 }
873 
874 
875 
876 namespace {
877 
878 //===== BorderSize ============================================================
879 
880 BorderSize::BorderSize (void)
881     : mnLeft(0),
882       mnTop(0),
883       mnRight(0),
884       mnBottom(0)
885 {
886 }
887 
888 
889 
890 
891 BorderSize::BorderSize (const BorderSize& rBorderSize)
892     : mnLeft(rBorderSize.mnLeft),
893       mnTop(rBorderSize.mnTop),
894       mnRight(rBorderSize.mnRight),
895       mnBottom(rBorderSize.mnBottom)
896 {
897 }
898 
899 
900 
901 
902 BorderSize& BorderSize::operator= (const BorderSize& rBorderSize)
903 {
904     if (&rBorderSize != this)
905     {
906         mnLeft = rBorderSize.mnLeft;
907         mnTop = rBorderSize.mnTop;
908         mnRight = rBorderSize.mnRight;
909         mnBottom = rBorderSize.mnBottom;
910     }
911     return *this;
912 }
913 
914 
915 
916 
917 //===== RendererPaneStyle  ============================================================
918 
919 RendererPaneStyle::RendererPaneStyle (
920     const ::boost::shared_ptr<PresenterTheme>& rpTheme,
921     const OUString& rsStyleName)
922     : mpTopLeft(),
923       mpTop(),
924       mpTopRight(),
925       mpLeft(),
926       mpRight(),
927       mpBottomLeft(),
928       mpBottom(),
929       mpBottomRight(),
930       mpBottomCallout(),
931       mpBackground(),
932       mpEmpty(new PresenterBitmapDescriptor()),
933       mpFont(),
934       mnFontXOffset(0),
935       mnFontYOffset(0),
936       meFontAnchor(AnchorCenter),
937       maInnerBorderSize(),
938       maOuterBorderSize(),
939       maTotalBorderSize()
940 {
941     if (rpTheme.get() != NULL)
942     {
943         mpTopLeft = GetBitmap(rpTheme, rsStyleName, A2S("TopLeft"));
944         mpTop = GetBitmap(rpTheme, rsStyleName,  A2S("Top"));
945         mpTopRight = GetBitmap(rpTheme, rsStyleName,  A2S("TopRight"));
946         mpLeft = GetBitmap(rpTheme, rsStyleName, A2S("Left"));
947         mpRight = GetBitmap(rpTheme, rsStyleName,  A2S("Right"));
948         mpBottomLeft = GetBitmap(rpTheme, rsStyleName, A2S("BottomLeft"));
949         mpBottom = GetBitmap(rpTheme, rsStyleName,  A2S("Bottom"));
950         mpBottomRight = GetBitmap(rpTheme, rsStyleName,  A2S("BottomRight"));
951         mpBottomCallout = GetBitmap(rpTheme, rsStyleName,  A2S("BottomCallout"));
952         mpBackground = GetBitmap(rpTheme, OUString(), A2S("Background"));
953 
954         // Get font description.
955         mpFont = rpTheme->GetFont(rsStyleName);
956 
957         OUString sAnchor (OUString::createFromAscii("Left"));
958         if (mpFont.get() != NULL)
959         {
960             sAnchor = mpFont->msAnchor;
961             mnFontXOffset = mpFont->mnXOffset;
962             mnFontYOffset = mpFont->mnYOffset;
963         }
964 
965         if (sAnchor == OUString::createFromAscii("Left"))
966             meFontAnchor = AnchorLeft;
967         else if (sAnchor == OUString::createFromAscii("Right"))
968             meFontAnchor = AnchorRight;
969         else if (sAnchor == OUString::createFromAscii("Center"))
970             meFontAnchor = AnchorCenter;
971         else
972             meFontAnchor = AnchorCenter;
973 
974         // Get border sizes.
975         try
976         {
977             ::std::vector<sal_Int32> aInnerBorder (rpTheme->GetBorderSize(rsStyleName, false));
978             OSL_ASSERT(aInnerBorder.size()==4);
979             maInnerBorderSize.mnLeft = aInnerBorder[0];
980             maInnerBorderSize.mnTop = aInnerBorder[1];
981             maInnerBorderSize.mnRight = aInnerBorder[2];
982             maInnerBorderSize.mnBottom = aInnerBorder[3];
983 
984             ::std::vector<sal_Int32> aOuterBorder (rpTheme->GetBorderSize(rsStyleName, true));
985             OSL_ASSERT(aOuterBorder.size()==4);
986             maOuterBorderSize.mnLeft = aOuterBorder[0];
987             maOuterBorderSize.mnTop = aOuterBorder[1];
988             maOuterBorderSize.mnRight = aOuterBorder[2];
989             maOuterBorderSize.mnBottom = aOuterBorder[3];
990         }
991         catch(beans::UnknownPropertyException&)
992         {
993             OSL_ASSERT(false);
994         }
995 
996         UpdateBorderSizes();
997     }
998 }
999 
1000 
1001 
1002 
1003 
1004 awt::Rectangle RendererPaneStyle::AddBorder (
1005     const awt::Rectangle& rBox,
1006     const drawing::framework::BorderType eBorderType) const
1007 {
1008     const BorderSize* pBorderSize = NULL;
1009     switch (eBorderType)
1010     {
1011         case drawing::framework::BorderType_INNER_BORDER:
1012             pBorderSize = &maInnerBorderSize;
1013             break;
1014         case drawing::framework::BorderType_OUTER_BORDER:
1015             pBorderSize = &maOuterBorderSize;
1016             break;
1017         case drawing::framework::BorderType_TOTAL_BORDER:
1018             pBorderSize = &maTotalBorderSize;
1019             break;
1020         default:
1021             return rBox;
1022     }
1023     return awt::Rectangle (
1024         rBox.X - pBorderSize->mnLeft,
1025         rBox.Y - pBorderSize->mnTop,
1026         rBox.Width + pBorderSize->mnLeft + pBorderSize->mnRight,
1027         rBox.Height + pBorderSize->mnTop + pBorderSize->mnBottom);
1028 }
1029 
1030 
1031 
1032 
1033 awt::Rectangle RendererPaneStyle::RemoveBorder (
1034     const awt::Rectangle& rBox,
1035     const css::drawing::framework::BorderType eBorderType) const
1036 {
1037     const BorderSize* pBorderSize = NULL;
1038     switch (eBorderType)
1039     {
1040         case drawing::framework::BorderType_INNER_BORDER:
1041             pBorderSize = &maInnerBorderSize;
1042             break;
1043         case drawing::framework::BorderType_OUTER_BORDER:
1044             pBorderSize = &maOuterBorderSize;
1045             break;
1046         case drawing::framework::BorderType_TOTAL_BORDER:
1047             pBorderSize = &maTotalBorderSize;
1048             break;
1049         default:
1050             return rBox;
1051     }
1052     return awt::Rectangle (
1053         rBox.X + pBorderSize->mnLeft,
1054         rBox.Y + pBorderSize->mnTop,
1055         rBox.Width - pBorderSize->mnLeft - pBorderSize->mnRight,
1056         rBox.Height - pBorderSize->mnTop - pBorderSize->mnBottom);
1057 }
1058 
1059 
1060 
1061 
1062 const Reference<rendering::XCanvasFont> RendererPaneStyle::GetFont (
1063     const Reference<rendering::XCanvas>& rxCanvas) const
1064 {
1065     if (mpFont.get() != NULL)
1066         mpFont->PrepareFont(rxCanvas);
1067     return mpFont->mxFont;
1068 }
1069 
1070 
1071 
1072 
1073 void RendererPaneStyle::UpdateBorderSizes (void)
1074 {
1075     maTotalBorderSize.mnLeft = maInnerBorderSize.mnLeft + maOuterBorderSize.mnLeft;
1076     maTotalBorderSize.mnTop = maInnerBorderSize.mnTop + maOuterBorderSize.mnTop;
1077     maTotalBorderSize.mnRight = maInnerBorderSize.mnRight + maOuterBorderSize.mnRight;
1078     maTotalBorderSize.mnBottom = maInnerBorderSize.mnBottom + maOuterBorderSize.mnBottom;
1079 }
1080 
1081 
1082 
1083 
1084 SharedBitmapDescriptor RendererPaneStyle::GetBitmap(
1085     const ::boost::shared_ptr<PresenterTheme>& rpTheme,
1086     const OUString& rsStyleName,
1087     const OUString& rsBitmapName)
1088 {
1089     SharedBitmapDescriptor pDescriptor (rpTheme->GetBitmap(rsStyleName, rsBitmapName));
1090     if (pDescriptor.get() != NULL)
1091         return pDescriptor;
1092     else
1093         return mpEmpty;
1094 }
1095 
1096 
1097 
1098 } // end of anonymous namespace
1099 
1100 
1101 } } // end of namespace ::sd::presenter
1102