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); 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); 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 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 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 329 PresenterClock::~PresenterClock (void) 330 { 331 } 332 333 334 335 336 void PresenterClock::LateInit (void) 337 { 338 mpTimer = new Timer(this); 339 } 340 341 342 343 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 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 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 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 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 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 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 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 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 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 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 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 507 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void) 508 throw (RuntimeException) 509 { 510 return mxViewId; 511 } 512 513 514 515 516 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void) 517 throw (RuntimeException) 518 { 519 return false; 520 } 521 522 523 524 525 //----------------------------------------------------------------------------- 526 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 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 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 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 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 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 687 PresenterClock::Timer::~Timer (void) 688 { 689 if (mpClock.is()) 690 Stop(); 691 } 692 693 694 695 696 void PresenterClock::Timer::Stop (void) 697 { 698 mpClock = NULL; 699 stop(); 700 release(); 701 } 702 703 704 705 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 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 744 AnalogDefaultPainter::AnalogDefaultPainter (void) 745 : maCenter(0,0), 746 mnOuterRadius(0), 747 maSize(0,0), 748 mxBitmap() 749 { 750 } 751 752 753 754 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 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 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 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 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 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 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 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 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 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 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 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 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 1241 DigitalDefaultPainter::~DigitalDefaultPainter (void) 1242 { 1243 } 1244 1245 1246 1247 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 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 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