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