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