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