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
PreviewRenderer(OutputDevice * pTemplate,const bool bHasFrame)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
~PreviewRenderer(void)99 PreviewRenderer::~PreviewRenderer (void)
100 {
101 if (mpDocShellOfView != NULL)
102 EndListening (*mpDocShellOfView);
103 }
104
105
106
107
RenderPage(const SdPage * pPage,const sal_Int32 nWidth,const String & rSubstitutionText,const bool bObeyHighContrastMode,const bool bDisplayPresentationObjects)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
RenderPage(const SdPage * pPage,Size aPixelSize,const String & rSubstitutionText,const bool bObeyHighContrastMode,const bool bDisplayPresentationObjects)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
RenderSubstitution(const Size & rPreviewPixelSize,const String & rSubstitutionText)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
Initialize(const SdPage * pPage,const Size & rPixelSize,const bool bObeyHighContrastMode)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
Cleanup(void)322 void PreviewRenderer::Cleanup (void)
323 {
324 mpView->HideSdrPage();
325 }
326
327
328
329
PaintPage(const SdPage * pPage,const bool bDisplayPresentationObjects)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
PaintSubstitutionText(const String & rSubstitutionText)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
PaintFrame(void)401 void PreviewRenderer::PaintFrame (void)
402 {
403 if (mbHasFrame)
404 {
405 // Paint a frame around 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
SetupOutputSize(const SdPage & rPage,const Size & rFramePixelSize)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
ProvideView(DrawDocShell * pDocShell)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();
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
ScaleBitmap(const BitmapEx & rBitmapEx,int nWidth)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 around 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
Notify(SfxBroadcaster &,const SfxHint & rHint)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();
558 mpDocShellOfView = NULL;
559 }
560 }
561 }
562
563
564
565
566 //===== ViewRedirector ========================================================
567
568 namespace {
569
ViewRedirector(void)570 ViewRedirector::ViewRedirector (void)
571 {
572 }
573
574
575
576
~ViewRedirector(void)577 ViewRedirector::~ViewRedirector (void)
578 {
579 }
580
581
582
583
createRedirectedPrimitive2DSequence(const sdr::contact::ViewObjectContact & rOriginal,const sdr::contact::DisplayInfo & rDisplayInfo)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