LibreOffice Module sd (master) 1
PreviewRenderer.cxx
Go to the documentation of this file.
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>
38
39#include <memory>
40
41using namespace ::com::sun::star;
42using namespace ::com::sun::star::uno;
43
44namespace sd {
45
48
49namespace {
53 class ViewRedirector : public sdr::contact::ViewObjectContactRedirector
54 {
55 public:
56 ViewRedirector();
57
58 virtual void createRedirectedPrimitive2DSequence(
59 const sdr::contact::ViewObjectContact& rOriginal,
60 const sdr::contact::DisplayInfo& rDisplayInfo,
62 };
63}
64
65//===== PreviewRenderer =======================================================
66
68 const bool bHasFrame)
69 : mpPreviewDevice (VclPtr<VirtualDevice>::Create()),
70 mpDocShellOfView(nullptr),
71 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
72 mbHasFrame(bHasFrame)
73{
74 mpPreviewDevice->SetBackground(Wallpaper(
75 Application::GetSettings().GetStyleSettings().GetWindowColor()));
76}
77
79{
80 if (mpDocShellOfView != nullptr)
82}
83
85 const SdPage* pPage,
86 const sal_Int32 nWidth)
87{
88 if (pPage != nullptr)
89 {
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));
96 return RenderPage (
97 pPage,
98 Size(nWidth,nHeight),
99 false/*bObeyHighContrastMode*/);
100 }
101 else
102 return Image();
103}
104
106 const SdPage* pPage,
107 Size aPixelSize,
108 const bool bObeyHighContrastMode,
109 const bool bDisplayPresentationObjects)
110{
111 Image aPreview;
112
113 if (pPage != nullptr)
114 {
115 try
116 {
117 if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
118 {
119 PaintPage(pPage, bDisplayPresentationObjects);
121 PaintFrame();
122
123 Size aSize (mpPreviewDevice->GetOutputSizePixel());
124 aPreview = Image(mpPreviewDevice->GetBitmapEx(
125 mpPreviewDevice->PixelToLogic(Point(0,0)),
126 mpPreviewDevice->PixelToLogic(aSize)));
127
128 mpView->HideSdrPage();
129 }
130 }
131 catch (const css::uno::Exception&)
132 {
133 DBG_UNHANDLED_EXCEPTION("sd.tools");
134 }
135 }
136
137 return aPreview;
138}
139
141 const Size& rPreviewPixelSize,
142 const OUString& rSubstitutionText)
143{
144 Image aPreview;
145
146 try
147 {
148 // Set size.
149 mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize);
150
151 // Adjust contrast mode.
152 const bool bUseContrast (
153 Application::GetSettings().GetStyleSettings().GetHighContrastMode());
154 mpPreviewDevice->SetDrawMode (bUseContrast
157
158 // Set a map mode that makes a typical substitution text completely
159 // visible.
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);
169
170 // Clear the background.
171 const ::tools::Rectangle aPaintRectangle (
172 Point(0,0),
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();
180
181 // Paint substitution text and a frame around it.
182 PaintSubstitutionText (rSubstitutionText);
183 PaintFrame();
184
185 const Size aSize (mpPreviewDevice->GetOutputSizePixel());
186 aPreview = Image(mpPreviewDevice->GetBitmapEx(
187 mpPreviewDevice->PixelToLogic(Point(0,0)),
188 mpPreviewDevice->PixelToLogic(aSize)));
189 }
190 catch (const css::uno::Exception&)
191 {
192 DBG_UNHANDLED_EXCEPTION("sd.tools");
193 }
194
195 return aPreview;
196}
197
199 const SdPage* pPage,
200 const Size& rPixelSize,
201 const bool bObeyHighContrastMode)
202{
203 if (!pPage)
204 return false;
205
206 SetupOutputSize(*pPage, rPixelSize);
207 SdDrawDocument& rDocument(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
208 DrawDocShell* pDocShell = rDocument.GetDocSh();
209
210 if (!pDocShell)
211 return false;
212
213 // Create view
214 ProvideView (pDocShell);
215 if (mpView == nullptr)
216 return false;
217
218 // Adjust contrast mode.
219 bool bUseContrast (bObeyHighContrastMode
220 && Application::GetSettings().GetStyleSettings().GetHighContrastMode());
221 mpPreviewDevice->SetDrawMode (bUseContrast
225
226 // Tell the view to show the given page.
227 SdPage* pNonConstPage = const_cast<SdPage*>(pPage);
228 if (pPage->IsMasterPage())
229 {
230 mpView->ShowSdrPage(mpView->GetModel().GetMasterPage(pPage->GetPageNum()));
231 }
232 else
233 {
234 mpView->ShowSdrPage(pNonConstPage);
235 }
236
237 // Make sure that a page view exists.
238 SdrPageView* pPageView = mpView->GetSdrPageView();
239
240 if (pPageView == nullptr)
241 return false;
242
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;
249
250 if (pPageView->GetApplicationDocumentColor() == COL_AUTO)
251 {
252 svtools::ColorConfig aColorConfig;
253 aApplicationDocumentColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor;
254 }
255 else
256 {
257 aApplicationDocumentColor = pPageView->GetApplicationDocumentColor();
258 }
259
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();
266
267 return true;
268}
269
271 const SdPage* pPage,
272 const bool bDisplayPresentationObjects)
273{
274 // Paint the page.
275 ::tools::Rectangle aPaintRectangle (Point(0,0), pPage->GetSize());
276 vcl::Region aRegion (aPaintRectangle);
277
278 // Turn off online spelling and redlining.
279 SdrOutliner* pOutliner = nullptr;
280 EEControlBits nSavedControlWord = EEControlBits::NONE;
281 if (mpDocShellOfView!=nullptr && mpDocShellOfView->GetDoc()!=nullptr)
282 {
283 pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner();
284 nSavedControlWord = pOutliner->GetControlWord();
285 pOutliner->SetControlWord(nSavedControlWord & ~EEControlBits::ONLINESPELLING);
286 }
287
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());
292
293 try
294 {
295 mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get());
296 }
297 catch (const css::uno::Exception&)
298 {
299 DBG_UNHANDLED_EXCEPTION("sd.tools");
300 }
301
302 // Restore the previous online spelling and redlining states.
303 if (pOutliner != nullptr)
304 pOutliner->SetControlWord(nSavedControlWord);
305}
306
307void PreviewRenderer::PaintSubstitutionText (const OUString& rSubstitutionText)
308{
309 if (rSubstitutionText.isEmpty())
310 return;
311
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);
318
319 // Paint the substitution text.
320 ::tools::Rectangle aTextBox (
321 Point(0,0),
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);
330
331 // Restore the font.
332 mpPreviewDevice->SetFont (rOriginalFont);
333}
334
336{
337 if (mbHasFrame)
338 {
339 // Paint a frame around the preview.
340 ::tools::Rectangle aPaintRectangle (
341 Point(0,0),
342 mpPreviewDevice->GetOutputSizePixel());
343 mpPreviewDevice->EnableMapMode(false);
344 mpPreviewDevice->SetLineColor(maFrameColor);
345 mpPreviewDevice->SetFillColor();
346 mpPreviewDevice->DrawRect(aPaintRectangle);
347 mpPreviewDevice->EnableMapMode();
348 }
349}
350
352 const SdPage& rPage,
353 const Size& rFramePixelSize)
354{
355 // First set the map mode to some arbitrary scale that is numerically
356 // stable.
357 MapMode aMapMode (mpPreviewDevice->GetMapMode());
358 aMapMode.SetMapUnit(MapUnit::MapPixel);
359
360 // Adapt it to the desired width.
361 const Size aPageModelSize (rPage.GetSize());
362 if (!aPageModelSize.IsEmpty())
363 {
364 const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
365 aMapMode.SetScaleX(
366 Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width()));
367 aMapMode.SetScaleY(
368 Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height()));
369 aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode));
370 }
371 else
372 {
373 // We should never get here.
374 OSL_ASSERT(false);
375 aMapMode.SetScaleX(Fraction(1.0));
376 aMapMode.SetScaleY(Fraction(1.0));
377 }
378 mpPreviewDevice->SetMapMode (aMapMode);
379 mpPreviewDevice->SetOutputSizePixel(rFramePixelSize);
380}
381
383{
384 if (pDocShell != mpDocShellOfView)
385 {
386 // Destroy the view that is connected to the current doc shell.
387 mpView.reset();
388
389 // Switch our attention, i.e. listening for DYING events, to
390 // the new doc shell.
391 if (mpDocShellOfView != nullptr)
393 mpDocShellOfView = pDocShell;
394 if (mpDocShellOfView != nullptr)
396 }
397 if (mpView == nullptr)
398 {
399 mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), nullptr));
400 }
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);
408}
409
411 const BitmapEx& rBitmapEx,
412 int nWidth)
413{
414 Image aPreview;
415
416 do
417 {
418 // Adjust contrast mode.
419 bool bUseContrast = Application::GetSettings().GetStyleSettings().
420 GetHighContrastMode();
421 mpPreviewDevice->SetDrawMode (bUseContrast
424
425 // Set output size.
426 Size aSize (rBitmapEx.GetSizePixel());
427 if (aSize.Width() <= 0)
428 break;
429 Size aFrameSize (
430 nWidth,
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);
440
441 // Paint a frame around the preview.
442 mpPreviewDevice->SetLineColor (maFrameColor);
443 mpPreviewDevice->SetFillColor ();
444 mpPreviewDevice->DrawRect (::tools::Rectangle(Point(0,0), aFrameSize));
445
446 // Paint the bitmap scaled to the desired width.
447 BitmapEx aScaledBitmap(rBitmapEx);
448 aScaledBitmap.Scale (aPreviewSize, BmpScaleFlag::BestQuality);
449 mpPreviewDevice->DrawBitmapEx (
450 Point(1,1),
451 aPreviewSize,
452 aScaledBitmap);
453
454 // Get the resulting bitmap.
455 aPreview = Image(mpPreviewDevice->GetBitmapEx(Point(0,0), aFrameSize));
456 }
457 while (false);
458
459 return aPreview;
460}
461
463{
464 if (!mpDocShellOfView)
465 return;
466
467 if (rHint.GetId() == SfxHintId::Dying)
468 {
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.)
473 mpView.reset();
474 mpDocShellOfView = nullptr;
475 }
476}
477
478//===== ViewRedirector ========================================================
479
480namespace {
481
482ViewRedirector::ViewRedirector()
483{
484}
485
486void ViewRedirector::createRedirectedPrimitive2DSequence(
487 const sdr::contact::ViewObjectContact& rOriginal,
488 const sdr::contact::DisplayInfo& rDisplayInfo,
490{
492
493 if (pObject==nullptr || pObject->getSdrPageFromSdrObject() == nullptr)
494 {
495 // not a SdrObject visualisation (maybe e.g. page) or no page
497 rOriginal,
498 rDisplayInfo,
499 rVisitor);
500 return;
501 }
502
503 const bool bDoCreateGeometry (pObject->getSdrPageFromSdrObject()->checkVisibility( rOriginal, rDisplayInfo, true));
504
505 if ( ! bDoCreateGeometry
506 && (pObject->GetObjInventor() != SdrInventor::Default || pObject->GetObjIdentifier() != SdrObjKind::Page))
507 {
508 return;
509 }
510
511 if (pObject->IsEmptyPresObj())
512 return;
513
515 rOriginal,
516 rDisplayInfo,
517 rVisitor);
518}
519
520} // end of anonymous namespace
521
522} // end of namespace ::sd
523
524/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
DrawTextFlags
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
const Size & GetSizePixel() const
void SetOrigin(const Point &rOrigin)
void SetScaleY(const Fraction &rScaleY)
void SetMapUnit(MapUnit eUnit)
void SetScaleX(const Fraction &rScaleX)
SAL_DLLPRIVATE LanguageType GetLanguage(const sal_uInt16 nId) const
Definition: drawdoc2.cxx:875
SAL_DLLPRIVATE::sd::DrawDocShell * GetDocSh() const
Definition: drawdoc.hxx:242
SdrOutliner & GetDrawOutliner(const SdrTextObj *pObj=nullptr) const
void SetApplicationDocumentColor(Color aDocumentColor)
const Color & GetApplicationDocumentColor() const
sal_uInt16 GetPageNum() const
bool IsMasterPage() const
Size GetSize() const
SdrModel & getSdrModelFromSdrPage() const
SfxHintId GetId() const
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
void EndListening(SfxBroadcaster &rBroadcaster, bool bRemoveAllDuplicates=false)
bool IsEmpty() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
reference_type * get() const
SdDrawDocument * GetDoc()
Derivative of sd::View; contains also a pointer to the document.
Definition: drawview.hxx:35
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
static const int snSubstitutionTextSize
void ProvideView(DrawDocShell *pDocShell)
When mpView is empty then create a new view and initialize it.
Image RenderSubstitution(const Size &rPreviewPixelSize, const OUString &sSubstitutionText)
Render an image that contains the given substitution text instead of a slide preview.
virtual ~PreviewRenderer() override
::std::unique_ptr< DrawView > mpView
Image ScaleBitmap(const BitmapEx &rBitmap, int nWidth)
Scale the given bitmap by keeping its aspect ratio to the desired width.
ScopedVclPtr< VirtualDevice > mpPreviewDevice
Image RenderPage(const SdPage *pPage, const sal_Int32 nWidth)
Render a page with the given pixel size.
static const int snFrameWidth
void SetupOutputSize(const SdPage &rPage, const Size &rPixelSize)
Set up the map mode so that the given page is renderer into a bitmap with the specified width.
DrawDocShell * mpDocShellOfView
void PaintPage(const SdPage *pPage, const bool bDisplayPresentationObjects)
bool Initialize(const SdPage *pPage, const Size &rPixelSize, const bool bObeyHighContrastMode)
void PaintSubstitutionText(const OUString &rSubstitutionText)
PreviewRenderer(const bool bPaintFrame=true)
Create a new preview renderer that takes some of its initial values from the given output device.
virtual SdrObject * TryToGetSdrObject() const
virtual void createRedirectedPrimitive2DSequence(const sdr::contact::ViewObjectContact &rOriginal, const sdr::contact::DisplayInfo &rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor &rVisitor)
ViewContact & GetViewContact() const
ColorConfigValue GetColorValue(ColorConfigEntry eEntry, bool bSmart=true) const
void SetFontHeight(tools::Long nHeight)
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
#define DBG_UNHANDLED_EXCEPTION(...)
EEControlBits
constexpr TypedWhichId< SvxLanguageItem > EE_CHAR_LANGUAGE(EE_CHAR_START+14)
EmbeddedObjectRef * pObject
@ ColorConfig
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
const DrawModeFlags OUTPUT_DRAWMODE_CONTRAST
Definition: ViewShell.hxx:72
const DrawModeFlags OUTPUT_DRAWMODE_COLOR
Definition: ViewShell.hxx:62
DOCBOUNDARIES
long Long