LibreOffice Module svx (master)  1
sdrpaintwindow.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 <comphelper/lok.hxx>
21 #include <osl/diagnose.h>
22 #include <svx/sdrpaintwindow.hxx>
24 #include <svx/svdpntv.hxx>
25 #include <vcl/gdimtf.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/settings.hxx>
28 #include <vcl/window.hxx>
30 #include <set>
31 #include <vector>
32 
33 namespace {
34 
35 //rhbz#1007697 do this in two loops, one to collect the candidates
36 //and another to update them because updating a candidate can
37 //trigger the candidate to be deleted, so asking for its
38 //sibling after that is going to fail hard
39 class CandidateMgr
40 {
41  std::vector<VclPtr<vcl::Window> > m_aCandidates;
42  std::set<VclPtr<vcl::Window> > m_aDeletedCandidates;
43  DECL_LINK(WindowEventListener, VclWindowEvent&, void);
44 public:
45  void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect);
46  ~CandidateMgr();
47 };
48 
49 }
50 
51 IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent&, rEvent, void)
52 {
53  vcl::Window* pWindow = rEvent.GetWindow();
54  if (rEvent.GetId() == VclEventId::ObjectDying)
55  {
56  m_aDeletedCandidates.insert(pWindow);
57  }
58 }
59 
60 CandidateMgr::~CandidateMgr()
61 {
62  for (VclPtr<vcl::Window>& pCandidate : m_aCandidates)
63  {
64  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
65  continue;
66  pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
67  }
68 }
69 
70 void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
71 {
72  if (!rWindow.IsChildTransparentModeEnabled())
73  return;
74 
75  CandidateMgr aManager;
76  aManager.PaintTransparentChildren(rWindow, rPixelRect);
77 }
78 
79 void CandidateMgr::PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
80 {
81  vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
82  while (pCandidate)
83  {
84  if (pCandidate->IsPaintTransparent())
85  {
86  const tools::Rectangle aCandidatePosSizePixel(
87  pCandidate->GetPosPixel(),
88  pCandidate->GetSizePixel());
89 
90  if (aCandidatePosSizePixel.Overlaps(rPixelRect))
91  {
92  m_aCandidates.emplace_back(pCandidate);
93  pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
94  }
95  }
96  pCandidate = pCandidate->GetWindow( GetWindowType::Next );
97  }
98 
99  for (const auto& rpCandidate : m_aCandidates)
100  {
101  pCandidate = rpCandidate.get();
102  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
103  continue;
104  //rhbz#1007697 this can cause the window itself to be
105  //deleted. So we are listening to see if that happens
106  //and if so, then skip the update
107  pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children);
108  // important: actually paint the child here!
109  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
110  continue;
111  pCandidate->PaintImmediately();
112  }
113 }
114 
116 : mpOutputDevice(&rOriginal),
117  mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
118 {
119 }
120 
122 {
124 }
125 
127 {
128  // compare size of mpPreRenderDevice with size of visible area
130  {
132  }
133 
134  // Also compare the MapModes for zoom/scroll changes
136  {
138  }
139 
140  // #i29186#
143 }
144 
146 {
147  // region to pixels
148  const vcl::Region aRegionPixel(mpOutputDevice->LogicToPixel(rExpandedRegion));
149  //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150  //Rectangle aRegionRectanglePixel;
151 
152  // MapModes off
153  bool bMapModeWasEnabledDest(mpOutputDevice->IsMapModeEnabled());
154  bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
157 
158  RectangleVector aRectangles;
159  aRegionPixel.GetRegionRectangles(aRectangles);
160 
161  for(const auto& rRect : aRectangles)
162  {
163  // for each rectangle, copy the area
164  const Point aTopLeft(rRect.TopLeft());
165  const Size aSize(rRect.GetSize());
166 
168  aTopLeft, aSize,
169  aTopLeft, aSize,
171  }
172 
173  mpOutputDevice->EnableMapMode(bMapModeWasEnabledDest);
174  mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
175 }
176 
178 {
181 
182  if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
183  {
185  aColB.Invert();
186  }
187 
188  xOverlayManager->setStripeColorA(aColA);
189  xOverlayManager->setStripeColorB(aColB);
190  xOverlayManager->setStripeLengthPixel(SvtOptionsDrawinglayer::GetStripeLength());
191 }
192 
194 {
196  // is it a window?
197  if (OUTDEV_WINDOW == rOutputDevice.GetOutDevType())
198  {
199  vcl::Window* pWindow = rOutputDevice.GetOwnerWindow();
200  // decide which OverlayManager to use
202  {
203  // buffered OverlayManager, buffers its background and refreshes from there
204  // for pure overlay changes (no system redraw). The 3rd parameter specifies
205  // whether that refresh itself will use a 2nd vdev to avoid flickering.
206  // Also hand over the old OverlayManager if existent; this means to take over
207  // the registered OverlayObjects from it
208  xOverlayManager = sdr::overlay::OverlayManagerBuffered::create(rOutputDevice);
209  }
210  else
211  {
212  // unbuffered OverlayManager, just invalidates places where changes
213  // take place
214  // Also hand over the old OverlayManager if existent; this means to take over
215  // the registered OverlayObjects from it
216  xOverlayManager = sdr::overlay::OverlayManager::create(rOutputDevice);
217  }
218 
219  OSL_ENSURE(xOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
220 
221  // Request a repaint so that the buffered overlay manager fills
222  // its buffer properly. This is a workaround for missing buffer
223  // updates.
225  {
226  pWindow->Invalidate();
227  }
228 
229  InitOverlayManager(xOverlayManager);
230  }
231  return xOverlayManager;
232 }
233 
235 {
236  // not yet one created?
237  if(!mxOverlayManager.is())
239 }
240 
242 : mpOutputDevice(&rOut),
243  mpWindow(pWindow),
244  mrPaintView(rNewPaintView),
245  mbTemporaryTarget(false), // #i72889#
246  mbOutputToWindow(OUTDEV_WINDOW == mpOutputDevice->GetOutDevType()),
247  mpPatched(nullptr)
248 {
249 }
250 
252 {
253  mxOverlayManager.clear();
254 
256 }
257 
259 {
260  if(!mxOverlayManager.is())
261  {
262  // Create buffered overlay manager by default.
263  const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
264  }
265 
266  return mxOverlayManager;
267 }
268 
270 {
271  Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
272  return GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel));
273 }
274 
276 {
278  return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
279 }
280 
282 {
283  const bool bPrepareBufferedOutput(
285  && !OutputToPrinter()
288 
289  if(bPrepareBufferedOutput)
290  {
291  if(!mpPreRenderDevice)
292  {
294  }
295  }
296  else
297  {
299  }
300 
302  {
303  mpPreRenderDevice->PreparePreRenderDevice();
304  }
305 }
306 
308 {
309  mpPreRenderDevice.reset();
310 }
311 
313 {
315  {
316  mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
317  }
318 }
319 
320 // #i73602# add flag if buffer shall be used
322 {
323  // ## force creation of OverlayManager since the first repaint needs to
324  // save the background to get a controlled start into overlay mechanism
326 
327  if(mxOverlayManager.is() && !OutputToPrinter())
328  {
330  {
331  mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
332  }
333  else
334  {
335  mxOverlayManager->completeRedraw(rRegion);
336  }
337  }
338 }
339 
340 
342 {
343  maRedrawRegion = rNew;
344 }
345 
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual Point GetPosPixel() const
OutDevType GetOutDevType() const
rtl::Reference< sdr::overlay::OverlayManager > mxOverlayManager
virtual bool IsVirtual() const
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const
bool IsBufferedOutputAllowed() const
Definition: svdpntv.cxx:1148
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
bool IsMapModeEnabled() const
virtual Size GetSizePixel() const
const MapMode & GetMapMode() const
void DestroyPreRenderDevice()
GDIMetaFile * GetConnectMetaFile() const
virtual void SetSettings(const AllSettings &rSettings)
bool IsRecord() const
void EnableMapMode(bool bEnable=true)
static rtl::Reference< OverlayManager > create(OutputDevice &rOutputDevice)
void PaintImmediately()
void SetMapMode()
const Color & GetHighlightColor() const
void PaintTransparentChildren(vcl::Window const &rWindow, tools::Rectangle const &rPixelRect)
paint the transparent children of rWin that overlap rPixelRect (for example, transparent form control...
std::vector< tools::Rectangle > RectangleVector
void SetDrawMode(DrawModeFlags nDrawMode)
void SetRedrawRegion(const vcl::Region &rNew)
tools::Rectangle GetVisibleArea() const
virtual rtl::Reference< sdr::overlay::OverlayManager > CreateOverlayManager(OutputDevice &rDevice) const
OUTDEV_WINDOW
VclPtr< OutputDevice > mpOutputDevice
bool IsChildTransparentModeEnabled() const
void Invert()
VclPtr< vcl::Window > mpWindow
SdrPaintWindow(SdrPaintView &rNewPaintView, OutputDevice &rOut, vcl::Window *pWindow=nullptr)
sal_uInt16 GetStripeLength()
bool IsBufferedOverlayAllowed() const
Definition: svdpntv.cxx:1161
bool SetOutputSizePixel(const Size &rNewSize, bool bErase=true)
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void Create(SvxOrientationItem &rItem, SvStream &rStrm, sal_uInt16)
Definition: legacyitem.cxx:34
SdrPreRenderDevice(OutputDevice &rOriginal)
static rtl::Reference< OverlayManager > create(OutputDevice &rOutputDevice)
IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent &, rEvent, void)
const AllSettings & GetSettings() const
Size GetOutputSizePixel() const
VclPtr< OutputDevice > mpOutputDevice
bool OutputToPrinter() const
DrawModeFlags GetDrawMode() const
vcl::Window * GetWindow(GetWindowType nType) const
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
bool IsPause() const
void PreparePreRenderDevice()
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
VclPtr< VirtualDevice > mpPreRenderDevice
void OutputPreRenderDevice(const vcl::Region &rExpandedRegion)
static void InitOverlayManager(rtl::Reference< sdr::overlay::OverlayManager > xOverlayManager)
bool IsPaintTransparent() const
void DrawOverlay(const vcl::Region &rRegion)
void OutputPreRenderDevice(const vcl::Region &rExpandedRegion)
void impCreateOverlayManager()
bool OutputToRecordingMetaFile() const
bool SupportsDoubleBuffering() const
vcl::Region maRedrawRegion
virtual vcl::Window * GetOwnerWindow() const
OutputDevice & GetOutputDevice() const
SAL_DLLPRIVATE void DrawOutDev(const Point &, const Size &, const Point &, const Size &, const Printer &)=delete
std::unique_ptr< SdrPreRenderDevice > mpPreRenderDevice
SdrPaintView & mrPaintView