bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / tools / PreviewRenderer.cxx
blobb3eb95402df320ddcff11faa3435dbf253991311
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
25 #include <sdpage.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>
39 #include <memory>
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
44 namespace sd {
46 const int PreviewRenderer::snSubstitutionTextSize = 11;
47 const int PreviewRenderer::snFrameWidth = 1;
49 namespace {
50 /** This incarnation of the ViewObjectContactRedirector filters away all
51 PageObj objects, unconditionally.
53 class ViewRedirector : public sdr::contact::ViewObjectContactRedirector
55 public:
56 ViewRedirector();
58 virtual drawinglayer::primitive2d::Primitive2DContainer createRedirectedPrimitive2DSequence(
59 const sdr::contact::ViewObjectContact& rOriginal,
60 const sdr::contact::DisplayInfo& rDisplayInfo) override;
64 //===== PreviewRenderer =======================================================
66 PreviewRenderer::PreviewRenderer (
67 const bool bHasFrame)
68 : mpPreviewDevice (VclPtr<VirtualDevice>::Create()),
69 mpDocShellOfView(nullptr),
70 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
71 mbHasFrame(bHasFrame)
73 mpPreviewDevice->SetBackground(Wallpaper(
74 Application::GetSettings().GetStyleSettings().GetWindowColor()));
77 PreviewRenderer::~PreviewRenderer()
79 if (mpDocShellOfView != nullptr)
80 EndListening (*mpDocShellOfView);
83 Image PreviewRenderer::RenderPage (
84 const SdPage* pPage,
85 const sal_Int32 nWidth)
87 if (pPage != nullptr)
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));
95 return RenderPage (
96 pPage,
97 Size(nWidth,nHeight),
98 false/*bObeyHighContrastMode*/);
100 else
101 return Image();
104 Image PreviewRenderer::RenderPage (
105 const SdPage* pPage,
106 Size aPixelSize,
107 const bool bObeyHighContrastMode,
108 const bool bDisplayPresentationObjects)
110 Image aPreview;
112 if (pPage != nullptr)
116 if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
118 PaintPage(pPage, bDisplayPresentationObjects);
119 PaintSubstitutionText("");
120 PaintFrame();
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");
136 return aPreview;
139 Image PreviewRenderer::RenderSubstitution (
140 const Size& rPreviewPixelSize,
141 const OUString& rSubstitutionText)
143 Image aPreview;
147 // Set size.
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
158 // visible.
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 (
171 Point(0,0),
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);
182 PaintFrame();
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");
194 return aPreview;
197 bool PreviewRenderer::Initialize (
198 const SdPage* pPage,
199 const Size& rPixelSize,
200 const bool bObeyHighContrastMode)
202 if (!pPage)
203 return false;
205 SetupOutputSize(*pPage, rPixelSize);
206 SdDrawDocument& rDocument(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
207 DrawDocShell* pDocShell = rDocument.GetDocSh();
209 if (!pDocShell)
210 return false;
212 // Create view
213 ProvideView (pDocShell);
214 if (mpView == nullptr)
215 return false;
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()));
231 else
233 mpView->ShowSdrPage(pNonConstPage);
236 // Make sure that a page view exists.
237 SdrPageView* pPageView = mpView->GetSdrPageView();
239 if (pPageView == nullptr)
240 return false;
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;
254 else
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();
266 return true;
269 void PreviewRenderer::PaintPage (
270 const SdPage* pPage,
271 const bool bDisplayPresentationObjects)
273 // Paint the page.
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())
309 return;
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 (
320 Point(0,0),
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);
330 // Restore the font.
331 mpPreviewDevice->SetFont (rOriginalFont);
334 void PreviewRenderer::PaintFrame()
336 if (mbHasFrame)
338 // Paint a frame around the preview.
339 ::tools::Rectangle aPaintRectangle (
340 Point(0,0),
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 (
351 const SdPage& rPage,
352 const Size& rFramePixelSize)
354 // First set the map mode to some arbitrary scale that is numerically
355 // stable.
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);
364 aMapMode.SetScaleX(
365 Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width()));
366 aMapMode.SetScaleY(
367 Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height()));
368 aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode));
370 else
372 // We should never get here.
373 OSL_ASSERT(false);
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.
386 mpView.reset();
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);
401 #if 1
402 mpView->SetPageVisible(false);
403 mpView->SetPageBorderVisible();
404 mpView->SetBordVisible(false);
405 mpView->SetGridVisible(false);
406 mpView->SetHlplVisible(false);
407 mpView->SetGlueVisible(false);
409 #else
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
412 // task manager.
413 mpView->SetPagePaintingAllowed(false);
414 #endif
417 Image PreviewRenderer::ScaleBitmap (
418 const BitmapEx& rBitmapEx,
419 int nWidth)
421 Image aPreview;
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);
432 // Set output size.
433 Size aSize (rBitmapEx.GetSizePixel());
434 if (aSize.Width() <= 0)
435 break;
436 Size aFrameSize (
437 nWidth,
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 (
457 Point(1,1),
458 aPreviewSize,
459 aScaledBitmap.GetBitmap());
461 // Get the resulting bitmap.
462 aPreview = Image(mpPreviewDevice->GetBitmapEx(Point(0,0), aFrameSize));
464 while (false);
466 return aPreview;
469 void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint)
471 if (!mpDocShellOfView)
472 return;
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.)
480 mpView.reset();
481 mpDocShellOfView = nullptr;
485 //===== ViewRedirector ========================================================
487 namespace {
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(
503 rOriginal,
504 rDisplayInfo);
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(
519 rOriginal,
520 rDisplayInfo);
523 } // end of anonymous namespace
525 } // end of namespace ::sd
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */