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