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