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