tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sd / source / ui / tools / PreviewRenderer.cxx
blob9425f0b16791f3eba57bf571e8abd9217610d8b0
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 <comphelper/diagnose_ex.hxx>
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 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 (
68 const bool bHasFrame)
69 : mpPreviewDevice (VclPtr<VirtualDevice>::Create()),
70 mpDocShellOfView(nullptr),
71 maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
72 mbHasFrame(bHasFrame)
74 mpPreviewDevice->SetBackground(Wallpaper(
75 Application::GetSettings().GetStyleSettings().GetWindowColor()));
78 PreviewRenderer::~PreviewRenderer()
80 if (mpDocShellOfView != nullptr)
81 EndListening (*mpDocShellOfView);
84 Image PreviewRenderer::RenderPage (
85 const SdPage* pPage,
86 const sal_Int32 nWidth)
88 if (pPage != nullptr)
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*/);
101 else
102 return Image();
105 Image PreviewRenderer::RenderPage (
106 const SdPage* pPage,
107 Size aPixelSize,
108 const bool bObeyHighContrastMode,
109 const bool bDisplayPresentationObjects)
111 Image aPreview;
113 if (pPage != nullptr)
117 if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
119 PaintPage(pPage, bDisplayPresentationObjects);
120 PaintSubstitutionText(u""_ustr);
121 PaintFrame();
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");
137 return aPreview;
140 Image PreviewRenderer::RenderSubstitution (
141 const Size& rPreviewPixelSize,
142 const OUString& rSubstitutionText)
144 Image aPreview;
148 // Set size.
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
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);
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();
181 // Paint substitution text and a frame around it.
182 PaintSubstitutionText (rSubstitutionText);
183 PaintFrame();
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");
195 return aPreview;
198 bool PreviewRenderer::Initialize (
199 const SdPage* pPage,
200 const Size& rPixelSize,
201 const bool bObeyHighContrastMode)
203 if (!pPage)
204 return false;
206 SetupOutputSize(*pPage, rPixelSize);
207 SdDrawDocument& rDocument(static_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
208 DrawDocShell* pDocShell = rDocument.GetDocSh();
210 if (!pDocShell)
211 return false;
213 // Create view
214 ProvideView (pDocShell);
215 if (mpView == nullptr)
216 return false;
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()));
232 else
234 mpView->ShowSdrPage(pNonConstPage);
237 // Make sure that a page view exists.
238 SdrPageView* pPageView = mpView->GetSdrPageView();
240 if (pPageView == nullptr)
241 return false;
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;
255 else
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();
267 return true;
270 void PreviewRenderer::PaintPage (
271 const SdPage* pPage,
272 const bool bDisplayPresentationObjects)
274 // Paint the page.
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())
310 return;
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 (
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);
331 // Restore the font.
332 mpPreviewDevice->SetFont (rOriginalFont);
335 void PreviewRenderer::PaintFrame()
337 if (mbHasFrame)
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();
351 void PreviewRenderer::SetupOutputSize (
352 const SdPage& rPage,
353 const Size& rFramePixelSize)
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);
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);
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));
371 else
373 // We should never get here.
374 OSL_ASSERT(false);
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.
387 mpView.reset();
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,
412 int nWidth)
414 Image aPreview;
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);
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);
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 (
450 Point(1,1),
451 aPreviewSize,
452 aScaledBitmap);
454 // Get the resulting bitmap.
455 aPreview = Image(mpPreviewDevice->GetBitmapEx(Point(0,0), aFrameSize));
457 while (false);
459 return aPreview;
462 void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint)
464 if (!mpDocShellOfView)
465 return;
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.)
473 mpView.reset();
474 mpDocShellOfView = nullptr;
478 //===== ViewRedirector ========================================================
480 namespace {
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(
497 rOriginal,
498 rDisplayInfo,
499 rVisitor);
500 return;
503 const bool bDoCreateGeometry (pObject->getSdrPageFromSdrObject()->checkVisibility( rOriginal, rDisplayInfo, true));
505 if ( ! bDoCreateGeometry
506 && (pObject->GetObjInventor() != SdrInventor::Default || pObject->GetObjIdentifier() != SdrObjKind::Page))
508 return;
511 if (pObject->IsEmptyPresObj())
512 return;
514 sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
515 rOriginal,
516 rDisplayInfo,
517 rVisitor);
520 } // end of anonymous namespace
522 } // end of namespace ::sd
524 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */