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 <comphelper/diagnose_ex.hxx>
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 void createRedirectedPrimitive2DSequence(
59 const sdr::contact::ViewObjectContact
& rOriginal
,
60 const sdr::contact::DisplayInfo
& rDisplayInfo
,
61 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) override
;
65 //===== PreviewRenderer =======================================================
67 PreviewRenderer::PreviewRenderer (
69 : mpPreviewDevice (VclPtr
<VirtualDevice
>::Create()),
70 mpDocShellOfView(nullptr),
71 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES
).nColor
),
74 mpPreviewDevice
->SetBackground(Wallpaper(
75 Application::GetSettings().GetStyleSettings().GetWindowColor()));
78 PreviewRenderer::~PreviewRenderer()
80 if (mpDocShellOfView
!= nullptr)
81 EndListening (*mpDocShellOfView
);
84 Image
PreviewRenderer::RenderPage (
86 const sal_Int32 nWidth
)
90 const Size
aPageModelSize (pPage
->GetSize());
91 const double nAspectRatio (
92 double(aPageModelSize
.Width()) / double(aPageModelSize
.Height()));
93 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
94 const sal_Int32
nHeight (sal::static_int_cast
<sal_Int32
>(
95 (nWidth
- 2*nFrameWidth
) / nAspectRatio
+ 2*nFrameWidth
+ 0.5));
99 false/*bObeyHighContrastMode*/);
105 Image
PreviewRenderer::RenderPage (
108 const bool bObeyHighContrastMode
,
109 const bool bDisplayPresentationObjects
)
113 if (pPage
!= nullptr)
117 if (Initialize(pPage
, aPixelSize
, bObeyHighContrastMode
))
119 PaintPage(pPage
, bDisplayPresentationObjects
);
120 PaintSubstitutionText(u
""_ustr
);
123 Size
aSize (mpPreviewDevice
->GetOutputSizePixel());
124 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(
125 mpPreviewDevice
->PixelToLogic(Point(0,0)),
126 mpPreviewDevice
->PixelToLogic(aSize
)));
128 mpView
->HideSdrPage();
131 catch (const css::uno::Exception
&)
133 DBG_UNHANDLED_EXCEPTION("sd.tools");
140 Image
PreviewRenderer::RenderSubstitution (
141 const Size
& rPreviewPixelSize
,
142 const OUString
& rSubstitutionText
)
149 mpPreviewDevice
->SetOutputSizePixel(rPreviewPixelSize
);
151 // Adjust contrast mode.
152 const bool bUseContrast (
153 Application::GetSettings().GetStyleSettings().GetHighContrastMode());
154 mpPreviewDevice
->SetDrawMode (bUseContrast
155 ? sd::OUTPUT_DRAWMODE_CONTRAST
156 : sd::OUTPUT_DRAWMODE_COLOR
);
158 // Set a map mode that makes a typical substitution text completely
160 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
161 aMapMode
.SetMapUnit(MapUnit::Map100thMM
);
162 Fraction
aFinalScale(25 * rPreviewPixelSize
.Width(), 28000);
163 aMapMode
.SetScaleX(aFinalScale
);
164 aMapMode
.SetScaleY(aFinalScale
);
165 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
166 aMapMode
.SetOrigin(mpPreviewDevice
->PixelToLogic(
167 Point(nFrameWidth
,nFrameWidth
),aMapMode
));
168 mpPreviewDevice
->SetMapMode (aMapMode
);
170 // Clear the background.
171 const ::tools::Rectangle
aPaintRectangle (
173 mpPreviewDevice
->GetOutputSizePixel());
174 mpPreviewDevice
->EnableMapMode(false);
175 mpPreviewDevice
->SetLineColor();
176 svtools::ColorConfig aColorConfig
;
177 mpPreviewDevice
->SetFillColor(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
178 mpPreviewDevice
->DrawRect (aPaintRectangle
);
179 mpPreviewDevice
->EnableMapMode();
181 // Paint substitution text and a frame around it.
182 PaintSubstitutionText (rSubstitutionText
);
185 const Size
aSize (mpPreviewDevice
->GetOutputSizePixel());
186 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(
187 mpPreviewDevice
->PixelToLogic(Point(0,0)),
188 mpPreviewDevice
->PixelToLogic(aSize
)));
190 catch (const css::uno::Exception
&)
192 DBG_UNHANDLED_EXCEPTION("sd.tools");
198 bool PreviewRenderer::Initialize (
200 const Size
& rPixelSize
,
201 const bool bObeyHighContrastMode
)
206 SetupOutputSize(*pPage
, rPixelSize
);
207 SdDrawDocument
& rDocument(static_cast< SdDrawDocument
& >(pPage
->getSdrModelFromSdrPage()));
208 DrawDocShell
* pDocShell
= rDocument
.GetDocSh();
214 ProvideView (pDocShell
);
215 if (mpView
== nullptr)
218 // Adjust contrast mode.
219 bool bUseContrast (bObeyHighContrastMode
220 && Application::GetSettings().GetStyleSettings().GetHighContrastMode());
221 mpPreviewDevice
->SetDrawMode (bUseContrast
222 ? sd::OUTPUT_DRAWMODE_CONTRAST
223 : sd::OUTPUT_DRAWMODE_COLOR
);
224 mpPreviewDevice
->SetSettings(Application::GetSettings());
226 // Tell the view to show the given page.
227 SdPage
* pNonConstPage
= const_cast<SdPage
*>(pPage
);
228 if (pPage
->IsMasterPage())
230 mpView
->ShowSdrPage(mpView
->GetModel().GetMasterPage(pPage
->GetPageNum()));
234 mpView
->ShowSdrPage(pNonConstPage
);
237 // Make sure that a page view exists.
238 SdrPageView
* pPageView
= mpView
->GetSdrPageView();
240 if (pPageView
== nullptr)
243 // #i121224# No need to set SetApplicationBackgroundColor (which is the color
244 // of the area 'behind' the page (formerly called 'Wiese') since the page previews
245 // produced exactly cover the page's area, so it would never be visible. What
246 // needs to be set is the ApplicationDocumentColor which is derived from
247 // svtools::DOCCOLOR normally
248 Color aApplicationDocumentColor
;
250 if (pPageView
->GetApplicationDocumentColor() == COL_AUTO
)
252 svtools::ColorConfig aColorConfig
;
253 aApplicationDocumentColor
= aColorConfig
.GetColorValue( svtools::DOCCOLOR
).nColor
;
257 aApplicationDocumentColor
= pPageView
->GetApplicationDocumentColor();
260 pPageView
->SetApplicationDocumentColor(aApplicationDocumentColor
);
261 SdrOutliner
& rOutliner(rDocument
.GetDrawOutliner());
262 rOutliner
.SetBackgroundColor(aApplicationDocumentColor
);
263 rOutliner
.SetDefaultLanguage(rDocument
.GetLanguage(EE_CHAR_LANGUAGE
));
264 mpPreviewDevice
->SetBackground(Wallpaper(aApplicationDocumentColor
));
265 mpPreviewDevice
->Erase();
270 void PreviewRenderer::PaintPage (
272 const bool bDisplayPresentationObjects
)
275 ::tools::Rectangle
aPaintRectangle (Point(0,0), pPage
->GetSize());
276 vcl::Region
aRegion (aPaintRectangle
);
278 // Turn off online spelling and redlining.
279 SdrOutliner
* pOutliner
= nullptr;
280 EEControlBits nSavedControlWord
= EEControlBits::NONE
;
281 if (mpDocShellOfView
!=nullptr && mpDocShellOfView
->GetDoc()!=nullptr)
283 pOutliner
= &mpDocShellOfView
->GetDoc()->GetDrawOutliner();
284 nSavedControlWord
= pOutliner
->GetControlWord();
285 pOutliner
->SetControlWord(nSavedControlWord
& ~EEControlBits::ONLINESPELLING
);
288 // Use a special redirector to prevent PresObj shapes from being painted.
289 std::unique_ptr
<ViewRedirector
> pRedirector
;
290 if ( ! bDisplayPresentationObjects
)
291 pRedirector
.reset(new ViewRedirector());
295 mpView
->CompleteRedraw(mpPreviewDevice
.get(), aRegion
, pRedirector
.get());
297 catch (const css::uno::Exception
&)
299 DBG_UNHANDLED_EXCEPTION("sd.tools");
302 // Restore the previous online spelling and redlining states.
303 if (pOutliner
!= nullptr)
304 pOutliner
->SetControlWord(nSavedControlWord
);
307 void PreviewRenderer::PaintSubstitutionText (const OUString
& rSubstitutionText
)
309 if (rSubstitutionText
.isEmpty())
312 // Set the font size.
313 const vcl::Font
& rOriginalFont (mpPreviewDevice
->GetFont());
314 vcl::Font
aFont (mpPreviewDevice
->GetSettings().GetStyleSettings().GetAppFont());
315 sal_Int32
nHeight (mpPreviewDevice
->PixelToLogic(Size(0,snSubstitutionTextSize
)).Height());
316 aFont
.SetFontHeight(nHeight
);
317 mpPreviewDevice
->SetFont (aFont
);
319 // Paint the substitution text.
320 ::tools::Rectangle
aTextBox (
322 mpPreviewDevice
->PixelToLogic(
323 mpPreviewDevice
->GetOutputSizePixel()));
324 DrawTextFlags
const nTextStyle
=
325 DrawTextFlags::Center
326 | DrawTextFlags::VCenter
327 | DrawTextFlags::MultiLine
328 | DrawTextFlags::WordBreak
;
329 mpPreviewDevice
->DrawText (aTextBox
, rSubstitutionText
, nTextStyle
);
332 mpPreviewDevice
->SetFont (rOriginalFont
);
335 void PreviewRenderer::PaintFrame()
339 // Paint a frame around the preview.
340 ::tools::Rectangle
aPaintRectangle (
342 mpPreviewDevice
->GetOutputSizePixel());
343 mpPreviewDevice
->EnableMapMode(false);
344 mpPreviewDevice
->SetLineColor(maFrameColor
);
345 mpPreviewDevice
->SetFillColor();
346 mpPreviewDevice
->DrawRect(aPaintRectangle
);
347 mpPreviewDevice
->EnableMapMode();
351 void PreviewRenderer::SetupOutputSize (
353 const Size
& rFramePixelSize
)
355 // First set the map mode to some arbitrary scale that is numerically
357 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
358 aMapMode
.SetMapUnit(MapUnit::MapPixel
);
360 // Adapt it to the desired width.
361 const Size
aPageModelSize (rPage
.GetSize());
362 if (!aPageModelSize
.IsEmpty())
364 const sal_Int32
nFrameWidth (mbHasFrame
? snFrameWidth
: 0);
366 Fraction(rFramePixelSize
.Width()-2*nFrameWidth
-1, aPageModelSize
.Width()));
368 Fraction(rFramePixelSize
.Height()-2*nFrameWidth
-1, aPageModelSize
.Height()));
369 aMapMode
.SetOrigin(mpPreviewDevice
->PixelToLogic(Point(nFrameWidth
,nFrameWidth
),aMapMode
));
373 // We should never get here.
375 aMapMode
.SetScaleX(Fraction(1.0));
376 aMapMode
.SetScaleY(Fraction(1.0));
378 mpPreviewDevice
->SetMapMode (aMapMode
);
379 mpPreviewDevice
->SetOutputSizePixel(rFramePixelSize
);
382 void PreviewRenderer::ProvideView (DrawDocShell
* pDocShell
)
384 if (pDocShell
!= mpDocShellOfView
)
386 // Destroy the view that is connected to the current doc shell.
389 // Switch our attention, i.e. listening for DYING events, to
390 // the new doc shell.
391 if (mpDocShellOfView
!= nullptr)
392 EndListening (*mpDocShellOfView
);
393 mpDocShellOfView
= pDocShell
;
394 if (mpDocShellOfView
!= nullptr)
395 StartListening (*mpDocShellOfView
);
397 if (mpView
== nullptr)
399 mpView
.reset (new DrawView (pDocShell
, mpPreviewDevice
.get(), nullptr));
401 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 Image
PreviewRenderer::ScaleBitmap (
411 const BitmapEx
& rBitmapEx
,
418 // Adjust contrast mode.
419 bool bUseContrast
= Application::GetSettings().GetStyleSettings().
420 GetHighContrastMode();
421 mpPreviewDevice
->SetDrawMode (bUseContrast
422 ? sd::OUTPUT_DRAWMODE_CONTRAST
423 : sd::OUTPUT_DRAWMODE_COLOR
);
426 Size
aSize (rBitmapEx
.GetSizePixel());
427 if (aSize
.Width() <= 0)
431 static_cast<::tools::Long
>((nWidth
*1.0 * aSize
.Height()) / aSize
.Width() + 0.5));
432 Size
aPreviewSize (aFrameSize
.Width()-2,aFrameSize
.Height()-2);
433 MapMode
aMapMode (mpPreviewDevice
->GetMapMode());
434 aMapMode
.SetMapUnit(MapUnit::MapPixel
);
435 aMapMode
.SetOrigin (Point());
436 aMapMode
.SetScaleX (Fraction(1.0));
437 aMapMode
.SetScaleY (Fraction(1.0));
438 mpPreviewDevice
->SetMapMode (aMapMode
);
439 mpPreviewDevice
->SetOutputSize (aFrameSize
);
441 // Paint a frame around the preview.
442 mpPreviewDevice
->SetLineColor (maFrameColor
);
443 mpPreviewDevice
->SetFillColor ();
444 mpPreviewDevice
->DrawRect (::tools::Rectangle(Point(0,0), aFrameSize
));
446 // Paint the bitmap scaled to the desired width.
447 BitmapEx
aScaledBitmap(rBitmapEx
);
448 aScaledBitmap
.Scale (aPreviewSize
, BmpScaleFlag::BestQuality
);
449 mpPreviewDevice
->DrawBitmapEx (
454 // Get the resulting bitmap.
455 aPreview
= Image(mpPreviewDevice
->GetBitmapEx(Point(0,0), aFrameSize
));
462 void PreviewRenderer::Notify(SfxBroadcaster
&, const SfxHint
& rHint
)
464 if (!mpDocShellOfView
)
467 if (rHint
.GetId() == SfxHintId::Dying
)
469 // The doc shell is dying. Our view uses its item pool and
470 // has to be destroyed as well. The next call to
471 // ProvideView will create a new one (for another
472 // doc shell, of course.)
474 mpDocShellOfView
= nullptr;
478 //===== ViewRedirector ========================================================
482 ViewRedirector::ViewRedirector()
486 void ViewRedirector::createRedirectedPrimitive2DSequence(
487 const sdr::contact::ViewObjectContact
& rOriginal
,
488 const sdr::contact::DisplayInfo
& rDisplayInfo
,
489 drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
)
491 SdrObject
* pObject
= rOriginal
.GetViewContact().TryToGetSdrObject();
493 if (pObject
==nullptr || pObject
->getSdrPageFromSdrObject() == nullptr)
495 // not a SdrObject visualisation (maybe e.g. page) or no page
496 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
503 const bool bDoCreateGeometry (pObject
->getSdrPageFromSdrObject()->checkVisibility( rOriginal
, rDisplayInfo
, true));
505 if ( ! bDoCreateGeometry
506 && (pObject
->GetObjInventor() != SdrInventor::Default
|| pObject
->GetObjIdentifier() != SdrObjKind::Page
))
511 if (pObject
->IsEmptyPresObj())
514 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
520 } // end of anonymous namespace
522 } // end of namespace ::sd
524 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */