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_sd.hxx" 30 31 #include "PreviewRenderer.hxx" 32 33 #include "DrawDocShell.hxx" 34 #include "drawdoc.hxx" 35 #include "drawview.hxx" 36 #include "sdpage.hxx" 37 #include "ViewShell.hxx" 38 #include <vcl/virdev.hxx> 39 #include <svx/svdpagv.hxx> 40 #include <svx/svdoutl.hxx> 41 #include <editeng/eeitem.hxx> 42 #include <editeng/editstat.hxx> 43 #include <tools/link.hxx> 44 #include <vcl/svapp.hxx> 45 #include <tools/diagnose_ex.h> 46 #include <svx/sdr/contact/viewobjectcontact.hxx> 47 #include <svx/sdr/contact/viewcontact.hxx> 48 49 using namespace ::com::sun::star; 50 using namespace ::com::sun::star::uno; 51 52 53 namespace sd { 54 55 const int PreviewRenderer::snSubstitutionTextSize = 11; 56 const int PreviewRenderer::snFrameWidth = 1; 57 58 namespace { 59 /** This incarnation of the ViewObjectContactRedirector filters away all 60 PageObj objects, unconditionally. 61 */ 62 class ViewRedirector : public ::sdr::contact::ViewObjectContactRedirector 63 { 64 public: 65 ViewRedirector (void); 66 virtual ~ViewRedirector (void); 67 virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence( 68 const sdr::contact::ViewObjectContact& rOriginal, 69 const sdr::contact::DisplayInfo& rDisplayInfo); 70 }; 71 } 72 73 74 75 76 //===== PreviewRenderer ======================================================= 77 78 PreviewRenderer::PreviewRenderer ( 79 OutputDevice* pTemplate, 80 const bool bHasFrame) 81 : mpPreviewDevice (new VirtualDevice()), 82 mpView(NULL), 83 mpDocShellOfView(NULL), 84 mnWidthOfView(0), 85 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor), 86 mbHasFrame(bHasFrame) 87 { 88 if (pTemplate != NULL) 89 { 90 mpPreviewDevice->SetDigitLanguage (pTemplate->GetDigitLanguage()); 91 mpPreviewDevice->SetBackground(pTemplate->GetBackground()); 92 } 93 else 94 { 95 mpPreviewDevice->SetBackground(Wallpaper( 96 Application::GetSettings().GetStyleSettings().GetWindowColor())); 97 } 98 } 99 100 101 102 103 PreviewRenderer::~PreviewRenderer (void) 104 { 105 if (mpDocShellOfView != NULL) 106 EndListening (*mpDocShellOfView); 107 } 108 109 110 111 112 Image PreviewRenderer::RenderPage ( 113 const SdPage* pPage, 114 const sal_Int32 nWidth, 115 const String& rSubstitutionText, 116 const bool bObeyHighContrastMode, 117 const bool bDisplayPresentationObjects) 118 { 119 if (pPage != NULL) 120 { 121 const Size aPageModelSize (pPage->GetSize()); 122 const double nAspectRatio ( 123 double(aPageModelSize.Width()) / double(aPageModelSize.Height())); 124 const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); 125 const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>( 126 (nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5)); 127 return RenderPage ( 128 pPage, 129 Size(nWidth,nHeight), 130 rSubstitutionText, 131 bObeyHighContrastMode, 132 bDisplayPresentationObjects); 133 } 134 else 135 return Image(); 136 } 137 138 139 140 141 Image PreviewRenderer::RenderPage ( 142 const SdPage* pPage, 143 Size aPixelSize, 144 const String& rSubstitutionText, 145 const bool bObeyHighContrastMode, 146 const bool bDisplayPresentationObjects) 147 { 148 Image aPreview; 149 150 if (pPage != NULL) 151 { 152 try 153 { 154 if (Initialize(pPage, aPixelSize, bObeyHighContrastMode)) 155 { 156 PaintPage(pPage, bDisplayPresentationObjects); 157 PaintSubstitutionText(rSubstitutionText); 158 PaintFrame(); 159 160 Size aSize (mpPreviewDevice->GetOutputSizePixel()); 161 aPreview = mpPreviewDevice->GetBitmap ( 162 mpPreviewDevice->PixelToLogic(Point(0,0)), 163 mpPreviewDevice->PixelToLogic(aSize)); 164 165 Cleanup(); 166 } 167 } 168 catch (const com::sun::star::uno::Exception&) 169 { 170 DBG_UNHANDLED_EXCEPTION(); 171 } 172 } 173 174 return aPreview; 175 } 176 177 178 179 180 Image PreviewRenderer::RenderSubstitution ( 181 const Size& rPreviewPixelSize, 182 const String& rSubstitutionText) 183 { 184 Image aPreview; 185 186 try 187 { 188 // Set size. 189 mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize); 190 191 // Adjust contrast mode. 192 const bool bUseContrast ( 193 Application::GetSettings().GetStyleSettings().GetHighContrastMode()); 194 mpPreviewDevice->SetDrawMode (bUseContrast 195 ? ViewShell::OUTPUT_DRAWMODE_CONTRAST 196 : ViewShell::OUTPUT_DRAWMODE_COLOR); 197 198 // Set a map mode that makes a typical substitution text completely 199 // visible. 200 MapMode aMapMode (mpPreviewDevice->GetMapMode()); 201 aMapMode.SetMapUnit(MAP_100TH_MM); 202 const double nFinalScale (25.0 * rPreviewPixelSize.Width() / 28000.0); 203 aMapMode.SetScaleX(nFinalScale); 204 aMapMode.SetScaleY(nFinalScale); 205 const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); 206 aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic( 207 Point(nFrameWidth,nFrameWidth),aMapMode)); 208 mpPreviewDevice->SetMapMode (aMapMode); 209 210 // Clear the background. 211 const Rectangle aPaintRectangle ( 212 Point(0,0), 213 mpPreviewDevice->GetOutputSizePixel()); 214 mpPreviewDevice->EnableMapMode(sal_False); 215 mpPreviewDevice->SetLineColor(); 216 svtools::ColorConfig aColorConfig; 217 mpPreviewDevice->SetFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor); 218 mpPreviewDevice->DrawRect (aPaintRectangle); 219 mpPreviewDevice->EnableMapMode(sal_True); 220 221 // Paint substitution text and a frame around it. 222 PaintSubstitutionText (rSubstitutionText); 223 PaintFrame(); 224 225 const Size aSize (mpPreviewDevice->GetOutputSizePixel()); 226 aPreview = mpPreviewDevice->GetBitmap ( 227 mpPreviewDevice->PixelToLogic(Point(0,0)), 228 mpPreviewDevice->PixelToLogic(aSize)); 229 } 230 catch (const com::sun::star::uno::Exception&) 231 { 232 DBG_UNHANDLED_EXCEPTION(); 233 } 234 235 return aPreview; 236 } 237 238 239 240 241 bool PreviewRenderer::Initialize ( 242 const SdPage* pPage, 243 const Size& rPixelSize, 244 const bool bObeyHighContrastMode) 245 { 246 bool bSuccess = false; 247 do 248 { 249 if (pPage == NULL) 250 break; 251 252 SdrModel* pModel = pPage->GetModel(); 253 if (pModel == NULL) 254 break; 255 256 SetupOutputSize(*pPage, rPixelSize); 257 258 SdDrawDocument* pDocument 259 = static_cast<SdDrawDocument*>(pPage->GetModel()); 260 DrawDocShell* pDocShell = pDocument->GetDocSh(); 261 262 // Create view 263 ProvideView (pDocShell); 264 if (mpView.get() == NULL) 265 break; 266 267 // Adjust contrast mode. 268 bool bUseContrast (bObeyHighContrastMode 269 && Application::GetSettings().GetStyleSettings().GetHighContrastMode()); 270 mpPreviewDevice->SetDrawMode (bUseContrast 271 ? ViewShell::OUTPUT_DRAWMODE_CONTRAST 272 : ViewShell::OUTPUT_DRAWMODE_COLOR); 273 mpPreviewDevice->SetSettings(Application::GetSettings()); 274 275 // Tell the view to show the given page. 276 SdPage* pNonConstPage = const_cast<SdPage*>(pPage); 277 if (pPage->IsMasterPage()) 278 { 279 mpView->ShowSdrPage(mpView->GetModel()->GetMasterPage(pPage->GetPageNum())); 280 } 281 else 282 { 283 mpView->ShowSdrPage(pNonConstPage); 284 } 285 286 // Make sure that a page view exists. 287 SdrPageView* pPageView = mpView->GetSdrPageView(); 288 if (pPageView == NULL) 289 break; 290 // Set background color of page view and outliner. 291 svtools::ColorConfig aColorConfig; 292 const Color aPageBackgroundColor(pPage->GetPageBackgroundColor(pPageView)); 293 pPageView->SetApplicationBackgroundColor(aPageBackgroundColor); 294 SdrOutliner& rOutliner (pDocument->GetDrawOutliner(NULL)); 295 rOutliner.SetBackgroundColor(aPageBackgroundColor); 296 rOutliner.SetDefaultLanguage(pDocument->GetLanguage(EE_CHAR_LANGUAGE)); 297 mpView->SetApplicationBackgroundColor( 298 Color(aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor)); 299 mpPreviewDevice->SetBackground(Wallpaper(aPageBackgroundColor)); 300 mpPreviewDevice->Erase(); 301 302 bSuccess = true; 303 } 304 while (false); 305 306 return bSuccess; 307 } 308 309 310 311 312 void PreviewRenderer::Cleanup (void) 313 { 314 mpView->HideSdrPage(); 315 } 316 317 318 319 320 void PreviewRenderer::PaintPage ( 321 const SdPage* pPage, 322 const bool bDisplayPresentationObjects) 323 { 324 // Paint the page. 325 Rectangle aPaintRectangle (Point(0,0), pPage->GetSize()); 326 Region aRegion (aPaintRectangle); 327 328 // Turn off online spelling and redlining. 329 SdrOutliner* pOutliner = NULL; 330 sal_uLong nSavedControlWord (0); 331 if (mpDocShellOfView!=NULL && mpDocShellOfView->GetDoc()!=NULL) 332 { 333 pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner(); 334 nSavedControlWord = pOutliner->GetControlWord(); 335 pOutliner->SetControlWord((nSavedControlWord & ~EE_CNTRL_ONLINESPELLING)); 336 } 337 338 // Use a special redirector to prevent PresObj shapes from being painted. 339 boost::scoped_ptr<ViewRedirector> pRedirector; 340 if ( ! bDisplayPresentationObjects) 341 pRedirector.reset(new ViewRedirector()); 342 343 try 344 { 345 mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get()); 346 } 347 catch (const ::com::sun::star::uno::Exception&) 348 { 349 DBG_UNHANDLED_EXCEPTION(); 350 } 351 352 // Restore the previous online spelling and redlining states. 353 if (pOutliner != NULL) 354 pOutliner->SetControlWord(nSavedControlWord); 355 } 356 357 358 359 360 void PreviewRenderer::PaintSubstitutionText (const String& rSubstitutionText) 361 { 362 if (rSubstitutionText.Len() > 0) 363 { 364 // Set the font size. 365 const Font& rOriginalFont (mpPreviewDevice->GetFont()); 366 Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont()); 367 sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height()); 368 aFont.SetHeight(nHeight); 369 mpPreviewDevice->SetFont (aFont); 370 371 // Paint the substitution text. 372 Rectangle aTextBox ( 373 Point(0,0), 374 mpPreviewDevice->PixelToLogic( 375 mpPreviewDevice->GetOutputSizePixel())); 376 sal_uInt16 nTextStyle = 377 TEXT_DRAW_CENTER 378 | TEXT_DRAW_VCENTER 379 | TEXT_DRAW_MULTILINE 380 | TEXT_DRAW_WORDBREAK; 381 mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle); 382 383 // Restore the font. 384 mpPreviewDevice->SetFont (rOriginalFont); 385 } 386 } 387 388 389 390 391 void PreviewRenderer::PaintFrame (void) 392 { 393 if (mbHasFrame) 394 { 395 // Paint a frame arround the preview. 396 Rectangle aPaintRectangle ( 397 Point(0,0), 398 mpPreviewDevice->GetOutputSizePixel()); 399 mpPreviewDevice->EnableMapMode(sal_False); 400 mpPreviewDevice->SetLineColor(maFrameColor); 401 mpPreviewDevice->SetFillColor(); 402 mpPreviewDevice->DrawRect(aPaintRectangle); 403 mpPreviewDevice->EnableMapMode(sal_True); 404 } 405 } 406 407 408 409 410 void PreviewRenderer::SetupOutputSize ( 411 const SdPage& rPage, 412 const Size& rFramePixelSize) 413 { 414 // First set the map mode to some arbitrary scale that is numerically 415 // stable. 416 MapMode aMapMode (mpPreviewDevice->GetMapMode()); 417 aMapMode.SetMapUnit(MAP_PIXEL); 418 419 // Adapt it to the desired width. 420 const Size aPageModelSize (rPage.GetSize()); 421 if (aPageModelSize.Width()>0 || aPageModelSize.Height()>0) 422 { 423 const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); 424 aMapMode.SetScaleX( 425 Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width())); 426 aMapMode.SetScaleY( 427 Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height())); 428 aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode)); 429 } 430 else 431 { 432 // We should never get here. 433 OSL_ASSERT(false); 434 aMapMode.SetScaleX(1.0); 435 aMapMode.SetScaleY(1.0); 436 } 437 mpPreviewDevice->SetMapMode (aMapMode); 438 mpPreviewDevice->SetOutputSizePixel(rFramePixelSize); 439 } 440 441 442 443 444 void PreviewRenderer::ProvideView (DrawDocShell* pDocShell) 445 { 446 if (pDocShell != mpDocShellOfView) 447 { 448 // Destroy the view that is connected to the current doc shell. 449 mpView.reset (NULL); 450 451 // Switch our attention, i.e. listening for DYING events, to 452 // the new doc shell. 453 if (mpDocShellOfView != NULL) 454 EndListening (*mpDocShellOfView); 455 mpDocShellOfView = pDocShell; 456 if (mpDocShellOfView != NULL) 457 StartListening (*mpDocShellOfView); 458 } 459 if (mpView.get() == NULL) 460 { 461 mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), NULL)); 462 } 463 mpView->SetPreviewRenderer(true); 464 #if 1 465 mpView->SetPageVisible(false); 466 mpView->SetPageBorderVisible(true); 467 mpView->SetBordVisible(false); 468 #else 469 // This works in the slide sorter but prevents the master page 470 // background being painted in the list of current master pages in the 471 // task manager. 472 mpView->SetPagePaintingAllowed(false); 473 #endif 474 } 475 476 477 478 479 Image PreviewRenderer::ScaleBitmap ( 480 const BitmapEx& rBitmapEx, 481 int nWidth) 482 { 483 Image aPreview; 484 485 do 486 { 487 // Adjust contrast mode. 488 bool bUseContrast = Application::GetSettings().GetStyleSettings(). 489 GetHighContrastMode(); 490 mpPreviewDevice->SetDrawMode (bUseContrast 491 ? ViewShell::OUTPUT_DRAWMODE_CONTRAST 492 : ViewShell::OUTPUT_DRAWMODE_COLOR); 493 494 // Set output size. 495 Size aSize (rBitmapEx.GetSizePixel()); 496 if (aSize.Width() <= 0) 497 break; 498 Size aFrameSize ( 499 nWidth, 500 (long)((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5)); 501 Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2); 502 MapMode aMapMode (mpPreviewDevice->GetMapMode()); 503 aMapMode.SetMapUnit(MAP_PIXEL); 504 aMapMode.SetOrigin (Point()); 505 aMapMode.SetScaleX (1.0); 506 aMapMode.SetScaleY (1.0); 507 mpPreviewDevice->SetMapMode (aMapMode); 508 mpPreviewDevice->SetOutputSize (aFrameSize); 509 510 // Paint a frame arround the preview. 511 mpPreviewDevice->SetLineColor (maFrameColor); 512 mpPreviewDevice->SetFillColor (); 513 mpPreviewDevice->DrawRect (Rectangle(Point(0,0), aFrameSize)); 514 515 // Paint the bitmap scaled to the desired width. 516 BitmapEx aScaledBitmap (rBitmapEx.GetBitmap()); 517 aScaledBitmap.Scale (aPreviewSize, BMP_SCALE_INTERPOLATE); 518 mpPreviewDevice->DrawBitmap ( 519 Point(1,1), 520 aPreviewSize, 521 aScaledBitmap.GetBitmap()); 522 523 // Get the resulting bitmap. 524 aPreview = mpPreviewDevice->GetBitmap (Point(0,0), aFrameSize); 525 } 526 while (false); 527 528 return aPreview; 529 } 530 531 532 533 534 void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint) 535 { 536 if (rHint.IsA(TYPE(SfxSimpleHint)) 537 && mpDocShellOfView != NULL) 538 { 539 const SfxSimpleHint* pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint); 540 if (pSimpleHint != NULL 541 && pSimpleHint->GetId() == SFX_HINT_DYING) 542 { 543 // The doc shell is dying. Our view uses its item pool and 544 // has to be destroyed as well. The next call to 545 // ProvideView will create a new one (for another 546 // doc shell, of course.) 547 mpView.reset (NULL); 548 mpDocShellOfView = NULL; 549 } 550 } 551 } 552 553 554 555 556 //===== ViewRedirector ======================================================== 557 558 namespace { 559 560 ViewRedirector::ViewRedirector (void) 561 { 562 } 563 564 565 566 567 ViewRedirector::~ViewRedirector (void) 568 { 569 } 570 571 572 573 574 drawinglayer::primitive2d::Primitive2DSequence ViewRedirector::createRedirectedPrimitive2DSequence( 575 const sdr::contact::ViewObjectContact& rOriginal, 576 const sdr::contact::DisplayInfo& rDisplayInfo) 577 { 578 SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); 579 580 if (pObject==NULL || pObject->GetPage() == NULL) 581 { 582 // not a SdrObject visualisation (maybe e.g. page) or no page 583 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( 584 rOriginal, 585 rDisplayInfo); 586 } 587 588 const bool bDoCreateGeometry (pObject->GetPage()->checkVisibility( rOriginal, rDisplayInfo, true)); 589 590 if ( ! bDoCreateGeometry 591 && (pObject->GetObjInventor() != SdrInventor || pObject->GetObjIdentifier() != OBJ_PAGE)) 592 { 593 return drawinglayer::primitive2d::Primitive2DSequence(); 594 } 595 596 if (pObject->IsEmptyPresObj()) 597 return drawinglayer::primitive2d::Primitive2DSequence(); 598 599 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( 600 rOriginal, 601 rDisplayInfo); 602 } 603 604 } // end of anonymous namespace 605 606 607 } // end of namespace ::sd 608