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 "PresenterClock.hxx"
28 #include "PresenterComponent.hxx"
29 #include "PresenterConfigurationAccess.hxx"
30 #include "PresenterGeometryHelper.hxx"
31 #include <com/sun/star/awt/InvalidateStyle.hpp>
32 #include <com/sun/star/awt/MouseButton.hpp>
33 #include <com/sun/star/awt/Point.hpp>
34 #include <com/sun/star/awt/XWindowPeer.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
37 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
38 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
39 #include <com/sun/star/rendering/CompositeOperation.hpp>
40 #include <com/sun/star/rendering/PathCapType.hpp>
41 #include <com/sun/star/rendering/TextDirection.hpp>
42 #include <com/sun/star/rendering/XCanvasFont.hpp>
43 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
44 #include <com/sun/star/util/Color.hpp>
45 #include <osl/mutex.hxx>
46 #include <osl/time.h>
47 #include <rtl/ref.hxx>
48 #include <vos/timer.hxx>
49 #include <boost/bind.hpp>
50 #include <cmath>
51 
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::drawing::framework;
55 using ::rtl::OUString;
56 
57 namespace sdext { namespace presenter {
58 
59 
60 /** Wrapper around a library timer.
61 */
62 class PresenterClock::Timer : public vos::OTimer
63 {
64 public:
65     explicit Timer (const ::rtl::Reference<PresenterClock>& rpClock);
66     virtual ~Timer (void);
67 
68     void Stop (void);
69 
70 protected:
71     virtual void SAL_CALL onShot (void);
72 
73 private:
74     ::rtl::Reference<PresenterClock> mpClock;
75 };
76 
77 
78 
79 
80 namespace {
81     bool GetDateTime (oslDateTime& rDateTime);
82 
83     class BitmapDescriptor
84     {
85     public:
86         Reference<rendering::XBitmap> mxBitmap;
87         awt::Point maOffset;
88         Reference<rendering::XBitmap> mxScaledBitmap;
89         geometry::RealPoint2D maScaledOffset;
90     };
91 }
92 
93 
94 
95 
96 class PresenterClock::Painter
97 {
98 public:
99     virtual void Paint (
100         const Reference<rendering::XCanvas>& rxCanvas,
101         const rendering::ViewState& rViewState,
102         const rendering::RenderState& rRenderState,
103         const util::Color& rBackgroundColor,
104         const sal_Int32 nHour,
105         const sal_Int32 nMinute,
106         const sal_Int32 nSecond,
107         const bool bShowSeconds) = 0;
108     virtual void Resize (const awt::Size& rSize) = 0;
109 };
110 
111 
112 
113 
114 namespace {
115     class AnalogDefaultPainter : public PresenterClock::Painter
116     {
117     public:
118         AnalogDefaultPainter (void);
119         virtual ~AnalogDefaultPainter (void) {}
120         virtual void Paint (
121             const Reference<rendering::XCanvas>& rxCanvas,
122             const rendering::ViewState& rViewState,
123             const rendering::RenderState& rRenderState,
124             const util::Color& rBackgroundColor,
125             const sal_Int32 nHour,
126             const sal_Int32 nMinute,
127             const sal_Int32 nSecond,
128             const bool bShowSeconds);
129         virtual void Resize (const awt::Size& rSize);
130     private:
131         geometry::RealPoint2D maCenter;
132         double mnOuterRadius;
133         awt::Size maSize;
134         Reference<rendering::XBitmap> mxBitmap;
135 
136         /** Relative length (with respect to radius) from center to the tip of
137             the hand.
138         */
139         static const double mnRelativeHourHandLength;
140         /** Relative length (with respect to radius) from center to the
141             oposing end of the tip of the hand.
142         */
143         static const double mnRelativeHourHandLength2;
144         static const double mnRelativeHourHandWidth;
145         static const double mnRelativeMinuteHandLength;
146         static const double mnRelativeMinuteHandLength2;
147         static const double mnRelativeMinuteHandWidth;
148         static const double mnRelativeSecondHandLength;
149         static const double mnRelativeSecondHandLength2;
150         static const double mnRelativeSecondHandWidth;
151 
152         void PaintAngledLine (
153             const double nAngle,
154             const double nInnerRadius,
155             const double nOuterRadius,
156             const double nStrokeWidth,
157             const Reference<rendering::XCanvas>& rxCanvas,
158             const rendering::ViewState& rViewState,
159             const rendering::RenderState& rRenderState);
160     };
161 
162 
163     class AnalogBitmapPainter : public PresenterClock::Painter
164     {
165     public:
166         AnalogBitmapPainter(
167             const Reference<XComponentContext>& rxContext,
168             const OUString& rsThemeName);
169         virtual ~AnalogBitmapPainter (void) {}
170         virtual void Paint (
171             const Reference<rendering::XCanvas>& rxCanvas,
172             const rendering::ViewState& rViewState,
173             const rendering::RenderState& rRenderState,
174             const util::Color& rBackgroundColor,
175             const sal_Int32 nHour,
176             const sal_Int32 nMinute,
177             const sal_Int32 nSecond,
178             const bool bShowSeconds);
179         virtual void Resize (const awt::Size& rSize);
180     private:
181         css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
182         const OUString msThemeName;
183         bool mbThemeLoaded;
184         bool mbThemeLoadingFailed;
185         geometry::RealPoint2D maCenter;
186         double mnOuterRadius;
187         BitmapDescriptor maFace;
188         BitmapDescriptor maMinuteHand;
189         BitmapDescriptor maHourHand;
190 
191         void PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas);
192         Reference<container::XNameAccess> GetTheme (
193             PresenterConfigurationAccess& rConfiguration);
194         bool ThemeNameComparator (
195             const ::rtl::OUString& rsKey,
196             const Reference<container::XNameAccess>& rxCandidate,
197             const ::rtl::OUString& rsCurrentThemeName);
198         void LoadBitmaps (
199             PresenterConfigurationAccess& rConfiguration,
200             const Reference<container::XNameAccess>& rxNameAccess,
201             const Reference<rendering::XCanvas>& rxCanvas);
202         void LoadBitmap (
203             const OUString& rsKey,
204             const ::std::vector<Any>& rValues,
205             const OUString& rsBitmapPath,
206             const Reference<container::XNameAccess>& rxBitmapLoader);
207         void ScaleBitmaps (void);
208     };
209 
210 
211     class DigitalDefaultPainter : public PresenterClock::Painter
212     {
213     public:
214         DigitalDefaultPainter (
215             const ::rtl::Reference<PresenterController>& rpPresenterController,
216             const Reference<XResourceId>& rxViewId);
217         virtual ~DigitalDefaultPainter (void);
218 
219         virtual void Paint (
220             const Reference<rendering::XCanvas>& rxCanvas,
221             const rendering::ViewState& rViewState,
222             const rendering::RenderState& rRenderState,
223             const util::Color& rBackgroundColor,
224             const sal_Int32 nHour,
225             const sal_Int32 nMinute,
226             const sal_Int32 nSecond,
227             const bool bShowSeconds);
228         virtual void Resize (const awt::Size& rSize);
229 
230     private:
231         ::rtl::Reference<PresenterController> mpPresenterController;
232         bool mbIs24HourFormat;
233         bool mbIsAdaptFontSize;
234         Reference<rendering::XCanvasFont> mxFont;
235         awt::Size maWindowSize;
236         OUString msViewURL;
237 
238         void CreateFont (
239             const Reference<rendering::XCanvas>& rxCanvas,
240             const bool bIsShowSeconds);
241     };
242 
243 
244 } // end of anonymous namespace
245 
246 
247 
248 
249 //===== PresenterClock =================================================================
250 
251 ::rtl::Reference<PresenterClock> PresenterClock::Create (
252     const Reference<XComponentContext>& rxContext,
253     const Reference<XResourceId>& rxViewId,
254     const Reference<frame::XController>& rxController,
255     const ::rtl::Reference<PresenterController>& rpPresenterController)
256 {
257     ::rtl::Reference<PresenterClock> pClock (new PresenterClock(
258         rxContext,
259         rxViewId,
260         rxController,
261         rpPresenterController));
262     pClock->LateInit();
263     return pClock;
264 }
265 
266 
267 
268 
269 PresenterClock::PresenterClock (
270     const Reference<XComponentContext>& rxContext,
271     const Reference<XResourceId>& rxViewId,
272     const Reference<frame::XController>& rxController,
273     const ::rtl::Reference<PresenterController>& rpPresenterController)
274     : PresenterClockInterfaceBase(m_aMutex),
275       mxComponentContext(rxContext),
276       mxViewId(rxViewId),
277       mxWindow(),
278       mxCanvas(),
279       mxPane(),
280       mpPresenterController(rpPresenterController),
281       mbIsResizePending(true),
282       maViewState(),
283       maRenderState(),
284       mpTimer(),
285       mpClockPainter(),
286       mpClockPainter2(),
287       mnMode(1),
288       mnHour(-1),
289       mnMinute(-1),
290       mnSecond(-1),
291       mbIsShowSeconds(true)
292 {
293     SetMode(mnMode);
294 
295     maViewState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
296     maRenderState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
297     maRenderState.DeviceColor = Sequence<double>(4);
298     PresenterCanvasHelper::SetDeviceColor(maRenderState, util::Color(0x00000000));
299 
300     try
301     {
302 
303         Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
304         Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW);
305         mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
306 
307         mxWindow = mxPane->getWindow();
308         if (mxWindow.is())
309         {
310             mxWindow->addPaintListener(this);
311             mxWindow->addWindowListener(this);
312             mxWindow->addMouseListener(this);
313             Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
314             if (xPeer.is())
315                 xPeer->setBackground(util::Color(0xff000000));
316             mxWindow->setVisible(sal_True);
317         }
318 
319         Resize();
320     }
321     catch (RuntimeException&)
322     {
323         disposing();
324         throw;
325     }
326 }
327 
328 
329 
330 
331 PresenterClock::~PresenterClock (void)
332 {
333 }
334 
335 
336 
337 
338 void PresenterClock::LateInit (void)
339 {
340     mpTimer = new Timer(this);
341 }
342 
343 
344 
345 
346 void SAL_CALL PresenterClock::disposing (void)
347 {
348     //    osl::MutexGuard aGuard (m_aMutex);
349     if (mpTimer != NULL)
350     {
351         mpTimer->Stop();
352     }
353     if (mxWindow.is())
354     {
355         mxWindow->removePaintListener(this);
356         mxWindow->removeWindowListener(this);
357         mxWindow->removeMouseListener(this);
358         mxWindow = NULL;
359     }
360     mxCanvas = NULL;
361     mxViewId = NULL;
362 }
363 
364 
365 
366 
367 void PresenterClock::UpdateTime (void)
368 {
369     // Get current time and check whether it is different from last time.
370     oslDateTime aDateTime;
371     if ( ! GetDateTime(aDateTime))
372         return;
373     if (aDateTime.Hours != mnHour
374         || aDateTime.Minutes != mnMinute
375         || aDateTime.Seconds != mnSecond)
376     {
377         mnHour = aDateTime.Hours % 24;
378         mnMinute = aDateTime.Minutes % 60;
379         mnSecond = aDateTime.Seconds % 60;
380 
381         Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
382         if (xPeer.is())
383             xPeer->invalidate(awt::InvalidateStyle::NOERASE |
384             awt::InvalidateStyle::UPDATE);
385     }
386 }
387 
388 
389 
390 
391 //-----  lang::XEventListener -------------------------------------------------
392 
393 void SAL_CALL PresenterClock::disposing (const lang::EventObject& rEventObject)
394     throw (RuntimeException)
395 {
396     //    ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
397     //    osl::MutexGuard aGuard (m_aMutex);
398 
399     if (rEventObject.Source == mxWindow)
400     {
401         mxWindow = NULL;
402         if (mpTimer != NULL)
403             mpTimer->Stop();
404     }
405 }
406 
407 
408 
409 
410 //----- XPaintListener --------------------------------------------------------
411 
412 void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent)
413     throw (RuntimeException)
414 {
415     (void)rEvent;
416     ThrowIfDisposed();
417     ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
418     Paint(rEvent.UpdateRect);
419 }
420 
421 
422 
423 
424 //----- XWindowListener -------------------------------------------------------
425 
426 void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent)
427     throw (RuntimeException)
428 {
429     (void)rEvent;
430     mbIsResizePending = true;
431 }
432 
433 
434 
435 
436 void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent)
437     throw (RuntimeException)
438 {
439     (void)rEvent;
440     mbIsResizePending = true;
441 }
442 
443 
444 
445 
446 void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent)
447     throw (RuntimeException)
448 {
449     (void)rEvent;
450     mbIsResizePending = true;
451 }
452 
453 
454 
455 
456 void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent)
457     throw (RuntimeException)
458 {
459     (void)rEvent;
460 }
461 
462 
463 
464 
465 //----- XMouseListener --------------------------------------------------------
466 
467 void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent)
468     throw (css::uno::RuntimeException)
469 {
470     (void)rEvent;
471     if (rEvent.Buttons == awt::MouseButton::LEFT)
472     {
473         SetMode(mnMode+1);
474     }
475 }
476 
477 
478 
479 
480 void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent)
481     throw (css::uno::RuntimeException)
482 {
483     (void)rEvent;
484 }
485 
486 
487 
488 
489 void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent)
490     throw (css::uno::RuntimeException)
491 {
492     (void)rEvent;
493 }
494 
495 
496 
497 
498 void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent)
499     throw (css::uno::RuntimeException)
500 {
501     (void)rEvent;
502 }
503 
504 
505 
506 
507 //----- XResourceId -----------------------------------------------------------
508 
509 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void)
510     throw (RuntimeException)
511 {
512     return mxViewId;
513 }
514 
515 
516 
517 
518 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void)
519     throw (RuntimeException)
520 {
521     return false;
522 }
523 
524 
525 
526 
527 //-----------------------------------------------------------------------------
528 
529 void PresenterClock::Resize (void)
530 {
531     if (mxPane.is())
532         mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
533     if (mxWindow.is() && mxCanvas.is())
534     {
535         const awt::Rectangle aWindowBox (mxWindow->getPosSize());
536         const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height);
537         if (mpClockPainter.get() != NULL)
538             mpClockPainter->Resize(aWindowSize);
539         if (mpClockPainter2.get() != NULL)
540             mpClockPainter2->Resize(aWindowSize);
541         mbIsResizePending = false;
542     }
543 }
544 
545 
546 
547 
548 void PresenterClock::Paint (const awt::Rectangle& rUpdateBox)
549 {
550     if ( ! mxCanvas.is() && mxPane.is())
551         mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
552     if ( ! mxWindow.is()
553         || ! mxCanvas.is()
554         || ! mxCanvas->getDevice().is())
555     {
556         return;
557     }
558 
559     try
560     {
561         if (mbIsResizePending)
562             Resize();
563 
564         Reference<rendering::XPolyPolygon2D> xUpdatePolygon (
565             PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
566 
567         Clear(xUpdatePolygon);
568 
569         if (mpClockPainter.get() != NULL)
570             mpClockPainter->Paint(mxCanvas,
571                 maViewState,
572                 maRenderState,
573                 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
574                 mnHour,
575                 mnMinute,
576                 mnSecond,
577                 mbIsShowSeconds);
578 
579         if (mpClockPainter2.get() != NULL)
580             mpClockPainter2->Paint(
581                 mxCanvas,
582                 maViewState,
583                 maRenderState,
584                 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
585                 mnHour,
586                 mnMinute,
587                 mnSecond,
588                 mbIsShowSeconds);
589     }
590     catch (RuntimeException& e)
591     {
592         (void)e;
593     }
594 
595     // Make the back buffer visible.
596     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
597     if (xSpriteCanvas.is())
598         xSpriteCanvas->updateScreen(sal_False);
599 }
600 
601 
602 
603 
604 void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon)
605 {
606     rendering::RenderState aRenderState = maRenderState;
607     const sal_Int32 nColor (
608         mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()));
609     aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0;
610     aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >>  8) / 255.0;
611     aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >>  0) / 255.0;
612 
613     if (rxUpdatePolygon.is())
614         mxCanvas->fillPolyPolygon(
615             rxUpdatePolygon,
616             maViewState,
617             aRenderState);
618 }
619 
620 
621 
622 
623 void PresenterClock::SetMode (const sal_Int32 nMode)
624 {
625     mnMode = nMode % 3;
626 
627     switch (mnMode)
628     {
629         case 0:
630             mpClockPainter.reset(
631                 new AnalogBitmapPainter(
632                     mxComponentContext,
633                     OUString::createFromAscii("ClockTheme")));
634             mpClockPainter2.reset();
635             break;
636 
637         case 1:
638             mpClockPainter.reset();
639             mpClockPainter2.reset(new AnalogDefaultPainter());
640             break;
641 
642         case 2:
643             mpClockPainter.reset();
644             mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId));
645             break;
646 
647         case 3:
648             mpClockPainter.reset(
649                 new AnalogBitmapPainter(
650                     mxComponentContext,
651                     OUString::createFromAscii("ClockTheme")));
652             mpClockPainter2.reset(new AnalogDefaultPainter());
653             break;
654     }
655     Resize();
656 }
657 
658 
659 
660 
661 void PresenterClock::ThrowIfDisposed (void)
662     throw (::com::sun::star::lang::DisposedException)
663 {
664 	if (rBHelper.bDisposed || rBHelper.bInDispose)
665 	{
666         throw lang::DisposedException (
667             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
668                 "PresenterClock object has already been disposed")),
669             static_cast<uno::XWeak*>(this));
670     }
671 }
672 
673 
674 
675 
676 //===== Timer =================================================================
677 
678 PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock)
679     : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)),
680       mpClock(rpClock)
681 {
682     acquire();
683     start();
684 }
685 
686 
687 
688 
689 PresenterClock::Timer::~Timer (void)
690 {
691     if (mpClock.is())
692         Stop();
693 }
694 
695 
696 
697 
698 void PresenterClock::Timer::Stop (void)
699 {
700     mpClock = NULL;
701     stop();
702     release();
703 }
704 
705 
706 
707 
708 void SAL_CALL PresenterClock::Timer::onShot (void)
709 {
710     if (mpClock.get() != NULL)
711         mpClock->UpdateTime();
712 }
713 
714 
715 
716 namespace {
717 
718 //=============================================================================
719 
720 bool GetDateTime (oslDateTime& rDateTime)
721 {
722     TimeValue aSystemTime;
723     TimeValue aLocalTime;
724     if (osl_getSystemTime(&aSystemTime))
725         if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime))
726             if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime))
727                 return true;
728     return false;
729 }
730 
731 
732 
733 
734 //===== AnalogDefaultPainter ==================================================
735 
736 const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65;
737 const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1);
738 const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055);
739 const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2);
740 const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85);
741 const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025);
742 const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25);
743 const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95);
744 const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015);
745 
746 AnalogDefaultPainter::AnalogDefaultPainter (void)
747     : maCenter(0,0),
748       mnOuterRadius(0),
749       maSize(0,0),
750       mxBitmap()
751 {
752 }
753 
754 
755 
756 
757 void AnalogDefaultPainter::Paint (
758     const Reference<rendering::XCanvas>& rxCanvas,
759     const rendering::ViewState& rViewState,
760     const rendering::RenderState& rRenderState,
761     const util::Color& rBackgroundColor,
762     const sal_Int32 nHour,
763     const sal_Int32 nMinute,
764     const sal_Int32 nSecond,
765     const bool bShowSeconds)
766 {
767     double nInnerRadius (0);
768     double nStrokeWidth (0.1);
769     const double nClockSize (2*mnOuterRadius);
770 
771     // Some antialiasing is created by painting into a bitmap twice the
772     // screen size and then scaling it down.
773     const sal_Int32 nSuperSampleFactor (2);
774     if ( ! mxBitmap.is())
775     {
776         mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap(
777             geometry::IntegerSize2D(
778                 maSize.Width*nSuperSampleFactor,
779                 maSize.Height*nSuperSampleFactor)));
780     }
781     Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY);
782     rendering::RenderState aRenderState(rRenderState);
783     aRenderState.AffineTransform.m00 = nSuperSampleFactor;
784     aRenderState.AffineTransform.m11 = nSuperSampleFactor;
785 
786     // Clear the background.
787     aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0;
788     aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >>  8) / 255.0;
789     aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >>  0) / 255.0;
790     Reference<rendering::XPolyPolygon2D> xPolygon (
791         PresenterGeometryHelper::CreatePolygon(
792             awt::Rectangle(0,0,maSize.Width,maSize.Height),
793             xBitmapCanvas->getDevice()));
794     if (xPolygon.is())
795         xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState);
796 
797     // Clock face and clock hands are painted in black.
798     aRenderState.DeviceColor[0] = 0;
799     aRenderState.DeviceColor[1] = 0;
800     aRenderState.DeviceColor[2] = 0;
801 
802     // Paint the clock face.
803     for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark)
804     {
805         if (nHourMark%3 == 0)
806         {
807             nInnerRadius = 0.7 * mnOuterRadius;
808             nStrokeWidth = 0.05 * nClockSize;
809         }
810         else
811         {
812             nInnerRadius = 0.8 * mnOuterRadius;
813             nStrokeWidth = 0.03 * nClockSize;
814         }
815 
816         const double nAngle (nHourMark * 2 * M_PI / 12);
817         PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth,
818             xBitmapCanvas, rViewState, aRenderState);
819     }
820 
821     // Paint the hour hand.
822     const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12);
823     PaintAngledLine(nHoursAngle,
824         mnRelativeHourHandLength2*mnOuterRadius,
825         mnRelativeHourHandLength*mnOuterRadius,
826         mnRelativeHourHandWidth*nClockSize,
827         xBitmapCanvas, rViewState, aRenderState);
828 
829     // Paint the minute hand.
830     const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60);
831     PaintAngledLine(nMinutesAngle,
832         mnRelativeMinuteHandLength2*mnOuterRadius,
833         mnRelativeMinuteHandLength*mnOuterRadius,
834         mnRelativeMinuteHandWidth*nClockSize,
835         xBitmapCanvas, rViewState, aRenderState);
836 
837     // Optionally paint the second hand.
838     if (bShowSeconds)
839     {
840         const double nSecondsAngle (nSecond * 2 * M_PI / 60);
841         PaintAngledLine(nSecondsAngle,
842             mnRelativeSecondHandLength2*mnOuterRadius,
843             mnRelativeSecondHandLength*mnOuterRadius,
844             mnRelativeSecondHandWidth*nClockSize,
845             xBitmapCanvas, rViewState, aRenderState);
846     }
847 
848     aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor;
849     aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor;
850     rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState);
851 }
852 
853 
854 
855 
856 void AnalogDefaultPainter::PaintAngledLine (
857     const double nAngle,
858     const double nInnerRadius,
859     const double nOuterRadius,
860     const double nStrokeWidth,
861     const Reference<rendering::XCanvas>& rxCanvas,
862     const rendering::ViewState& rViewState,
863     const rendering::RenderState& rRenderState)
864 {
865     if ( ! rxCanvas.is())
866         return;
867 
868     rendering::StrokeAttributes aStrokeAttributes;
869     aStrokeAttributes.StrokeWidth = nStrokeWidth;
870     aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
871     aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
872     aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
873     aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
874     const double nCos (cos(nAngle - M_PI/2));
875     const double nSin (sin(nAngle - M_PI/2));
876 
877     Sequence<Sequence<geometry::RealPoint2D> > aPoints(1);
878     aPoints[0] = Sequence<geometry::RealPoint2D>(2);
879     aPoints[0][0] = geometry::RealPoint2D(
880         maCenter.X + nInnerRadius*nCos + 0.5,
881         maCenter.Y + nInnerRadius*nSin + 0.5);
882     aPoints[0][1] = geometry::RealPoint2D(
883         maCenter.X + nOuterRadius*nCos + 0.5,
884         maCenter.Y + nOuterRadius*nSin + 0.5);
885 
886     Reference<rendering::XPolyPolygon2D> xLine (
887         rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints),
888         UNO_QUERY);
889     if ( ! xLine.is())
890         return;
891     rxCanvas->strokePolyPolygon(
892         xLine,
893         rViewState,
894         rRenderState,
895         aStrokeAttributes);
896 }
897 
898 
899 
900 
901 void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize)
902 {
903     maSize = rWindowSize;
904     maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
905     mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
906     mxBitmap = NULL;
907 }
908 
909 
910 
911 
912 //===== AnalogBitmapPainter ===================================================
913 
914 AnalogBitmapPainter::AnalogBitmapPainter (
915     const Reference<XComponentContext>& rxContext,
916     const OUString& rsThemeName)
917     : mxComponentContext(rxContext),
918       msThemeName(rsThemeName),
919       mbThemeLoaded(false),
920       mbThemeLoadingFailed(false),
921       maCenter(),
922       mnOuterRadius(),
923       maFace(),
924       maMinuteHand(),
925       maHourHand()
926 {
927 }
928 
929 
930 
931 
932 void AnalogBitmapPainter::Paint (
933     const Reference<rendering::XCanvas>& rxCanvas,
934     const rendering::ViewState& rViewState,
935     const rendering::RenderState& rRenderState,
936     const util::Color& rBackgroundColor,
937     const sal_Int32 nHour,
938     const sal_Int32 nMinute,
939     const sal_Int32 nSecond,
940     const bool bShowSeconds)
941 {
942     (void)rBackgroundColor;
943     (void)nSecond;
944     (void)bShowSeconds;
945 
946     if ( ! rxCanvas.is())
947         return;
948 
949     rendering::RenderState aRenderState = rRenderState;
950 
951     try
952     {
953         PrepareBitmaps(rxCanvas);
954 
955         if (maFace.mxScaledBitmap.is())
956         {
957             aRenderState.AffineTransform = geometry::AffineMatrix2D(
958                 1,0, maCenter.X - maFace.maScaledOffset.X,
959                 0,1, maCenter.Y - maFace.maScaledOffset.Y);
960             rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState);
961         }
962 
963         if (maMinuteHand.mxScaledBitmap.is())
964         {
965             const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0);
966             const double nCos (cos(nMinuteAngle - M_PI/2));
967             const double nSin (sin(nMinuteAngle - M_PI/2));
968             aRenderState.AffineTransform = geometry::AffineMatrix2D(
969                 nCos,
970                 -nSin,
971                 -maMinuteHand.maScaledOffset.X*nCos
972                     + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X,
973                 nSin,
974                 nCos,
975                 -maMinuteHand.maScaledOffset.X*nSin
976                     - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y);
977             rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState);
978         }
979 
980         if (maHourHand.mxScaledBitmap.is())
981         {
982             const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0);
983             const double nCos (cos(nHoursAngle - M_PI/2));
984             const double nSin (sin(nHoursAngle - M_PI/2));
985             aRenderState.AffineTransform = geometry::AffineMatrix2D(
986                 nCos,
987                 -nSin,
988                 -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X,
989                 nSin,
990                 nCos,
991                 -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y);
992             rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState);
993         }
994     }
995     catch(beans::UnknownPropertyException&)
996     {
997     }
998     catch(RuntimeException&)
999     {
1000     }
1001 }
1002 
1003 
1004 
1005 
1006 void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize)
1007 {
1008     maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
1009     mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
1010     maFace.mxScaledBitmap = NULL;
1011     maHourHand.mxScaledBitmap = NULL;
1012     maMinuteHand.mxScaledBitmap = NULL;
1013 }
1014 
1015 
1016 
1017 
1018 void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas)
1019 {
1020     if (mbThemeLoadingFailed)
1021     {
1022         // Theme loading has failed previously.  Do not try a second time.
1023         return;
1024     }
1025     if ( ! rxCanvas.is())
1026     {
1027         // No canvas => bitmaps can neither be loaded, transformed into the
1028         // right format, nor can they be painted.
1029         return;
1030     }
1031 
1032     if ( ! mbThemeLoaded)
1033     {
1034         mbThemeLoaded = true;
1035 
1036         // Get access to the clock bitmaps in the configuration.
1037         PresenterConfigurationAccess aConfiguration (
1038             mxComponentContext,
1039             OUString::createFromAscii("org.openoffice.Office.extension.PresenterScreen"),
1040             PresenterConfigurationAccess::READ_ONLY);
1041 
1042         Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration));
1043         if (xTheme.is())
1044             LoadBitmaps(aConfiguration, xTheme, rxCanvas);
1045         else
1046             mbThemeLoadingFailed = true;
1047     }
1048 
1049     ScaleBitmaps();
1050 }
1051 
1052 
1053 
1054 
1055 Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme (
1056     PresenterConfigurationAccess& rConfiguration)
1057 {
1058     Reference<container::XNameAccess> xTheme;
1059 
1060     // Get root of clock themes.
1061     Reference<container::XHierarchicalNameAccess> xClock (
1062         rConfiguration.GetConfigurationNode(
1063             OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")),
1064         UNO_QUERY);
1065 
1066     // Determine the name of the theme to use.
1067     OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme"));
1068     rConfiguration.GetConfigurationNode(
1069         xClock,
1070         OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName;
1071 
1072     // Load the clock theme.
1073     Reference<container::XNameAccess> xThemes (
1074         rConfiguration.GetConfigurationNode(
1075             xClock,
1076             OUString::createFromAscii("Themes")),
1077         UNO_QUERY);
1078     if (xThemes.is())
1079     {
1080         xTheme = Reference<container::XNameAccess>(
1081             PresenterConfigurationAccess::Find(
1082                 xThemes,
1083                 ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator,
1084                     this, _1, _2, sCurrentThemeName)),
1085             UNO_QUERY);
1086     }
1087 
1088     return xTheme;
1089 }
1090 
1091 
1092 
1093 
1094 bool AnalogBitmapPainter::ThemeNameComparator (
1095     const OUString& rsKey,
1096     const Reference<container::XNameAccess>& rxCandidate,
1097     const OUString& rsCurrentThemeName)
1098 {
1099     (void)rsKey;
1100     if (rxCandidate.is())
1101     {
1102         OUString sThemeName;
1103         if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName)
1104         {
1105             return sThemeName == rsCurrentThemeName;
1106         }
1107     }
1108     return false;
1109 }
1110 
1111 
1112 
1113 
1114 
1115 void AnalogBitmapPainter::LoadBitmaps (
1116     PresenterConfigurationAccess& rConfiguration,
1117     const Reference<container::XNameAccess>& rxClockTheme,
1118     const Reference<rendering::XCanvas>& rxCanvas)
1119 {
1120     (void)rConfiguration;
1121 
1122     // Get base path to bitmaps.
1123     Reference<deployment::XPackageInformationProvider> xInformationProvider (
1124         mxComponentContext->getValueByName(OUString::createFromAscii(
1125             "/singletons/com.sun.star.deployment.PackageInformationProvider")),
1126         UNO_QUERY);
1127     OUString sLocation;
1128     if (xInformationProvider.is())
1129         sLocation = xInformationProvider->getPackageLocation(gsExtensionIdentifier);
1130     sLocation += OUString::createFromAscii("/");
1131 
1132     // Create the bitmap loader.
1133     Reference<lang::XMultiComponentFactory> xFactory (
1134         mxComponentContext->getServiceManager(), UNO_QUERY);
1135     if ( ! xFactory.is())
1136         return;
1137     Sequence<Any> aArguments(1);
1138     aArguments[0] <<= rxCanvas;
1139     Reference<container::XNameAccess> xBitmapLoader(
1140         xFactory->createInstanceWithArgumentsAndContext(
1141             OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"),
1142             aArguments,
1143             mxComponentContext),
1144         UNO_QUERY);
1145     if ( ! xBitmapLoader.is())
1146         return;
1147 
1148 
1149     // Iterate over all entries in the bitmap list and load the bitmaps.
1150     Reference<container::XNameAccess> xBitmaps (
1151         rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")),
1152         UNO_QUERY);
1153     ::std::vector<rtl::OUString> aBitmapProperties (3);
1154     aBitmapProperties[0] = OUString::createFromAscii("FileName");
1155     aBitmapProperties[1] = OUString::createFromAscii("XOffset");
1156     aBitmapProperties[2] = OUString::createFromAscii("YOffset");
1157     PresenterConfigurationAccess::ForAll(
1158         xBitmaps,
1159         aBitmapProperties,
1160         ::boost::bind(&AnalogBitmapPainter::LoadBitmap,
1161             this,
1162             _1,
1163             _2,
1164             sLocation,
1165             xBitmapLoader));
1166 }
1167 
1168 
1169 
1170 
1171 void AnalogBitmapPainter::LoadBitmap (
1172     const OUString& rsKey,
1173     const ::std::vector<Any>& rValues,
1174     const OUString& rsBitmapPath,
1175     const Reference<container::XNameAccess>& rxBitmapLoader)
1176 {
1177     if (rValues.size() == 3)
1178     {
1179         BitmapDescriptor* pDescriptor = NULL;
1180         if (rsKey == OUString::createFromAscii("Face"))
1181             pDescriptor = &maFace;
1182         else if (rsKey == OUString::createFromAscii("HourHand"))
1183             pDescriptor = &maHourHand;
1184         else if (rsKey == OUString::createFromAscii("MinuteHand"))
1185             pDescriptor = &maMinuteHand;
1186 
1187         if (pDescriptor == NULL)
1188             return;
1189 
1190         OUString sFileName;
1191         if ( ! (rValues[0] >>= sFileName))
1192             return;
1193 
1194         rValues[1] >>= pDescriptor->maOffset.X;
1195         rValues[2] >>= pDescriptor->maOffset.Y;
1196 
1197         pDescriptor->mxBitmap = Reference<rendering::XBitmap>(
1198             rxBitmapLoader->getByName(rsBitmapPath+sFileName), UNO_QUERY);
1199 
1200         if ( ! pDescriptor->mxBitmap.is())
1201             mbThemeLoadingFailed = true;
1202     }
1203 }
1204 
1205 
1206 
1207 
1208 void AnalogBitmapPainter::ScaleBitmaps (void)
1209 {
1210     if (mbThemeLoadingFailed)
1211         return;
1212     if ( ! maFace.mxBitmap.is())
1213         return;
1214 
1215     const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize());
1216     const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height);
1217     const double nScale = mnOuterRadius*2 / nSize;
1218 
1219     BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand };
1220     for (int nIndex=0; nIndex<3; ++nIndex)
1221     {
1222         BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]);
1223         if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is())
1224         {
1225             const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize());
1226             rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap(
1227                 geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale),
1228                 sal_False);
1229             rDescriptor.maScaledOffset = geometry::RealPoint2D(
1230                 rDescriptor.maOffset.X * nScale,
1231                 rDescriptor.maOffset.Y * nScale);
1232         }
1233     }
1234 }
1235 
1236 
1237 
1238 
1239 //===== DigitalDefaultPainter =================================================
1240 
1241 DigitalDefaultPainter::DigitalDefaultPainter (
1242     const ::rtl::Reference<PresenterController>& rpPresenterController,
1243     const Reference<XResourceId>& rxViewId)
1244     :  mpPresenterController(rpPresenterController),
1245        mbIs24HourFormat(false),
1246        mbIsAdaptFontSize(true),
1247        mxFont(),
1248        maWindowSize(0,0),
1249        msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString())
1250 {
1251 }
1252 
1253 
1254 
1255 
1256 DigitalDefaultPainter::~DigitalDefaultPainter (void)
1257 {
1258 }
1259 
1260 
1261 
1262 
1263 void DigitalDefaultPainter::Paint (
1264     const Reference<rendering::XCanvas>& rxCanvas,
1265     const rendering::ViewState& rViewState,
1266     const rendering::RenderState& rRenderState,
1267     const util::Color& rBackgroundColor,
1268     const sal_Int32 nHour,
1269     const sal_Int32 nMinute,
1270     const sal_Int32 nSecond,
1271     const bool bIsShowSeconds)
1272 {
1273     (void)rBackgroundColor;
1274     (void)rRenderState;
1275 
1276     if ( ! mxFont.is())
1277         CreateFont(rxCanvas,bIsShowSeconds);
1278     if ( ! mxFont.is())
1279         return;
1280 
1281     OUString sText;
1282 
1283     if (mbIs24HourFormat)
1284         sText = OUString::valueOf(nHour);
1285     else
1286     {
1287         sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour);
1288     }
1289     sText += OUString::createFromAscii(":");
1290     const OUString sMinutes (OUString::valueOf(nMinute));
1291     switch (sMinutes.getLength())
1292     {
1293         case 1 :
1294             sText += OUString::createFromAscii("0") + sMinutes;
1295             break;
1296         case 2:
1297             sText += sMinutes;
1298             break;
1299 
1300         default:
1301             return;
1302     }
1303     if (bIsShowSeconds)
1304     {
1305         sText += OUString::createFromAscii(":");
1306         const OUString sSeconds (OUString::valueOf(nSecond));
1307         switch (sSeconds.getLength())
1308         {
1309             case 1 :
1310                 sText += OUString::createFromAscii("0") + sSeconds;
1311                 break;
1312             case 2:
1313                 sText += sSeconds;
1314                 break;
1315 
1316             default:
1317                 return;
1318         }
1319     }
1320 
1321     rendering::StringContext aContext (
1322         sText,
1323         0,
1324         sText.getLength());
1325     Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1326         aContext,
1327         rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1328         0));
1329     if ( ! xLayout.is())
1330         return;
1331     geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1332 
1333 
1334     rendering::RenderState aRenderState(
1335         geometry::AffineMatrix2D(1,0,0, 0,1,0),
1336         NULL,
1337         Sequence<double>(4),
1338         rendering::CompositeOperation::SOURCE);
1339 
1340     util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL));
1341     PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor);
1342     aRenderState.AffineTransform.m02
1343         = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1;
1344     aRenderState.AffineTransform.m12
1345         = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1;
1346     rxCanvas->drawText(
1347         aContext,
1348         mxFont,
1349         rViewState,
1350         aRenderState,
1351         rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1352 }
1353 
1354 
1355 
1356 
1357 void DigitalDefaultPainter::Resize (const awt::Size& rSize)
1358 {
1359     if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height)
1360     {
1361         maWindowSize = rSize;
1362         if (mbIsAdaptFontSize)
1363             mxFont = NULL;
1364     }
1365 }
1366 
1367 
1368 
1369 
1370 void DigitalDefaultPainter::CreateFont (
1371     const Reference<rendering::XCanvas>& rxCanvas,
1372     const bool bIsShowSeconds)
1373 {
1374     if (rxCanvas.is()
1375         && rxCanvas->getDevice().is()
1376         && maWindowSize.Width>0
1377         && maWindowSize.Height>0)
1378     {
1379         // Create a time template for determinging the right font size.
1380         // Assume that 0 is the widest digit or that all digits have the
1381         // same width.
1382         OUString sTimeTemplate;
1383         // For the case that not all digits have the same width, create
1384         // different templates for 12 and 24 hour mode.
1385         if (mbIs24HourFormat)
1386             sTimeTemplate = OUString::createFromAscii("20");
1387         else
1388             sTimeTemplate = OUString::createFromAscii("10");
1389         if (bIsShowSeconds)
1390             sTimeTemplate += OUString::createFromAscii(":00:00");
1391         else
1392             sTimeTemplate += OUString::createFromAscii(":00");
1393 
1394         rendering::StringContext aContext (
1395             sTimeTemplate,
1396             0,
1397             sTimeTemplate.getLength());
1398 
1399         // When the font size is adapted to the window size (as large as
1400         // possible without overlapping) then that is done in a four step
1401         // process:
1402         // 1. Create a font in a default size, e.g. 10pt.
1403         // 2. Determine a scale factor from enlarging the text bounding box
1404         // to maximal size inside the window.
1405         // 3. Create a new font by scaling the default size with the factor
1406         // calculated in step 2.
1407         // 4. Text may be rendered differently in different sizes.
1408         // Therefore repeat step 2 and 3 once.  More iterations may lead to
1409         // even better results but probably not to visible differences.
1410         rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL));
1411         // TODO: use font from view style from configuration
1412         aFontRequest.CellSize = 10;
1413 
1414         for (sal_Int32 nLoop=0; nLoop<3; ++nLoop)
1415         {
1416             mxFont = rxCanvas->createFont(
1417                 aFontRequest,
1418                 Sequence<beans::PropertyValue>(),
1419                 geometry::Matrix2D(1,0,0,1));
1420             if (mxFont.is())
1421             {
1422                 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1423                     aContext,
1424                     rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1425                     0));
1426 
1427                 if ( ! xLayout.is())
1428                     break;
1429 
1430                 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1431                 if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1)
1432                     break;
1433                 const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1);
1434                 const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1);
1435                 aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor);
1436             }
1437         }
1438     }
1439 }
1440 
1441 
1442 } // end of anonymous namespace
1443 
1444 
1445 } } // end of namespace ::sdext::presenter
1446