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