xref: /trunk/main/sdext/source/presenter/PresenterClock.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
393     //    ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
394     //    osl::MutexGuard aGuard (m_aMutex);
395 
396     if (rEventObject.Source == mxWindow)
397     {
398         mxWindow = NULL;
399         if (mpTimer != NULL)
400             mpTimer->Stop();
401     }
402 }
403 
404 
405 
406 
407 //----- XPaintListener --------------------------------------------------------
408 
windowPaint(const awt::PaintEvent & rEvent)409 void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent)
410 {
411     (void)rEvent;
412     ThrowIfDisposed();
413     ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
414     Paint(rEvent.UpdateRect);
415 }
416 
417 
418 
419 
420 //----- XWindowListener -------------------------------------------------------
421 
windowResized(const awt::WindowEvent & rEvent)422 void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent)
423 {
424     (void)rEvent;
425     mbIsResizePending = true;
426 }
427 
428 
429 
430 
windowMoved(const awt::WindowEvent & rEvent)431 void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent)
432 {
433     (void)rEvent;
434     mbIsResizePending = true;
435 }
436 
437 
438 
439 
windowShown(const lang::EventObject & rEvent)440 void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent)
441 {
442     (void)rEvent;
443     mbIsResizePending = true;
444 }
445 
446 
447 
448 
windowHidden(const lang::EventObject & rEvent)449 void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent)
450 {
451     (void)rEvent;
452 }
453 
454 
455 
456 
457 //----- XMouseListener --------------------------------------------------------
458 
mousePressed(const css::awt::MouseEvent & rEvent)459 void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent)
460 {
461     (void)rEvent;
462     if (rEvent.Buttons == awt::MouseButton::LEFT)
463     {
464         SetMode(mnMode+1);
465     }
466 }
467 
468 
469 
470 
mouseReleased(const css::awt::MouseEvent & rEvent)471 void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent)
472 {
473     (void)rEvent;
474 }
475 
476 
477 
478 
mouseEntered(const css::awt::MouseEvent & rEvent)479 void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent)
480 {
481     (void)rEvent;
482 }
483 
484 
485 
486 
mouseExited(const css::awt::MouseEvent & rEvent)487 void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent)
488 {
489     (void)rEvent;
490 }
491 
492 
493 
494 
495 //----- XResourceId -----------------------------------------------------------
496 
getResourceId(void)497 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void)
498 {
499     return mxViewId;
500 }
501 
502 
503 
504 
isAnchorOnly(void)505 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void)
506 {
507     return false;
508 }
509 
510 
511 
512 
513 //-----------------------------------------------------------------------------
514 
Resize(void)515 void PresenterClock::Resize (void)
516 {
517     if (mxPane.is())
518         mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
519     if (mxWindow.is() && mxCanvas.is())
520     {
521         const awt::Rectangle aWindowBox (mxWindow->getPosSize());
522         const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height);
523         if (mpClockPainter.get() != NULL)
524             mpClockPainter->Resize(aWindowSize);
525         if (mpClockPainter2.get() != NULL)
526             mpClockPainter2->Resize(aWindowSize);
527         mbIsResizePending = false;
528     }
529 }
530 
531 
532 
533 
Paint(const awt::Rectangle & rUpdateBox)534 void PresenterClock::Paint (const awt::Rectangle& rUpdateBox)
535 {
536     if ( ! mxCanvas.is() && mxPane.is())
537         mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
538     if ( ! mxWindow.is()
539         || ! mxCanvas.is()
540         || ! mxCanvas->getDevice().is())
541     {
542         return;
543     }
544 
545     try
546     {
547         if (mbIsResizePending)
548             Resize();
549 
550         Reference<rendering::XPolyPolygon2D> xUpdatePolygon (
551             PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
552 
553         Clear(xUpdatePolygon);
554 
555         if (mpClockPainter.get() != NULL)
556             mpClockPainter->Paint(mxCanvas,
557                 maViewState,
558                 maRenderState,
559                 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
560                 mnHour,
561                 mnMinute,
562                 mnSecond,
563                 mbIsShowSeconds);
564 
565         if (mpClockPainter2.get() != NULL)
566             mpClockPainter2->Paint(
567                 mxCanvas,
568                 maViewState,
569                 maRenderState,
570                 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
571                 mnHour,
572                 mnMinute,
573                 mnSecond,
574                 mbIsShowSeconds);
575     }
576     catch (RuntimeException& e)
577     {
578         (void)e;
579     }
580 
581     // Make the back buffer visible.
582     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
583     if (xSpriteCanvas.is())
584         xSpriteCanvas->updateScreen(sal_False);
585 }
586 
587 
588 
589 
Clear(const Reference<rendering::XPolyPolygon2D> & rxUpdatePolygon)590 void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon)
591 {
592     rendering::RenderState aRenderState = maRenderState;
593     const sal_Int32 nColor (
594         mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()));
595     aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0;
596     aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >>  8) / 255.0;
597     aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >>  0) / 255.0;
598 
599     if (rxUpdatePolygon.is())
600         mxCanvas->fillPolyPolygon(
601             rxUpdatePolygon,
602             maViewState,
603             aRenderState);
604 }
605 
606 
607 
608 
SetMode(const sal_Int32 nMode)609 void PresenterClock::SetMode (const sal_Int32 nMode)
610 {
611     mnMode = nMode % 3;
612 
613     switch (mnMode)
614     {
615         case 0:
616             mpClockPainter.reset(
617                 new AnalogBitmapPainter(
618                     mxComponentContext,
619                     OUString::createFromAscii("ClockTheme")));
620             mpClockPainter2.reset();
621             break;
622 
623         case 1:
624             mpClockPainter.reset();
625             mpClockPainter2.reset(new AnalogDefaultPainter());
626             break;
627 
628         case 2:
629             mpClockPainter.reset();
630             mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId));
631             break;
632 
633         case 3:
634             mpClockPainter.reset(
635                 new AnalogBitmapPainter(
636                     mxComponentContext,
637                     OUString::createFromAscii("ClockTheme")));
638             mpClockPainter2.reset(new AnalogDefaultPainter());
639             break;
640     }
641     Resize();
642 }
643 
644 
645 
646 
ThrowIfDisposed(void)647 void PresenterClock::ThrowIfDisposed (void)
648 {
649     if (rBHelper.bDisposed || rBHelper.bInDispose)
650     {
651         throw lang::DisposedException (
652             ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
653                 "PresenterClock object has already been disposed")),
654             static_cast<uno::XWeak*>(this));
655     }
656 }
657 
658 
659 
660 
661 //===== Timer =================================================================
662 
Timer(const::rtl::Reference<PresenterClock> & rpClock)663 PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock)
664     : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)),
665       mpClock(rpClock)
666 {
667     acquire();
668     start();
669 }
670 
671 
672 
673 
~Timer(void)674 PresenterClock::Timer::~Timer (void)
675 {
676     if (mpClock.is())
677         Stop();
678 }
679 
680 
681 
682 
Stop(void)683 void PresenterClock::Timer::Stop (void)
684 {
685     mpClock = NULL;
686     stop();
687     release();
688 }
689 
690 
691 
692 
onShot(void)693 void SAL_CALL PresenterClock::Timer::onShot (void)
694 {
695     if (mpClock.get() != NULL)
696         mpClock->UpdateTime();
697 }
698 
699 
700 
701 namespace {
702 
703 //=============================================================================
704 
GetDateTime(oslDateTime & rDateTime)705 bool GetDateTime (oslDateTime& rDateTime)
706 {
707     TimeValue aSystemTime;
708     TimeValue aLocalTime;
709     if (osl_getSystemTime(&aSystemTime))
710         if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime))
711             if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime))
712                 return true;
713     return false;
714 }
715 
716 
717 
718 
719 //===== AnalogDefaultPainter ==================================================
720 
721 const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65;
722 const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1);
723 const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055);
724 const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2);
725 const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85);
726 const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025);
727 const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25);
728 const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95);
729 const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015);
730 
AnalogDefaultPainter(void)731 AnalogDefaultPainter::AnalogDefaultPainter (void)
732     : maCenter(0,0),
733       mnOuterRadius(0),
734       maSize(0,0),
735       mxBitmap()
736 {
737 }
738 
739 
740 
741 
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)742 void AnalogDefaultPainter::Paint (
743     const Reference<rendering::XCanvas>& rxCanvas,
744     const rendering::ViewState& rViewState,
745     const rendering::RenderState& rRenderState,
746     const util::Color& rBackgroundColor,
747     const sal_Int32 nHour,
748     const sal_Int32 nMinute,
749     const sal_Int32 nSecond,
750     const bool bShowSeconds)
751 {
752     double nInnerRadius (0);
753     double nStrokeWidth (0.1);
754     const double nClockSize (2*mnOuterRadius);
755 
756     // Some antialiasing is created by painting into a bitmap twice the
757     // screen size and then scaling it down.
758     const sal_Int32 nSuperSampleFactor (2);
759     if ( ! mxBitmap.is())
760     {
761         mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap(
762             geometry::IntegerSize2D(
763                 maSize.Width*nSuperSampleFactor,
764                 maSize.Height*nSuperSampleFactor)));
765     }
766     Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY);
767     rendering::RenderState aRenderState(rRenderState);
768     aRenderState.AffineTransform.m00 = nSuperSampleFactor;
769     aRenderState.AffineTransform.m11 = nSuperSampleFactor;
770 
771     // Clear the background.
772     aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0;
773     aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >>  8) / 255.0;
774     aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >>  0) / 255.0;
775     Reference<rendering::XPolyPolygon2D> xPolygon (
776         PresenterGeometryHelper::CreatePolygon(
777             awt::Rectangle(0,0,maSize.Width,maSize.Height),
778             xBitmapCanvas->getDevice()));
779     if (xPolygon.is())
780         xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState);
781 
782     // Clock face and clock hands are painted in black.
783     aRenderState.DeviceColor[0] = 0;
784     aRenderState.DeviceColor[1] = 0;
785     aRenderState.DeviceColor[2] = 0;
786 
787     // Paint the clock face.
788     for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark)
789     {
790         if (nHourMark%3 == 0)
791         {
792             nInnerRadius = 0.7 * mnOuterRadius;
793             nStrokeWidth = 0.05 * nClockSize;
794         }
795         else
796         {
797             nInnerRadius = 0.8 * mnOuterRadius;
798             nStrokeWidth = 0.03 * nClockSize;
799         }
800 
801         const double nAngle (nHourMark * 2 * M_PI / 12);
802         PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth,
803             xBitmapCanvas, rViewState, aRenderState);
804     }
805 
806     // Paint the hour hand.
807     const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12);
808     PaintAngledLine(nHoursAngle,
809         mnRelativeHourHandLength2*mnOuterRadius,
810         mnRelativeHourHandLength*mnOuterRadius,
811         mnRelativeHourHandWidth*nClockSize,
812         xBitmapCanvas, rViewState, aRenderState);
813 
814     // Paint the minute hand.
815     const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60);
816     PaintAngledLine(nMinutesAngle,
817         mnRelativeMinuteHandLength2*mnOuterRadius,
818         mnRelativeMinuteHandLength*mnOuterRadius,
819         mnRelativeMinuteHandWidth*nClockSize,
820         xBitmapCanvas, rViewState, aRenderState);
821 
822     // Optionally paint the second hand.
823     if (bShowSeconds)
824     {
825         const double nSecondsAngle (nSecond * 2 * M_PI / 60);
826         PaintAngledLine(nSecondsAngle,
827             mnRelativeSecondHandLength2*mnOuterRadius,
828             mnRelativeSecondHandLength*mnOuterRadius,
829             mnRelativeSecondHandWidth*nClockSize,
830             xBitmapCanvas, rViewState, aRenderState);
831     }
832 
833     aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor;
834     aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor;
835     rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState);
836 }
837 
838 
839 
840 
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)841 void AnalogDefaultPainter::PaintAngledLine (
842     const double nAngle,
843     const double nInnerRadius,
844     const double nOuterRadius,
845     const double nStrokeWidth,
846     const Reference<rendering::XCanvas>& rxCanvas,
847     const rendering::ViewState& rViewState,
848     const rendering::RenderState& rRenderState)
849 {
850     if ( ! rxCanvas.is())
851         return;
852 
853     rendering::StrokeAttributes aStrokeAttributes;
854     aStrokeAttributes.StrokeWidth = nStrokeWidth;
855     aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
856     aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
857     aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
858     aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
859     const double nCos (cos(nAngle - M_PI/2));
860     const double nSin (sin(nAngle - M_PI/2));
861 
862     Sequence<Sequence<geometry::RealPoint2D> > aPoints(1);
863     aPoints[0] = Sequence<geometry::RealPoint2D>(2);
864     aPoints[0][0] = geometry::RealPoint2D(
865         maCenter.X + nInnerRadius*nCos + 0.5,
866         maCenter.Y + nInnerRadius*nSin + 0.5);
867     aPoints[0][1] = geometry::RealPoint2D(
868         maCenter.X + nOuterRadius*nCos + 0.5,
869         maCenter.Y + nOuterRadius*nSin + 0.5);
870 
871     Reference<rendering::XPolyPolygon2D> xLine (
872         rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints),
873         UNO_QUERY);
874     if ( ! xLine.is())
875         return;
876     rxCanvas->strokePolyPolygon(
877         xLine,
878         rViewState,
879         rRenderState,
880         aStrokeAttributes);
881 }
882 
883 
884 
885 
Resize(const awt::Size & rWindowSize)886 void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize)
887 {
888     maSize = rWindowSize;
889     maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
890     mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
891     mxBitmap = NULL;
892 }
893 
894 
895 
896 
897 //===== AnalogBitmapPainter ===================================================
898 
AnalogBitmapPainter(const Reference<XComponentContext> & rxContext,const OUString & rsThemeName)899 AnalogBitmapPainter::AnalogBitmapPainter (
900     const Reference<XComponentContext>& rxContext,
901     const OUString& rsThemeName)
902     : mxComponentContext(rxContext),
903       msThemeName(rsThemeName),
904       mbThemeLoaded(false),
905       mbThemeLoadingFailed(false),
906       maCenter(),
907       mnOuterRadius(),
908       maFace(),
909       maMinuteHand(),
910       maHourHand()
911 {
912 }
913 
914 
915 
916 
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)917 void AnalogBitmapPainter::Paint (
918     const Reference<rendering::XCanvas>& rxCanvas,
919     const rendering::ViewState& rViewState,
920     const rendering::RenderState& rRenderState,
921     const util::Color& rBackgroundColor,
922     const sal_Int32 nHour,
923     const sal_Int32 nMinute,
924     const sal_Int32 nSecond,
925     const bool bShowSeconds)
926 {
927     (void)rBackgroundColor;
928     (void)nSecond;
929     (void)bShowSeconds;
930 
931     if ( ! rxCanvas.is())
932         return;
933 
934     rendering::RenderState aRenderState = rRenderState;
935 
936     try
937     {
938         PrepareBitmaps(rxCanvas);
939 
940         if (maFace.mxScaledBitmap.is())
941         {
942             aRenderState.AffineTransform = geometry::AffineMatrix2D(
943                 1,0, maCenter.X - maFace.maScaledOffset.X,
944                 0,1, maCenter.Y - maFace.maScaledOffset.Y);
945             rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState);
946         }
947 
948         if (maMinuteHand.mxScaledBitmap.is())
949         {
950             const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0);
951             const double nCos (cos(nMinuteAngle - M_PI/2));
952             const double nSin (sin(nMinuteAngle - M_PI/2));
953             aRenderState.AffineTransform = geometry::AffineMatrix2D(
954                 nCos,
955                 -nSin,
956                 -maMinuteHand.maScaledOffset.X*nCos
957                     + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X,
958                 nSin,
959                 nCos,
960                 -maMinuteHand.maScaledOffset.X*nSin
961                     - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y);
962             rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState);
963         }
964 
965         if (maHourHand.mxScaledBitmap.is())
966         {
967             const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0);
968             const double nCos (cos(nHoursAngle - M_PI/2));
969             const double nSin (sin(nHoursAngle - M_PI/2));
970             aRenderState.AffineTransform = geometry::AffineMatrix2D(
971                 nCos,
972                 -nSin,
973                 -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X,
974                 nSin,
975                 nCos,
976                 -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y);
977             rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState);
978         }
979     }
980     catch(beans::UnknownPropertyException&)
981     {
982     }
983     catch(RuntimeException&)
984     {
985     }
986 }
987 
988 
989 
990 
Resize(const awt::Size & rWindowSize)991 void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize)
992 {
993     maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
994     mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
995     maFace.mxScaledBitmap = NULL;
996     maHourHand.mxScaledBitmap = NULL;
997     maMinuteHand.mxScaledBitmap = NULL;
998 }
999 
1000 
1001 
1002 
PrepareBitmaps(const Reference<rendering::XCanvas> & rxCanvas)1003 void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas)
1004 {
1005     if (mbThemeLoadingFailed)
1006     {
1007         // Theme loading has failed previously.  Do not try a second time.
1008         return;
1009     }
1010     if ( ! rxCanvas.is())
1011     {
1012         // No canvas => bitmaps can neither be loaded, transformed into the
1013         // right format, nor can they be painted.
1014         return;
1015     }
1016 
1017     if ( ! mbThemeLoaded)
1018     {
1019         mbThemeLoaded = true;
1020 
1021         // Get access to the clock bitmaps in the configuration.
1022         PresenterConfigurationAccess aConfiguration (
1023             mxComponentContext,
1024             OUString::createFromAscii("org.openoffice.Office.PresenterScreen"),
1025             PresenterConfigurationAccess::READ_ONLY);
1026 
1027         Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration));
1028         if (xTheme.is())
1029             LoadBitmaps(aConfiguration, xTheme, rxCanvas);
1030         else
1031             mbThemeLoadingFailed = true;
1032     }
1033 
1034     ScaleBitmaps();
1035 }
1036 
1037 
1038 
1039 
GetTheme(PresenterConfigurationAccess & rConfiguration)1040 Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme (
1041     PresenterConfigurationAccess& rConfiguration)
1042 {
1043     Reference<container::XNameAccess> xTheme;
1044 
1045     // Get root of clock themes.
1046     Reference<container::XHierarchicalNameAccess> xClock (
1047         rConfiguration.GetConfigurationNode(
1048             OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")),
1049         UNO_QUERY);
1050 
1051     // Determine the name of the theme to use.
1052     OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme"));
1053     rConfiguration.GetConfigurationNode(
1054         xClock,
1055         OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName;
1056 
1057     // Load the clock theme.
1058     Reference<container::XNameAccess> xThemes (
1059         rConfiguration.GetConfigurationNode(
1060             xClock,
1061             OUString::createFromAscii("Themes")),
1062         UNO_QUERY);
1063     if (xThemes.is())
1064     {
1065         xTheme = Reference<container::XNameAccess>(
1066             PresenterConfigurationAccess::Find(
1067                 xThemes,
1068                 ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator,
1069                     this, _1, _2, sCurrentThemeName)),
1070             UNO_QUERY);
1071     }
1072 
1073     return xTheme;
1074 }
1075 
1076 
1077 
1078 
ThemeNameComparator(const OUString & rsKey,const Reference<container::XNameAccess> & rxCandidate,const OUString & rsCurrentThemeName)1079 bool AnalogBitmapPainter::ThemeNameComparator (
1080     const OUString& rsKey,
1081     const Reference<container::XNameAccess>& rxCandidate,
1082     const OUString& rsCurrentThemeName)
1083 {
1084     (void)rsKey;
1085     if (rxCandidate.is())
1086     {
1087         OUString sThemeName;
1088         if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName)
1089         {
1090             return sThemeName == rsCurrentThemeName;
1091         }
1092     }
1093     return false;
1094 }
1095 
1096 
1097 
1098 
1099 
LoadBitmaps(PresenterConfigurationAccess & rConfiguration,const Reference<container::XNameAccess> & rxClockTheme,const Reference<rendering::XCanvas> & rxCanvas)1100 void AnalogBitmapPainter::LoadBitmaps (
1101     PresenterConfigurationAccess& rConfiguration,
1102     const Reference<container::XNameAccess>& rxClockTheme,
1103     const Reference<rendering::XCanvas>& rxCanvas)
1104 {
1105     (void)rConfiguration;
1106     // Create the bitmap loader.
1107     Reference<lang::XMultiComponentFactory> xFactory (
1108         mxComponentContext->getServiceManager(), UNO_QUERY);
1109     if ( ! xFactory.is())
1110         return;
1111     Sequence<Any> aArguments(1);
1112     aArguments[0] <<= rxCanvas;
1113     Reference<container::XNameAccess> xBitmapLoader(
1114         xFactory->createInstanceWithArgumentsAndContext(
1115             OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"),
1116             aArguments,
1117             mxComponentContext),
1118         UNO_QUERY);
1119     if ( ! xBitmapLoader.is())
1120         return;
1121 
1122 
1123     // Iterate over all entries in the bitmap list and load the bitmaps.
1124     Reference<container::XNameAccess> xBitmaps (
1125         rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")),
1126         UNO_QUERY);
1127     ::std::vector<rtl::OUString> aBitmapProperties (3);
1128     aBitmapProperties[0] = OUString::createFromAscii("FileName");
1129     aBitmapProperties[1] = OUString::createFromAscii("XOffset");
1130     aBitmapProperties[2] = OUString::createFromAscii("YOffset");
1131     PresenterConfigurationAccess::ForAll(
1132         xBitmaps,
1133         aBitmapProperties,
1134         ::boost::bind(&AnalogBitmapPainter::LoadBitmap,
1135             this,
1136             _1,
1137             _2,
1138             xBitmapLoader));
1139 }
1140 
1141 
1142 
1143 
LoadBitmap(const OUString & rsKey,const::std::vector<Any> & rValues,const Reference<container::XNameAccess> & rxBitmapLoader)1144 void AnalogBitmapPainter::LoadBitmap (
1145     const OUString& rsKey,
1146     const ::std::vector<Any>& rValues,
1147     const Reference<container::XNameAccess>& rxBitmapLoader)
1148 {
1149     if (rValues.size() == 3)
1150     {
1151         BitmapDescriptor* pDescriptor = NULL;
1152         if (rsKey == OUString::createFromAscii("Face"))
1153             pDescriptor = &maFace;
1154         else if (rsKey == OUString::createFromAscii("HourHand"))
1155             pDescriptor = &maHourHand;
1156         else if (rsKey == OUString::createFromAscii("MinuteHand"))
1157             pDescriptor = &maMinuteHand;
1158 
1159         if (pDescriptor == NULL)
1160             return;
1161 
1162         OUString sFileName;
1163         if ( ! (rValues[0] >>= sFileName))
1164             return;
1165 
1166         rValues[1] >>= pDescriptor->maOffset.X;
1167         rValues[2] >>= pDescriptor->maOffset.Y;
1168 
1169         pDescriptor->mxBitmap = Reference<rendering::XBitmap>(
1170             rxBitmapLoader->getByName(sFileName), UNO_QUERY);
1171 
1172         if ( ! pDescriptor->mxBitmap.is())
1173             mbThemeLoadingFailed = true;
1174     }
1175 }
1176 
1177 
1178 
1179 
ScaleBitmaps(void)1180 void AnalogBitmapPainter::ScaleBitmaps (void)
1181 {
1182     if (mbThemeLoadingFailed)
1183         return;
1184     if ( ! maFace.mxBitmap.is())
1185         return;
1186 
1187     const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize());
1188     const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height);
1189     const double nScale = mnOuterRadius*2 / nSize;
1190 
1191     BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand };
1192     for (int nIndex=0; nIndex<3; ++nIndex)
1193     {
1194         BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]);
1195         if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is())
1196         {
1197             const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize());
1198             rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap(
1199                 geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale),
1200                 sal_False);
1201             rDescriptor.maScaledOffset = geometry::RealPoint2D(
1202                 rDescriptor.maOffset.X * nScale,
1203                 rDescriptor.maOffset.Y * nScale);
1204         }
1205     }
1206 }
1207 
1208 
1209 
1210 
1211 //===== DigitalDefaultPainter =================================================
1212 
DigitalDefaultPainter(const::rtl::Reference<PresenterController> & rpPresenterController,const Reference<XResourceId> & rxViewId)1213 DigitalDefaultPainter::DigitalDefaultPainter (
1214     const ::rtl::Reference<PresenterController>& rpPresenterController,
1215     const Reference<XResourceId>& rxViewId)
1216     :  mpPresenterController(rpPresenterController),
1217        mbIs24HourFormat(false),
1218        mbIsAdaptFontSize(true),
1219        mxFont(),
1220        maWindowSize(0,0),
1221        msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString())
1222 {
1223 }
1224 
1225 
1226 
1227 
~DigitalDefaultPainter(void)1228 DigitalDefaultPainter::~DigitalDefaultPainter (void)
1229 {
1230 }
1231 
1232 
1233 
1234 
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)1235 void DigitalDefaultPainter::Paint (
1236     const Reference<rendering::XCanvas>& rxCanvas,
1237     const rendering::ViewState& rViewState,
1238     const rendering::RenderState& rRenderState,
1239     const util::Color& rBackgroundColor,
1240     const sal_Int32 nHour,
1241     const sal_Int32 nMinute,
1242     const sal_Int32 nSecond,
1243     const bool bIsShowSeconds)
1244 {
1245     (void)rBackgroundColor;
1246     (void)rRenderState;
1247 
1248     if ( ! mxFont.is())
1249         CreateFont(rxCanvas,bIsShowSeconds);
1250     if ( ! mxFont.is())
1251         return;
1252 
1253     OUString sText;
1254 
1255     if (mbIs24HourFormat)
1256         sText = OUString::valueOf(nHour);
1257     else
1258     {
1259         sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour);
1260     }
1261     sText += OUString::createFromAscii(":");
1262     const OUString sMinutes (OUString::valueOf(nMinute));
1263     switch (sMinutes.getLength())
1264     {
1265         case 1 :
1266             sText += OUString::createFromAscii("0") + sMinutes;
1267             break;
1268         case 2:
1269             sText += sMinutes;
1270             break;
1271 
1272         default:
1273             return;
1274     }
1275     if (bIsShowSeconds)
1276     {
1277         sText += OUString::createFromAscii(":");
1278         const OUString sSeconds (OUString::valueOf(nSecond));
1279         switch (sSeconds.getLength())
1280         {
1281             case 1 :
1282                 sText += OUString::createFromAscii("0") + sSeconds;
1283                 break;
1284             case 2:
1285                 sText += sSeconds;
1286                 break;
1287 
1288             default:
1289                 return;
1290         }
1291     }
1292 
1293     rendering::StringContext aContext (
1294         sText,
1295         0,
1296         sText.getLength());
1297     Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1298         aContext,
1299         rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1300         0));
1301     if ( ! xLayout.is())
1302         return;
1303     geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1304 
1305 
1306     rendering::RenderState aRenderState(
1307         geometry::AffineMatrix2D(1,0,0, 0,1,0),
1308         NULL,
1309         Sequence<double>(4),
1310         rendering::CompositeOperation::SOURCE);
1311 
1312     util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL));
1313     PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor);
1314     aRenderState.AffineTransform.m02
1315         = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1;
1316     aRenderState.AffineTransform.m12
1317         = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1;
1318     rxCanvas->drawText(
1319         aContext,
1320         mxFont,
1321         rViewState,
1322         aRenderState,
1323         rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1324 }
1325 
1326 
1327 
1328 
Resize(const awt::Size & rSize)1329 void DigitalDefaultPainter::Resize (const awt::Size& rSize)
1330 {
1331     if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height)
1332     {
1333         maWindowSize = rSize;
1334         if (mbIsAdaptFontSize)
1335             mxFont = NULL;
1336     }
1337 }
1338 
1339 
1340 
1341 
CreateFont(const Reference<rendering::XCanvas> & rxCanvas,const bool bIsShowSeconds)1342 void DigitalDefaultPainter::CreateFont (
1343     const Reference<rendering::XCanvas>& rxCanvas,
1344     const bool bIsShowSeconds)
1345 {
1346     if (rxCanvas.is()
1347         && rxCanvas->getDevice().is()
1348         && maWindowSize.Width>0
1349         && maWindowSize.Height>0)
1350     {
1351         // Create a time template for determinging the right font size.
1352         // Assume that 0 is the widest digit or that all digits have the
1353         // same width.
1354         OUString sTimeTemplate;
1355         // For the case that not all digits have the same width, create
1356         // different templates for 12 and 24 hour mode.
1357         if (mbIs24HourFormat)
1358             sTimeTemplate = OUString::createFromAscii("20");
1359         else
1360             sTimeTemplate = OUString::createFromAscii("10");
1361         if (bIsShowSeconds)
1362             sTimeTemplate += OUString::createFromAscii(":00:00");
1363         else
1364             sTimeTemplate += OUString::createFromAscii(":00");
1365 
1366         rendering::StringContext aContext (
1367             sTimeTemplate,
1368             0,
1369             sTimeTemplate.getLength());
1370 
1371         // When the font size is adapted to the window size (as large as
1372         // possible without overlapping) then that is done in a four step
1373         // process:
1374         // 1. Create a font in a default size, e.g. 10pt.
1375         // 2. Determine a scale factor from enlarging the text bounding box
1376         // to maximal size inside the window.
1377         // 3. Create a new font by scaling the default size with the factor
1378         // calculated in step 2.
1379         // 4. Text may be rendered differently in different sizes.
1380         // Therefore repeat step 2 and 3 once.  More iterations may lead to
1381         // even better results but probably not to visible differences.
1382         rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL));
1383         // TODO: use font from view style from configuration
1384         aFontRequest.CellSize = 10;
1385 
1386         for (sal_Int32 nLoop=0; nLoop<3; ++nLoop)
1387         {
1388             mxFont = rxCanvas->createFont(
1389                 aFontRequest,
1390                 Sequence<beans::PropertyValue>(),
1391                 geometry::Matrix2D(1,0,0,1));
1392             if (mxFont.is())
1393             {
1394                 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1395                     aContext,
1396                     rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1397                     0));
1398 
1399                 if ( ! xLayout.is())
1400                     break;
1401 
1402                 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1403                 if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1)
1404                     break;
1405                 const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1);
1406                 const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1);
1407                 aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor);
1408             }
1409         }
1410     }
1411 }
1412 
1413 
1414 } // end of anonymous namespace
1415 
1416 
1417 } } // end of namespace ::sdext::presenter
1418