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 // Set background color of page view and outliner. 287 svtools::ColorConfig aColorConfig; 288 const Color aPageBackgroundColor(pPage->GetPageBackgroundColor(pPageView)); 289 pPageView->SetApplicationBackgroundColor(aPageBackgroundColor); 290 SdrOutliner& rOutliner (pDocument->GetDrawOutliner(NULL)); 291 rOutliner.SetBackgroundColor(aPageBackgroundColor); 292 rOutliner.SetDefaultLanguage(pDocument->GetLanguage(EE_CHAR_LANGUAGE)); 293 mpView->SetApplicationBackgroundColor( 294 Color(aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor)); 295 mpPreviewDevice->SetBackground(Wallpaper(aPageBackgroundColor)); 296 mpPreviewDevice->Erase(); 297 298 bSuccess = true; 299 } 300 while (false); 301 302 return bSuccess; 303 } 304 305 306 307 308 void PreviewRenderer::Cleanup (void) 309 { 310 mpView->HideSdrPage(); 311 } 312 313 314 315 316 void PreviewRenderer::PaintPage ( 317 const SdPage* pPage, 318 const bool bDisplayPresentationObjects) 319 { 320 // Paint the page. 321 Rectangle aPaintRectangle (Point(0,0), pPage->GetSize()); 322 Region aRegion (aPaintRectangle); 323 324 // Turn off online spelling and redlining. 325 SdrOutliner* pOutliner = NULL; 326 sal_uLong nSavedControlWord (0); 327 if (mpDocShellOfView!=NULL && mpDocShellOfView->GetDoc()!=NULL) 328 { 329 pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner(); 330 nSavedControlWord = pOutliner->GetControlWord(); 331 pOutliner->SetControlWord((nSavedControlWord & ~EE_CNTRL_ONLINESPELLING)); 332 } 333 334 // Use a special redirector to prevent PresObj shapes from being painted. 335 boost::scoped_ptr<ViewRedirector> pRedirector; 336 if ( ! bDisplayPresentationObjects) 337 pRedirector.reset(new ViewRedirector()); 338 339 try 340 { 341 mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get()); 342 } 343 catch (const ::com::sun::star::uno::Exception&) 344 { 345 DBG_UNHANDLED_EXCEPTION(); 346 } 347 348 // Restore the previous online spelling and redlining states. 349 if (pOutliner != NULL) 350 pOutliner->SetControlWord(nSavedControlWord); 351 } 352 353 354 355 356 void PreviewRenderer::PaintSubstitutionText (const String& rSubstitutionText) 357 { 358 if (rSubstitutionText.Len() > 0) 359 { 360 // Set the font size. 361 const Font& rOriginalFont (mpPreviewDevice->GetFont()); 362 Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont()); 363 sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height()); 364 aFont.SetHeight(nHeight); 365 mpPreviewDevice->SetFont (aFont); 366 367 // Paint the substitution text. 368 Rectangle aTextBox ( 369 Point(0,0), 370 mpPreviewDevice->PixelToLogic( 371 mpPreviewDevice->GetOutputSizePixel())); 372 sal_uInt16 nTextStyle = 373 TEXT_DRAW_CENTER 374 | TEXT_DRAW_VCENTER 375 | TEXT_DRAW_MULTILINE 376 | TEXT_DRAW_WORDBREAK; 377 mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle); 378 379 // Restore the font. 380 mpPreviewDevice->SetFont (rOriginalFont); 381 } 382 } 383 384 385 386 387 void PreviewRenderer::PaintFrame (void) 388 { 389 if (mbHasFrame) 390 { 391 // Paint a frame arround the preview. 392 Rectangle aPaintRectangle ( 393 Point(0,0), 394 mpPreviewDevice->GetOutputSizePixel()); 395 mpPreviewDevice->EnableMapMode(sal_False); 396 mpPreviewDevice->SetLineColor(maFrameColor); 397 mpPreviewDevice->SetFillColor(); 398 mpPreviewDevice->DrawRect(aPaintRectangle); 399 mpPreviewDevice->EnableMapMode(sal_True); 400 } 401 } 402 403 404 405 406 void PreviewRenderer::SetupOutputSize ( 407 const SdPage& rPage, 408 const Size& rFramePixelSize) 409 { 410 // First set the map mode to some arbitrary scale that is numerically 411 // stable. 412 MapMode aMapMode (mpPreviewDevice->GetMapMode()); 413 aMapMode.SetMapUnit(MAP_PIXEL); 414 415 // Adapt it to the desired width. 416 const Size aPageModelSize (rPage.GetSize()); 417 if (aPageModelSize.Width()>0 || aPageModelSize.Height()>0) 418 { 419 const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0); 420 aMapMode.SetScaleX( 421 Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width())); 422 aMapMode.SetScaleY( 423 Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height())); 424 aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode)); 425 } 426 else 427 { 428 // We should never get here. 429 OSL_ASSERT(false); 430 aMapMode.SetScaleX(1.0); 431 aMapMode.SetScaleY(1.0); 432 } 433 mpPreviewDevice->SetMapMode (aMapMode); 434 mpPreviewDevice->SetOutputSizePixel(rFramePixelSize); 435 } 436 437 438 439 440 void PreviewRenderer::ProvideView (DrawDocShell* pDocShell) 441 { 442 if (pDocShell != mpDocShellOfView) 443 { 444 // Destroy the view that is connected to the current doc shell. 445 mpView.reset (NULL); 446 447 // Switch our attention, i.e. listening for DYING events, to 448 // the new doc shell. 449 if (mpDocShellOfView != NULL) 450 EndListening (*mpDocShellOfView); 451 mpDocShellOfView = pDocShell; 452 if (mpDocShellOfView != NULL) 453 StartListening (*mpDocShellOfView); 454 } 455 if (mpView.get() == NULL) 456 { 457 mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), NULL)); 458 } 459 mpView->SetPreviewRenderer(true); 460 #if 1 461 mpView->SetPageVisible(false); 462 mpView->SetPageBorderVisible(true); 463 mpView->SetBordVisible(false); 464 #else 465 // This works in the slide sorter but prevents the master page 466 // background being painted in the list of current master pages in the 467 // task manager. 468 mpView->SetPagePaintingAllowed(false); 469 #endif 470 } 471 472 473 474 475 Image PreviewRenderer::ScaleBitmap ( 476 const BitmapEx& rBitmapEx, 477 int nWidth) 478 { 479 Image aPreview; 480 481 do 482 { 483 // Adjust contrast mode. 484 bool bUseContrast = Application::GetSettings().GetStyleSettings(). 485 GetHighContrastMode(); 486 mpPreviewDevice->SetDrawMode (bUseContrast 487 ? ViewShell::OUTPUT_DRAWMODE_CONTRAST 488 : ViewShell::OUTPUT_DRAWMODE_COLOR); 489 490 // Set output size. 491 Size aSize (rBitmapEx.GetSizePixel()); 492 if (aSize.Width() <= 0) 493 break; 494 Size aFrameSize ( 495 nWidth, 496 (long)((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5)); 497 Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2); 498 MapMode aMapMode (mpPreviewDevice->GetMapMode()); 499 aMapMode.SetMapUnit(MAP_PIXEL); 500 aMapMode.SetOrigin (Point()); 501 aMapMode.SetScaleX (1.0); 502 aMapMode.SetScaleY (1.0); 503 mpPreviewDevice->SetMapMode (aMapMode); 504 mpPreviewDevice->SetOutputSize (aFrameSize); 505 506 // Paint a frame arround the preview. 507 mpPreviewDevice->SetLineColor (maFrameColor); 508 mpPreviewDevice->SetFillColor (); 509 mpPreviewDevice->DrawRect (Rectangle(Point(0,0), aFrameSize)); 510 511 // Paint the bitmap scaled to the desired width. 512 BitmapEx aScaledBitmap (rBitmapEx.GetBitmap()); 513 aScaledBitmap.Scale (aPreviewSize, BMP_SCALE_INTERPOLATE); 514 mpPreviewDevice->DrawBitmap ( 515 Point(1,1), 516 aPreviewSize, 517 aScaledBitmap.GetBitmap()); 518 519 // Get the resulting bitmap. 520 aPreview = mpPreviewDevice->GetBitmap (Point(0,0), aFrameSize); 521 } 522 while (false); 523 524 return aPreview; 525 } 526 527 528 529 530 void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint) 531 { 532 if (rHint.IsA(TYPE(SfxSimpleHint)) 533 && mpDocShellOfView != NULL) 534 { 535 const SfxSimpleHint* pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint); 536 if (pSimpleHint != NULL 537 && pSimpleHint->GetId() == SFX_HINT_DYING) 538 { 539 // The doc shell is dying. Our view uses its item pool and 540 // has to be destroyed as well. The next call to 541 // ProvideView will create a new one (for another 542 // doc shell, of course.) 543 mpView.reset (NULL); 544 mpDocShellOfView = NULL; 545 } 546 } 547 } 548 549 550 551 552 //===== ViewRedirector ======================================================== 553 554 namespace { 555 556 ViewRedirector::ViewRedirector (void) 557 { 558 } 559 560 561 562 563 ViewRedirector::~ViewRedirector (void) 564 { 565 } 566 567 568 569 570 drawinglayer::primitive2d::Primitive2DSequence ViewRedirector::createRedirectedPrimitive2DSequence( 571 const sdr::contact::ViewObjectContact& rOriginal, 572 const sdr::contact::DisplayInfo& rDisplayInfo) 573 { 574 SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); 575 576 if (pObject==NULL || pObject->GetPage() == NULL) 577 { 578 // not a SdrObject visualisation (maybe e.g. page) or no page 579 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( 580 rOriginal, 581 rDisplayInfo); 582 } 583 584 const bool bDoCreateGeometry (pObject->GetPage()->checkVisibility( rOriginal, rDisplayInfo, true)); 585 586 if ( ! bDoCreateGeometry 587 && (pObject->GetObjInventor() != SdrInventor || pObject->GetObjIdentifier() != OBJ_PAGE)) 588 { 589 return drawinglayer::primitive2d::Primitive2DSequence(); 590 } 591 592 if (pObject->IsEmptyPresObj()) 593 return drawinglayer::primitive2d::Primitive2DSequence(); 594 595 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( 596 rOriginal, 597 rDisplayInfo); 598 } 599 600 } // end of anonymous namespace 601 602 603 } // end of namespace ::sd 604