1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <PreviewRenderer.hxx>
22 #include <DrawDocShell.hxx>
23 #include <drawdoc.hxx>
24 #include <drawview.hxx>
26 #include <ViewShell.hxx>
27 #include <vcl/virdev.hxx>
28 #include <vcl/settings.hxx>
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>
41 using namespace ::com::sun::star
;
42 using namespace ::com::sun::star::uno
;
46 const int PreviewRenderer::snSubstitutionTextSize
= 11;
47 const int PreviewRenderer::snFrameWidth
= 1;
50 /** This incarnation of the ViewObjectContactRedirector filters away all
51 PageObj objects, unconditionally.
53 class ViewRedirector
: public sdr::contact::ViewObjectContactRedirector
58 virtual drawinglayer::primitive2d::Primitive2DContainer
createRedirectedPrimitive2DSequence(
59 const sdr::contact::ViewObjectContact
& rOriginal
,
60 const sdr::contact::DisplayInfo
& rDisplayInfo
) override
;
64 //===== PreviewRenderer =======================================================
66 PreviewRenderer::PreviewRenderer (
68 : mpPreviewDevice (VclPtr
<VirtualDevice
>::Create()),
69 mpDocShellOfView(nullptr),
70 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES
).nColor
),
73 mpPreviewDevice
->SetBackground(Wallpaper(
74 Application::GetSettings().GetStyleSettings().GetWindowColor()));
77 PreviewRenderer::~PreviewRenderer()
79 if (mpDocShellOfView
!= nullptr)
80 EndListening (*mpDocShellOfView
);
83 Image
PreviewRenderer::RenderPage (
85 const sal_Int32 nWidth
)
89 const Size
aPageModelSize (pPage
->GetSize());
90 const double nAspectRatio (
91 double(aPageModelSize
.Width()) / double(aPageModelSize
.Height()));
92 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
93 const sal_Int32
nHeight (sal::static_int_cast
<sal_Int32
>(
94 (nWidth
- 2*nFrameWidth
) / nAspectRatio
+ 2*nFrameWidth
+ 0.5));
98 false/*bObeyHighContrastMode*/);
104 Image
PreviewRenderer::RenderPage (
107 const bool bObeyHighContrastMode
,
108 const bool bDisplayPresentationObjects
)
112 if (pPage
!= nullptr)
116 if (Initialize(pPage
, aPixelSize
, bObeyHighContrastMode
))
118 PaintPage(pPage
, bDisplayPresentationObjects
);
119 PaintSubstitutionText("");
122 Size
aSize (mpPreviewDevice
->GetOutputSizePixel());
123 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(
124 mpPreviewDevice
->PixelToLogic(Point(0,0)),
125 mpPreviewDevice
->PixelToLogic(aSize
)));
127 mpView
->HideSdrPage();
130 catch (const css::uno::Exception
&)
132 DBG_UNHANDLED_EXCEPTION("sd.tools");
139 Image
PreviewRenderer::RenderSubstitution (
140 const Size
& rPreviewPixelSize
,
141 const OUString
& rSubstitutionText
)
148 mpPreviewDevice
->SetOutputSizePixel(rPreviewPixelSize
);
150 // Adjust contrast mode.
151 const bool bUseContrast (
152 Application::GetSettings().GetStyleSettings().GetHighContrastMode());
153 mpPreviewDevice
->SetDrawMode (bUseContrast
154 ? sd::OUTPUT_DRAWMODE_CONTRAST
155 : sd::OUTPUT_DRAWMODE_COLOR
);
157 // Set a map mode that makes a typical substitution text completely
159 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
160 aMapMode
.SetMapUnit(MapUnit::Map100thMM
);
161 Fraction
aFinalScale(25 * rPreviewPixelSize
.Width(), 28000);
162 aMapMode
.SetScaleX(aFinalScale
);
163 aMapMode
.SetScaleY(aFinalScale
);
164 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
165 aMapMode
.SetOrigin(mpPreviewDevice
->PixelToLogic(
166 Point(nFrameWidth
,nFrameWidth
),aMapMode
));
167 mpPreviewDevice
->SetMapMode (aMapMode
);
169 // Clear the background.
170 const ::tools::Rectangle
aPaintRectangle (
172 mpPreviewDevice
->GetOutputSizePixel());
173 mpPreviewDevice
->EnableMapMode(false);
174 mpPreviewDevice
->SetLineColor();
175 svtools::ColorConfig aColorConfig
;
176 mpPreviewDevice
->SetFillColor(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
177 mpPreviewDevice
->DrawRect (aPaintRectangle
);
178 mpPreviewDevice
->EnableMapMode();
180 // Paint substitution text and a frame around it.
181 PaintSubstitutionText (rSubstitutionText
);
184 const Size
aSize (mpPreviewDevice
->GetOutputSizePixel());
185 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(
186 mpPreviewDevice
->PixelToLogic(Point(0,0)),
187 mpPreviewDevice
->PixelToLogic(aSize
)));
189 catch (const css::uno::Exception
&)
191 DBG_UNHANDLED_EXCEPTION("sd.tools");
197 bool PreviewRenderer::Initialize (
199 const Size
& rPixelSize
,
200 const bool bObeyHighContrastMode
)
205 SetupOutputSize(*pPage
, rPixelSize
);
206 SdDrawDocument
& rDocument(static_cast< SdDrawDocument
& >(pPage
->getSdrModelFromSdrPage()));
207 DrawDocShell
* pDocShell
= rDocument
.GetDocSh();
213 ProvideView (pDocShell
);
214 if (mpView
== nullptr)
217 // Adjust contrast mode.
218 bool bUseContrast (bObeyHighContrastMode
219 && Application::GetSettings().GetStyleSettings().GetHighContrastMode());
220 mpPreviewDevice
->SetDrawMode (bUseContrast
221 ? sd::OUTPUT_DRAWMODE_CONTRAST
222 : sd::OUTPUT_DRAWMODE_COLOR
);
223 mpPreviewDevice
->SetSettings(Application::GetSettings());
225 // Tell the view to show the given page.
226 SdPage
* pNonConstPage
= const_cast<SdPage
*>(pPage
);
227 if (pPage
->IsMasterPage())
229 mpView
->ShowSdrPage(mpView
->GetModel()->GetMasterPage(pPage
->GetPageNum()));
233 mpView
->ShowSdrPage(pNonConstPage
);
236 // Make sure that a page view exists.
237 SdrPageView
* pPageView
= mpView
->GetSdrPageView();
239 if (pPageView
== nullptr)
242 // #i121224# No need to set SetApplicationBackgroundColor (which is the color
243 // of the area 'behind' the page (formerly called 'Wiese') since the page previews
244 // produced exactly cover the page's area, so it would never be visible. What
245 // needs to be set is the ApplicationDocumentColor which is derived from
246 // svtools::DOCCOLOR normally
247 Color aApplicationDocumentColor
;
249 if (pPageView
->GetApplicationDocumentColor() == COL_AUTO
)
251 svtools::ColorConfig aColorConfig
;
252 aApplicationDocumentColor
= aColorConfig
.GetColorValue( svtools::DOCCOLOR
).nColor
;
256 aApplicationDocumentColor
= pPageView
->GetApplicationDocumentColor();
259 pPageView
->SetApplicationDocumentColor(aApplicationDocumentColor
);
260 SdrOutliner
& rOutliner(rDocument
.GetDrawOutliner());
261 rOutliner
.SetBackgroundColor(aApplicationDocumentColor
);
262 rOutliner
.SetDefaultLanguage(rDocument
.GetLanguage(EE_CHAR_LANGUAGE
));
263 mpPreviewDevice
->SetBackground(Wallpaper(aApplicationDocumentColor
));
264 mpPreviewDevice
->Erase();
269 void PreviewRenderer::PaintPage (
271 const bool bDisplayPresentationObjects
)
274 ::tools::Rectangle
aPaintRectangle (Point(0,0), pPage
->GetSize());
275 vcl::Region
aRegion (aPaintRectangle
);
277 // Turn off online spelling and redlining.
278 SdrOutliner
* pOutliner
= nullptr;
279 EEControlBits nSavedControlWord
= EEControlBits::NONE
;
280 if (mpDocShellOfView
!=nullptr && mpDocShellOfView
->GetDoc()!=nullptr)
282 pOutliner
= &mpDocShellOfView
->GetDoc()->GetDrawOutliner();
283 nSavedControlWord
= pOutliner
->GetControlWord();
284 pOutliner
->SetControlWord(nSavedControlWord
& ~EEControlBits::ONLINESPELLING
);
287 // Use a special redirector to prevent PresObj shapes from being painted.
288 std::unique_ptr
<ViewRedirector
> pRedirector
;
289 if ( ! bDisplayPresentationObjects
)
290 pRedirector
.reset(new ViewRedirector());
294 mpView
->CompleteRedraw(mpPreviewDevice
.get(), aRegion
, pRedirector
.get());
296 catch (const css::uno::Exception
&)
298 DBG_UNHANDLED_EXCEPTION("sd.tools");
301 // Restore the previous online spelling and redlining states.
302 if (pOutliner
!= nullptr)
303 pOutliner
->SetControlWord(nSavedControlWord
);
306 void PreviewRenderer::PaintSubstitutionText (const OUString
& rSubstitutionText
)
308 if (rSubstitutionText
.isEmpty())
311 // Set the font size.
312 const vcl::Font
& rOriginalFont (mpPreviewDevice
->GetFont());
313 vcl::Font
aFont (mpPreviewDevice
->GetSettings().GetStyleSettings().GetAppFont());
314 sal_Int32
nHeight (mpPreviewDevice
->PixelToLogic(Size(0,snSubstitutionTextSize
)).Height());
315 aFont
.SetFontHeight(nHeight
);
316 mpPreviewDevice
->SetFont (aFont
);
318 // Paint the substitution text.
319 ::tools::Rectangle
aTextBox (
321 mpPreviewDevice
->PixelToLogic(
322 mpPreviewDevice
->GetOutputSizePixel()));
323 DrawTextFlags
const nTextStyle
=
324 DrawTextFlags::Center
325 | DrawTextFlags::VCenter
326 | DrawTextFlags::MultiLine
327 | DrawTextFlags::WordBreak
;
328 mpPreviewDevice
->DrawText (aTextBox
, rSubstitutionText
, nTextStyle
);
331 mpPreviewDevice
->SetFont (rOriginalFont
);
334 void PreviewRenderer::PaintFrame()
338 // Paint a frame around the preview.
339 ::tools::Rectangle
aPaintRectangle (
341 mpPreviewDevice
->GetOutputSizePixel());
342 mpPreviewDevice
->EnableMapMode(false);
343 mpPreviewDevice
->SetLineColor(maFrameColor
);
344 mpPreviewDevice
->SetFillColor();
345 mpPreviewDevice
->DrawRect(aPaintRectangle
);
346 mpPreviewDevice
->EnableMapMode();
350 void PreviewRenderer::SetupOutputSize (
352 const Size
& rFramePixelSize
)
354 // First set the map mode to some arbitrary scale that is numerically
356 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
357 aMapMode
.SetMapUnit(MapUnit::MapPixel
);
359 // Adapt it to the desired width.
360 const Size
aPageModelSize (rPage
.GetSize());
361 if (aPageModelSize
.Width()>0 || aPageModelSize
.Height()>0)
363 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
365 Fraction(rFramePixelSize
.Width()-2*nFrameWidth
-1, aPageModelSize
.Width()));
367 Fraction(rFramePixelSize
.Height()-2*nFrameWidth
-1, aPageModelSize
.Height()));
368 aMapMode
.SetOrigin(mpPreviewDevice
->PixelToLogic(Point(nFrameWidth
,nFrameWidth
),aMapMode
));
372 // We should never get here.
374 aMapMode
.SetScaleX(Fraction(1.0));
375 aMapMode
.SetScaleY(Fraction(1.0));
377 mpPreviewDevice
->SetMapMode (aMapMode
);
378 mpPreviewDevice
->SetOutputSizePixel(rFramePixelSize
);
381 void PreviewRenderer::ProvideView (DrawDocShell
* pDocShell
)
383 if (pDocShell
!= mpDocShellOfView
)
385 // Destroy the view that is connected to the current doc shell.
388 // Switch our attention, i.e. listening for DYING events, to
389 // the new doc shell.
390 if (mpDocShellOfView
!= nullptr)
391 EndListening (*mpDocShellOfView
);
392 mpDocShellOfView
= pDocShell
;
393 if (mpDocShellOfView
!= nullptr)
394 StartListening (*mpDocShellOfView
);
396 if (mpView
== nullptr)
398 mpView
.reset (new DrawView (pDocShell
, mpPreviewDevice
.get(), nullptr));
400 mpView
->SetPreviewRenderer(true);
402 mpView
->SetPageVisible(false);
403 mpView
->SetPageBorderVisible();
404 mpView
->SetBordVisible(false);
405 mpView
->SetGridVisible(false);
406 mpView
->SetHlplVisible(false);
407 mpView
->SetGlueVisible(false);
410 // This works in the slide sorter but prevents the master page
411 // background being painted in the list of current master pages in the
413 mpView
->SetPagePaintingAllowed(false);
417 Image
PreviewRenderer::ScaleBitmap (
418 const BitmapEx
& rBitmapEx
,
425 // Adjust contrast mode.
426 bool bUseContrast
= Application::GetSettings().GetStyleSettings().
427 GetHighContrastMode();
428 mpPreviewDevice
->SetDrawMode (bUseContrast
429 ? sd::OUTPUT_DRAWMODE_CONTRAST
430 : sd::OUTPUT_DRAWMODE_COLOR
);
433 Size
aSize (rBitmapEx
.GetSizePixel());
434 if (aSize
.Width() <= 0)
438 static_cast<long>((nWidth
*1.0 * aSize
.Height()) / aSize
.Width() + 0.5));
439 Size
aPreviewSize (aFrameSize
.Width()-2,aFrameSize
.Height()-2);
440 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
441 aMapMode
.SetMapUnit(MapUnit::MapPixel
);
442 aMapMode
.SetOrigin (Point());
443 aMapMode
.SetScaleX (Fraction(1.0));
444 aMapMode
.SetScaleY (Fraction(1.0));
445 mpPreviewDevice
->SetMapMode (aMapMode
);
446 mpPreviewDevice
->SetOutputSize (aFrameSize
);
448 // Paint a frame around the preview.
449 mpPreviewDevice
->SetLineColor (maFrameColor
);
450 mpPreviewDevice
->SetFillColor ();
451 mpPreviewDevice
->DrawRect (::tools::Rectangle(Point(0,0), aFrameSize
));
453 // Paint the bitmap scaled to the desired width.
454 BitmapEx
aScaledBitmap (rBitmapEx
.GetBitmap());
455 aScaledBitmap
.Scale (aPreviewSize
, BmpScaleFlag::BestQuality
);
456 mpPreviewDevice
->DrawBitmap (
459 aScaledBitmap
.GetBitmap());
461 // Get the resulting bitmap.
462 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(Point(0,0), aFrameSize
));
469 void PreviewRenderer::Notify(SfxBroadcaster
&, const SfxHint
& rHint
)
471 if (!mpDocShellOfView
)
474 if (rHint
.GetId() == SfxHintId::Dying
)
476 // The doc shell is dying. Our view uses its item pool and
477 // has to be destroyed as well. The next call to
478 // ProvideView will create a new one (for another
479 // doc shell, of course.)
481 mpDocShellOfView
= nullptr;
485 //===== ViewRedirector ========================================================
489 ViewRedirector::ViewRedirector()
493 drawinglayer::primitive2d::Primitive2DContainer
ViewRedirector::createRedirectedPrimitive2DSequence(
494 const sdr::contact::ViewObjectContact
& rOriginal
,
495 const sdr::contact::DisplayInfo
& rDisplayInfo
)
497 SdrObject
* pObject
= rOriginal
.GetViewContact().TryToGetSdrObject();
499 if (pObject
==nullptr || pObject
->getSdrPageFromSdrObject() == nullptr)
501 // not a SdrObject visualisation (maybe e.g. page) or no page
502 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
507 const bool bDoCreateGeometry (pObject
->getSdrPageFromSdrObject()->checkVisibility( rOriginal
, rDisplayInfo
, true));
509 if ( ! bDoCreateGeometry
510 && (pObject
->GetObjInventor() != SdrInventor::Default
|| pObject
->GetObjIdentifier() != OBJ_PAGE
))
512 return drawinglayer::primitive2d::Primitive2DContainer();
515 if (pObject
->IsEmptyPresObj())
516 return drawinglayer::primitive2d::Primitive2DContainer();
518 return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
523 } // end of anonymous namespace
525 } // end of namespace ::sd
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */