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 <set>
29 #include <vector>
30 
31 namespace {
32 
33 //rhbz#1007697 do this in two loops, one to collect the candidates
34 //and another to update them because updating a candidate can
35 //trigger the candidate to be deleted, so asking for its
36 //sibling after that is going to fail hard
37 class CandidateMgr
38 {
39  std::vector<VclPtr<vcl::Window> > m_aCandidates;
40  std::set<VclPtr<vcl::Window> > m_aDeletedCandidates;
41  DECL_LINK(WindowEventListener, VclWindowEvent&, void);
42 public:
43  void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect);
44  ~CandidateMgr();
45 };
46 
47 }
48 
49 IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent&, rEvent, void)
50 {
51  vcl::Window* pWindow = rEvent.GetWindow();
52  if (rEvent.GetId() == VclEventId::ObjectDying)
53  {
54  m_aDeletedCandidates.insert(pWindow);
55  }
56 }
57 
58 CandidateMgr::~CandidateMgr()
59 {
60  for (VclPtr<vcl::Window>& pCandidate : m_aCandidates)
61  {
62  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
63  continue;
64  pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
65  }
66 }
67 
68 void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
69 {
70  if (!rWindow.IsChildTransparentModeEnabled())
71  return;
72 
73  CandidateMgr aManager;
74  aManager.PaintTransparentChildren(rWindow, rPixelRect);
75 }
76 
77 void CandidateMgr::PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect)
78 {
79  vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
80  while (pCandidate)
81  {
82  if (pCandidate->IsPaintTransparent())
83  {
84  const tools::Rectangle aCandidatePosSizePixel(
85  pCandidate->GetPosPixel(),
86  pCandidate->GetSizePixel());
87 
88  if (aCandidatePosSizePixel.IsOver(rPixelRect))
89  {
90  m_aCandidates.emplace_back(pCandidate);
91  pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
92  }
93  }
94  pCandidate = pCandidate->GetWindow( GetWindowType::Next );
95  }
96 
97  for (const auto& rpCandidate : m_aCandidates)
98  {
99  pCandidate = rpCandidate.get();
100  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
101  continue;
102  //rhbz#1007697 this can cause the window itself to be
103  //deleted. So we are listening to see if that happens
104  //and if so, then skip the update
105  pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children);
106  // important: actually paint the child here!
107  if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
108  continue;
109  pCandidate->PaintImmediately();
110  }
111 }
112 
114 : mpOutputDevice(&rOriginal),
115  mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
116 {
117 }
118 
120 {
122 }
123 
125 {
126  // compare size of mpPreRenderDevice with size of visible area
128  {
130  }
131 
132  // Also compare the MapModes for zoom/scroll changes
134  {
136  }
137 
138  // #i29186#
141 }
142 
144 {
145  // region to pixels
146  const vcl::Region aRegionPixel(mpOutputDevice->LogicToPixel(rExpandedRegion));
147  //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
148  //Rectangle aRegionRectanglePixel;
149 
150  // MapModes off
151  bool bMapModeWasEnabledDest(mpOutputDevice->IsMapModeEnabled());
152  bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
155 
156  RectangleVector aRectangles;
157  aRegionPixel.GetRegionRectangles(aRectangles);
158 
159  for(const auto& rRect : aRectangles)
160  {
161  // for each rectangle, copy the area
162  const Point aTopLeft(rRect.TopLeft());
163  const Size aSize(rRect.GetSize());
164 
166  aTopLeft, aSize,
167  aTopLeft, aSize,
169  }
170 
171  mpOutputDevice->EnableMapMode(bMapModeWasEnabledDest);
172  mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
173 }
174 
176 {
177  Color aColA(getOptionsDrawinglayer().GetStripeColorA());
178  Color aColB(getOptionsDrawinglayer().GetStripeColorB());
179 
180  if (Application::GetSettings().GetStyleSettings().GetHighContrastMode())
181  {
183  aColB.Invert();
184  }
185 
186  xOverlayManager->setStripeColorA(aColA);
187  xOverlayManager->setStripeColorB(aColB);
188  xOverlayManager->setStripeLengthPixel(getOptionsDrawinglayer().GetStripeLength());
189 }
190 
192 {
194  // is it a window?
195  if (OUTDEV_WINDOW == rOutputDevice.GetOutDevType())
196  {
197  vcl::Window& rWindow = dynamic_cast<vcl::Window&>(rOutputDevice);
198  // decide which OverlayManager to use
200  {
201  // buffered OverlayManager, buffers its background and refreshes from there
202  // for pure overlay changes (no system redraw). The 3rd parameter specifies
203  // whether that refresh itself will use a 2nd vdev to avoid flickering.
204  // Also hand over the old OverlayManager if existent; this means to take over
205  // the registered OverlayObjects from it
206  xOverlayManager = sdr::overlay::OverlayManagerBuffered::create(rOutputDevice);
207  }
208  else
209  {
210  // unbuffered OverlayManager, just invalidates places where changes
211  // take place
212  // Also hand over the old OverlayManager if existent; this means to take over
213  // the registered OverlayObjects from it
214  xOverlayManager = sdr::overlay::OverlayManager::create(rOutputDevice);
215  }
216 
217  OSL_ENSURE(xOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)");
218 
219  // Request a repaint so that the buffered overlay manager fills
220  // its buffer properly. This is a workaround for missing buffer
221  // updates.
223  {
224  rWindow.Invalidate();
225  }
226 
227  InitOverlayManager(xOverlayManager);
228  }
229  return xOverlayManager;
230 }
231 
233 {
234  // not yet one created?
235  if(!mxOverlayManager.is())
237 }
238 
240 : mpOutputDevice(&rOut),
241  mpWindow(pWindow),
242  mrPaintView(rNewPaintView),
243  mbTemporaryTarget(false), // #i72889#
244  mbOutputToWindow(OUTDEV_WINDOW == mpOutputDevice->GetOutDevType()),
245  mpPatched(nullptr)
246 {
247 }
248 
250 {
251  mxOverlayManager.clear();
252 
254 }
255 
257 {
258  if(!mxOverlayManager.is())
259  {
260  // Create buffered overlay manager by default.
261  const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
262  }
263 
264  return mxOverlayManager;
265 }
266 
268 {
269  Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
270  return GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel));
271 }
272 
274 {
276  return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
277 }
278 
280 {
281  const bool bPrepareBufferedOutput(
283  && !OutputToPrinter()
286 
287  if(bPrepareBufferedOutput)
288  {
289  if(!mpPreRenderDevice)
290  {
292  }
293  }
294  else
295  {
297  }
298 
300  {
301  mpPreRenderDevice->PreparePreRenderDevice();
302  }
303 }
304 
306 {
307  mpPreRenderDevice.reset();
308 }
309 
311 {
313  {
314  mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion);
315  }
316 }
317 
318 // #i73602# add flag if buffer shall be used
320 {
321  // ## force creation of OverlayManager since the first repaint needs to
322  // save the background to get a controlled start into overlay mechanism
324 
325  if(mxOverlayManager.is() && !OutputToPrinter())
326  {
328  {
329  mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice());
330  }
331  else
332  {
333  mxOverlayManager->completeRedraw(rRegion);
334  }
335  }
336 }
337 
338 
340 {
341  maRedrawRegion = rNew;
342 }
343 
344 /* 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:1143
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
bool IsMapModeEnabled() const
virtual Size GetSizePixel() const
const MapMode & GetMapMode() const
void DestroyPreRenderDevice()
void InitOverlayManager(rtl::Reference< sdr::overlay::OverlayManager > xOverlayManager) const
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)
bool IsBufferedOverlayAllowed() const
Definition: svdpntv.cxx:1156
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
Point PixelToLogic(const Point &rDevicePt) const
Point LogicToPixel(const Point &rLogicPt) const
bool IsPause() const
void PreparePreRenderDevice()
void AddEventListener(const Link< VclWindowEvent &, void > &rEventListener)
const SvtOptionsDrawinglayer & getOptionsDrawinglayer() const
Definition: svdpntv.hxx:508
VclPtr< VirtualDevice > mpPreRenderDevice
void OutputPreRenderDevice(const vcl::Region &rExpandedRegion)
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
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