cid#1636690 Dereference after null check
[LibreOffice.git] / vcl / source / window / paint.cxx
blobfc6435ef46bd3667813639e3f9c0e717c17b509f
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 <config_features.h>
21 #include <vcl/gdimtf.hxx>
22 #include <vcl/window.hxx>
23 #include <vcl/virdev.hxx>
24 #include <vcl/cursor.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/syswin.hxx>
28 #include <sal/types.h>
29 #include <sal/log.hxx>
31 #include <window.h>
32 #include <salgdi.hxx>
33 #include <salframe.hxx>
34 #include <svdata.hxx>
35 #include <comphelper/lok.hxx>
36 #include <comphelper/profilezone.hxx>
37 #if HAVE_FEATURE_OPENGL
38 #include <vcl/opengl/OpenGLHelper.hxx>
39 #endif
41 // PaintBufferGuard
43 namespace vcl
45 PaintBufferGuard::PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
46 : mpFrameData(pFrameData),
47 m_pWindow(pWindow),
48 mbBackground(false),
49 mnOutOffX(0),
50 mnOutOffY(0)
52 if (!pFrameData->mpBuffer)
53 return;
55 // transfer various settings
56 // FIXME: this must disappear as we move to RenderContext only,
57 // the painting must become state-less, so that no actual
58 // vcl::Window setting affects this
59 mbBackground = pFrameData->mpBuffer->IsBackground();
60 if (pWindow->IsBackground())
62 maBackground = pFrameData->mpBuffer->GetBackground();
63 pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
65 //else
66 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
68 vcl::PushFlags nFlags = vcl::PushFlags::NONE;
69 nFlags |= vcl::PushFlags::CLIPREGION;
70 nFlags |= vcl::PushFlags::FILLCOLOR;
71 nFlags |= vcl::PushFlags::FONT;
72 nFlags |= vcl::PushFlags::LINECOLOR;
73 nFlags |= vcl::PushFlags::MAPMODE;
74 maSettings = pFrameData->mpBuffer->GetSettings();
75 nFlags |= vcl::PushFlags::REFPOINT;
76 nFlags |= vcl::PushFlags::TEXTCOLOR;
77 nFlags |= vcl::PushFlags::TEXTLINECOLOR;
78 nFlags |= vcl::PushFlags::OVERLINECOLOR;
79 nFlags |= vcl::PushFlags::TEXTFILLCOLOR;
80 nFlags |= vcl::PushFlags::TEXTALIGN;
81 nFlags |= vcl::PushFlags::RASTEROP;
82 nFlags |= vcl::PushFlags::TEXTLAYOUTMODE;
83 nFlags |= vcl::PushFlags::TEXTLANGUAGE;
84 pFrameData->mpBuffer->Push(nFlags);
85 auto& rDev = *pWindow->GetOutDev();
86 pFrameData->mpBuffer->SetClipRegion(rDev.GetClipRegion());
87 pFrameData->mpBuffer->SetFillColor(rDev.GetFillColor());
88 pFrameData->mpBuffer->SetFont(pWindow->GetFont());
89 pFrameData->mpBuffer->SetLineColor(rDev.GetLineColor());
90 pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
91 pFrameData->mpBuffer->SetRefPoint(rDev.GetRefPoint());
92 pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
93 pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
94 pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
95 pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
96 pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
97 pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
98 pFrameData->mpBuffer->SetRasterOp(rDev.GetRasterOp());
99 pFrameData->mpBuffer->SetLayoutMode(rDev.GetLayoutMode());
100 pFrameData->mpBuffer->SetDigitLanguage(rDev.GetDigitLanguage());
102 mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
103 mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
104 pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
105 pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
106 pFrameData->mpBuffer->EnableRTL(pWindow->IsRTLEnabled());
109 PaintBufferGuard::~PaintBufferGuard() COVERITY_NOEXCEPT_FALSE
111 if (!mpFrameData->mpBuffer)
112 return;
114 if (!m_aPaintRect.IsEmpty())
116 // copy the buffer content to the actual window
117 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
118 // painting directly instead of using Invalidate()
119 // [ie. everything you can see was painted directly to the
120 // window either above or in eg. an event handler]
121 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
123 // Make sure that the +1 value GetSize() adds to the size is in pixels.
124 Size aPaintRectSize;
125 if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
127 aPaintRectSize = m_aPaintRect.GetSize();
129 else
131 tools::Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
132 aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
135 m_pWindow->GetOutDev()->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer);
139 // Restore buffer state.
140 mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
141 mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
143 mpFrameData->mpBuffer->Pop();
144 mpFrameData->mpBuffer->SetSettings(maSettings);
145 if (mbBackground)
146 mpFrameData->mpBuffer->SetBackground(maBackground);
147 else
148 mpFrameData->mpBuffer->SetBackground();
151 void PaintBufferGuard::SetPaintRect(const tools::Rectangle& rRectangle)
153 m_aPaintRect = rRectangle;
156 vcl::RenderContext* PaintBufferGuard::GetRenderContext()
158 if (mpFrameData->mpBuffer)
159 return mpFrameData->mpBuffer;
160 else
161 return m_pWindow->GetOutDev();
165 class PaintHelper
167 private:
168 VclPtr<vcl::Window> m_pWindow;
169 std::unique_ptr<vcl::Region> m_pChildRegion;
170 tools::Rectangle m_aSelectionRect;
171 tools::Rectangle m_aPaintRect;
172 vcl::Region m_aPaintRegion;
173 ImplPaintFlags m_nPaintFlags;
174 bool m_bPop : 1;
175 bool m_bRestoreCursor : 1;
176 bool m_bStartedBufferedPaint : 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
177 public:
178 PaintHelper(vcl::Window* pWindow, ImplPaintFlags nPaintFlags);
179 void SetPop()
181 m_bPop = true;
183 void SetPaintRect(const tools::Rectangle& rRect)
185 m_aPaintRect = rRect;
187 void SetSelectionRect(const tools::Rectangle& rRect)
189 m_aSelectionRect = rRect;
191 void SetRestoreCursor(bool bRestoreCursor)
193 m_bRestoreCursor = bRestoreCursor;
195 bool GetRestoreCursor() const
197 return m_bRestoreCursor;
199 ImplPaintFlags GetPaintFlags() const
201 return m_nPaintFlags;
203 vcl::Region& GetPaintRegion()
205 return m_aPaintRegion;
207 void DoPaint(const vcl::Region* pRegion);
209 /// Start buffered paint: set it up to have the same settings as m_pWindow.
210 void StartBufferedPaint();
212 /// Paint the content of the buffer to the current m_pWindow.
213 void PaintBuffer();
215 ~PaintHelper();
218 PaintHelper::PaintHelper(vcl::Window *pWindow, ImplPaintFlags nPaintFlags)
219 : m_pWindow(pWindow)
220 , m_nPaintFlags(nPaintFlags)
221 , m_bPop(false)
222 , m_bRestoreCursor(false)
223 , m_bStartedBufferedPaint(false)
227 void PaintHelper::StartBufferedPaint()
229 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
230 assert(!pFrameData->mbInBufferedPaint);
232 pFrameData->mbInBufferedPaint = true;
233 pFrameData->maBufferedRect = tools::Rectangle();
234 m_bStartedBufferedPaint = true;
237 void PaintHelper::PaintBuffer()
239 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
240 assert(pFrameData->mbInBufferedPaint);
241 assert(m_bStartedBufferedPaint);
243 vcl::PaintBufferGuard aGuard(pFrameData, m_pWindow);
244 aGuard.SetPaintRect(pFrameData->maBufferedRect);
247 void PaintHelper::DoPaint(const vcl::Region* pRegion)
249 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
251 vcl::Region& rWinChildClipRegion = m_pWindow->ImplGetWinChildClipRegion();
252 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
253 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll || pFrameData->mbInBufferedPaint)
255 pWindowImpl->maInvalidateRegion = rWinChildClipRegion;
257 else
259 if (pRegion)
260 pWindowImpl->maInvalidateRegion.Union( *pRegion );
262 if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible)
263 /* #98602# need to repaint all children within the
264 * tracking rectangle, so the following invert
265 * operation takes places without traces of the previous
266 * one.
268 pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
270 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren)
271 m_pChildRegion.reset( new vcl::Region(pWindowImpl->maInvalidateRegion) );
272 pWindowImpl->maInvalidateRegion.Intersect(rWinChildClipRegion);
274 pWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
275 if (pWindowImpl->maInvalidateRegion.IsEmpty())
276 return;
278 #if HAVE_FEATURE_OPENGL
279 VCL_GL_INFO("PaintHelper::DoPaint on " <<
280 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
281 #endif
282 // double-buffering: setup the buffer if it does not exist
283 if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
284 StartBufferedPaint();
286 // double-buffering: if this window does not support double-buffering,
287 // but we are in the middle of double-buffered paint, we might be
288 // losing information
289 if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
290 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
292 if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
294 // double-buffering
295 vcl::PaintBufferGuard g(pFrameData, m_pWindow);
296 m_pWindow->ApplySettings(*pFrameData->mpBuffer);
298 m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer);
299 m_pWindow->Paint(*pFrameData->mpBuffer, m_aPaintRect);
300 pFrameData->maBufferedRect.Union(m_aPaintRect);
302 else
304 // direct painting
305 Wallpaper aBackground = m_pWindow->GetBackground();
306 m_pWindow->ApplySettings(*m_pWindow->GetOutDev());
307 // Restore bitmap background if it was lost.
308 if (aBackground.IsBitmap() && !m_pWindow->GetBackground().IsBitmap())
310 m_pWindow->SetBackground(aBackground);
312 m_pWindow->PushPaintHelper(this, *m_pWindow->GetOutDev());
313 m_pWindow->Paint(*m_pWindow->GetOutDev(), m_aPaintRect);
315 #if HAVE_FEATURE_OPENGL
316 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
317 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
318 #endif
321 namespace vcl
324 void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window const & rWindow,
325 const tools::Rectangle& rRect, sal_uInt16 nHighlight,
326 bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
327 Color* pSelectionTextColor, tools::Long nCornerRadius, Color const * pPaintColor)
329 if (rRect.IsEmpty())
330 return;
332 bool bRoundEdges = nCornerRadius > 0;
334 const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
336 // colors used for item highlighting
337 Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
338 Color aSelectionFillColor(aSelectionBorderColor);
340 bool bDark = rStyles.GetFaceColor().IsDark();
341 bool bBright = ( rStyles.GetFaceColor() == COL_WHITE );
343 int c1 = aSelectionBorderColor.GetLuminance();
344 int c2 = rWindow.GetBackgroundColor().GetLuminance();
346 if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
348 // contrast too low
349 sal_uInt16 h, s, b;
350 aSelectionFillColor.RGBtoHSB( h, s, b );
351 if( b > 50 ) b -= 40;
352 else b += 40;
353 aSelectionFillColor = Color::HSBtoRGB( h, s, b );
354 aSelectionBorderColor = aSelectionFillColor;
357 if (bRoundEdges)
359 if (aSelectionBorderColor.IsDark())
360 aSelectionBorderColor.IncreaseLuminance(128);
361 else
362 aSelectionBorderColor.DecreaseLuminance(128);
365 tools::Rectangle aRect(rRect);
366 if (bDrawExtBorderOnly)
368 aRect.AdjustLeft( -1 );
369 aRect.AdjustTop( -1 );
370 aRect.AdjustRight(1 );
371 aRect.AdjustBottom(1 );
373 rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
375 if (bDrawBorder)
376 rRenderContext.SetLineColor(bDark ? COL_WHITE : (bBright ? COL_BLACK : aSelectionBorderColor));
377 else
378 rRenderContext.SetLineColor();
380 sal_uInt16 nPercent = 0;
381 if (!nHighlight)
383 if (bDark)
384 aSelectionFillColor = COL_BLACK;
385 else
386 nPercent = 80; // just checked (light)
388 else
390 if (bChecked && nHighlight == 2)
392 if (bDark)
393 aSelectionFillColor = COL_LIGHTGRAY;
394 else if (bBright)
396 aSelectionFillColor = COL_BLACK;
397 rRenderContext.SetLineColor(COL_BLACK);
398 nPercent = 0;
400 else
401 nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
403 else if (bChecked || nHighlight == 1)
405 if (bDark)
406 aSelectionFillColor = COL_GRAY;
407 else if (bBright)
409 aSelectionFillColor = COL_BLACK;
410 rRenderContext.SetLineColor(COL_BLACK);
411 nPercent = 0;
413 else
414 nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
416 else
418 if (bDark)
419 aSelectionFillColor = COL_LIGHTGRAY;
420 else if (bBright)
422 aSelectionFillColor = COL_BLACK;
423 rRenderContext.SetLineColor(COL_BLACK);
424 if (nHighlight == 3)
425 nPercent = 80;
426 else
427 nPercent = 0;
429 else
430 nPercent = 70; // selected ( dark )
434 if (bDark && bDrawExtBorderOnly)
436 rRenderContext.SetFillColor();
437 if (pSelectionTextColor)
438 *pSelectionTextColor = rStyles.GetHighlightTextColor();
440 else
442 rRenderContext.SetFillColor(aSelectionFillColor);
443 if (pSelectionTextColor)
445 Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
446 Color aHLTextColor = rStyles.GetHighlightTextColor();
447 int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
448 int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
449 *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
453 if (bDark)
455 rRenderContext.DrawRect(aRect);
457 else
459 if (bRoundEdges)
461 tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
462 tools::PolyPolygon aPolyPoly(aPoly);
463 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
465 else
467 tools::Polygon aPoly(aRect);
468 tools::PolyPolygon aPolyPoly(aPoly);
469 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
473 rRenderContext.Pop(); // LINECOLOR | FILLCOLOR
476 void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
478 pHelper->SetPop();
480 if ( mpWindowImpl->mpCursor )
481 pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
483 GetOutDev()->mbInitClipRegion = true;
484 mpWindowImpl->mbInPaint = true;
486 // restore Paint-Region
487 vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
488 rPaintRegion = mpWindowImpl->maInvalidateRegion;
489 tools::Rectangle aPaintRect = rPaintRegion.GetBoundRect();
491 // RTL: re-mirror paint rect and region at this window
492 if (GetOutDev()->ImplIsAntiparallel())
494 rRenderContext.ReMirror(aPaintRect);
495 rRenderContext.ReMirror(rPaintRegion);
497 aPaintRect = GetOutDev()->ImplDevicePixelToLogic(aPaintRect);
498 mpWindowImpl->mpPaintRegion = &rPaintRegion;
499 mpWindowImpl->maInvalidateRegion.SetEmpty();
501 if ((pHelper->GetPaintFlags() & ImplPaintFlags::Erase) && rRenderContext.IsBackground())
503 if (rRenderContext.IsClipRegion())
505 vcl::Region aOldRegion = rRenderContext.GetClipRegion();
506 rRenderContext.SetClipRegion();
507 Erase(rRenderContext);
508 rRenderContext.SetClipRegion(aOldRegion);
510 else
511 Erase(rRenderContext);
514 // #98943# trigger drawing of toolbox selection after all children are painted
515 if (mpWindowImpl->mbDrawSelectionBackground)
516 pHelper->SetSelectionRect(aPaintRect);
517 pHelper->SetPaintRect(aPaintRect);
520 void Window::PopPaintHelper(PaintHelper const *pHelper)
522 if (mpWindowImpl->mpWinData)
524 if (mpWindowImpl->mbFocusVisible)
525 ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
527 mpWindowImpl->mbInPaint = false;
528 GetOutDev()->mbInitClipRegion = true;
529 mpWindowImpl->mpPaintRegion = nullptr;
530 if (mpWindowImpl->mpCursor)
531 mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
534 } /* namespace vcl */
536 PaintHelper::~PaintHelper()
538 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
539 if (m_bPop)
541 m_pWindow->PopPaintHelper(this);
544 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
545 if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
547 // Paint from the bottom child window and frontward.
548 vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
549 while (pTempWindow)
551 if (pTempWindow->mpWindowImpl->mbVisible)
552 pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
553 pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
557 if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
558 /* #98602# need to invert the tracking rect AFTER
559 * the children have painted
561 m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
563 // double-buffering: paint in case we created the buffer, the children are
564 // already painted inside
565 if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
567 PaintBuffer();
568 pFrameData->mbInBufferedPaint = false;
569 pFrameData->maBufferedRect = tools::Rectangle();
572 // #98943# draw toolbox selection
573 if( !m_aSelectionRect.IsEmpty() )
574 m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
577 namespace vcl {
579 void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
581 // call PrePaint. PrePaint may add to the invalidate region as well as
582 // other parameters used below.
583 PrePaint(*GetOutDev());
585 mpWindowImpl->mbPaintFrame = false;
587 if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
588 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll);
589 if (nPaintFlags & ImplPaintFlags::PaintChildren)
590 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren;
591 if (nPaintFlags & ImplPaintFlags::Erase)
592 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
593 if (nPaintFlags & ImplPaintFlags::CheckRtl)
594 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
595 if (!mpWindowImpl->mpFirstChild)
596 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
598 // If tiled rendering is used, windows are only invalidated, never painted to.
599 if (mpWindowImpl->mbPaintDisabled || comphelper::LibreOfficeKit::isActive())
601 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
602 Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
603 else if ( pRegion )
604 Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
606 // call PostPaint before returning
607 PostPaint(*GetOutDev());
609 return;
612 nPaintFlags = mpWindowImpl->mnPaintFlags & ~ImplPaintFlags::Paint;
614 PaintHelper aHelper(this, nPaintFlags);
616 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
617 aHelper.DoPaint(pRegion);
618 else
619 mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
621 // call PostPaint
622 PostPaint(*GetOutDev());
625 void Window::ImplCallOverlapPaint()
627 if (!mpWindowImpl)
628 return;
630 // emit overlapping windows first
631 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
632 while ( pTempWindow )
634 if ( pTempWindow->mpWindowImpl->mbReallyVisible )
635 pTempWindow->ImplCallOverlapPaint();
636 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
639 // only then ourself
640 if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
642 // RTL: notify ImplCallPaint to check for re-mirroring
643 // because we were called from the Sal layer
644 ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
648 IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void)
650 comphelper::ProfileZone aZone("VCL idle re-paint");
652 // save paint events until layout is done
653 if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
655 mpWindowImpl->mpFrameData->maPaintIdle.Start();
656 return;
659 // save paint events until resizing or initial sizing done
660 if (mpWindowImpl->mbFrame &&
661 mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
663 mpWindowImpl->mpFrameData->maPaintIdle.Start();
665 else if ( mpWindowImpl->mbReallyVisible )
667 ImplCallOverlapPaint();
668 if (comphelper::LibreOfficeKit::isActive() &&
669 mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
670 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
674 IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void)
676 comphelper::ProfileZone aZone("VCL idle resize");
678 if( mpWindowImpl->mbReallyVisible )
680 ImplCallResize();
681 if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
683 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
684 mpWindowImpl->mpFrameData->maPaintIdle.Invoke( nullptr );
689 void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
691 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
692 if ( !ImplIsOverlapWindow() )
694 vcl::Window* pTempWindow = this;
695 ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE;
698 pTempWindow = pTempWindow->ImplGetParent();
699 if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren )
700 break;
701 pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint;
702 if( ! pTempWindow->IsPaintTransparent() )
703 nTranspPaint = ImplPaintFlags::NONE;
705 while ( !pTempWindow->ImplIsOverlapWindow() );
708 // set Paint-Flags
709 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint;
710 if ( nFlags & InvalidateFlags::Children )
711 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren;
712 if ( !(nFlags & InvalidateFlags::NoErase) )
713 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
715 if ( !pRegion )
716 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll;
717 else if ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
719 // if not everything has to be redrawn, add the region to it
720 mpWindowImpl->maInvalidateRegion.Union( *pRegion );
723 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
724 if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
725 && ImplGetParent() )
727 vcl::Window *pParent = ImplGetParent();
728 while( pParent && pParent->IsPaintTransparent() )
729 pParent = pParent->ImplGetParent();
730 if( pParent )
732 vcl::Region *pChildRegion;
733 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
734 // invalidate the whole child window region in the parent
735 pChildRegion = &ImplGetWinChildClipRegion();
736 else
737 // invalidate the same region in the parent that has to be repainted in the child
738 pChildRegion = &mpWindowImpl->maInvalidateRegion;
740 nFlags |= InvalidateFlags::Children; // paint should also be done on all children
741 nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
742 pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
746 if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
747 mpWindowImpl->mpFrameData->maPaintIdle.Start();
750 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
752 vcl::Region aRegion = rRegion;
754 ImplClipBoundaries( aRegion, true, true );
755 if ( !aRegion.IsEmpty() )
756 ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
758 // now we invalidate the overlapping windows
759 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
760 while ( pTempWindow )
762 if ( pTempWindow->IsVisible() )
763 pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
765 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
769 void Window::ImplInvalidateParentFrameRegion( const vcl::Region& rRegion )
771 if ( mpWindowImpl->mbOverlapWin )
772 mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
773 else
775 if( ImplGetParent() )
776 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
780 void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
782 // check what has to be redrawn
783 bool bInvalidateAll = !pRegion;
785 // take Transparent-Invalidate into account
786 vcl::Window* pOpaqueWindow = this;
787 if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
789 vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
790 while ( pTempWindow )
792 if ( !pTempWindow->IsPaintTransparent() )
794 pOpaqueWindow = pTempWindow;
795 nFlags |= InvalidateFlags::Children;
796 bInvalidateAll = false;
797 break;
800 if ( pTempWindow->ImplIsOverlapWindow() )
801 break;
803 pTempWindow = pTempWindow->ImplGetParent();
807 // assemble region
808 InvalidateFlags nOrgFlags = nFlags;
809 if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
811 if ( GetStyle() & WB_CLIPCHILDREN )
812 nFlags |= InvalidateFlags::NoChildren;
813 else
814 nFlags |= InvalidateFlags::Children;
816 if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
817 bInvalidateAll = false;
818 if ( bInvalidateAll )
819 ImplInvalidateFrameRegion( nullptr, nFlags );
820 else
822 vcl::Region aRegion( GetOutputRectPixel() );
823 if ( pRegion )
825 // RTL: remirror region before intersecting it
826 if ( GetOutDev()->ImplIsAntiparallel() )
828 const OutputDevice *pOutDev = GetOutDev();
830 vcl::Region aRgn( *pRegion );
831 pOutDev->ReMirror( aRgn );
832 aRegion.Intersect( aRgn );
834 else
835 aRegion.Intersect( *pRegion );
837 ImplClipBoundaries( aRegion, true, true );
838 if ( nFlags & InvalidateFlags::NoChildren )
840 nFlags &= ~InvalidateFlags::Children;
841 if ( !(nFlags & InvalidateFlags::NoClipChildren) )
843 if ( nOrgFlags & InvalidateFlags::NoChildren )
844 ImplClipAllChildren( aRegion );
845 else
847 if ( ImplClipChildren( aRegion ) )
848 nFlags |= InvalidateFlags::Children;
852 if ( !aRegion.IsEmpty() )
853 ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
856 if ( nFlags & InvalidateFlags::Update )
857 pOpaqueWindow->PaintImmediately(); // start painting at the opaque parent
860 void Window::ImplMoveInvalidateRegion( const tools::Rectangle& rRect,
861 tools::Long nHorzScroll, tools::Long nVertScroll,
862 bool bChildren )
864 if ( (mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintAll)) == ImplPaintFlags::Paint )
866 vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
867 aTempRegion.Intersect( rRect );
868 aTempRegion.Move( nHorzScroll, nVertScroll );
869 mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
872 if ( bChildren && (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren) )
874 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
875 while ( pWindow )
877 pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
878 pWindow = pWindow->mpWindowImpl->mpNext;
883 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
884 tools::Long nHorzScroll, tools::Long nVertScroll,
885 bool bChildren )
887 // also shift Paint-Region when paints need processing
888 ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
889 // Paint-Region should be shifted, as drawn by the parents
890 if ( ImplIsOverlapWindow() )
891 return;
893 vcl::Region aPaintAllRegion;
894 vcl::Window* pPaintAllWindow = this;
897 pPaintAllWindow = pPaintAllWindow->ImplGetParent();
898 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
900 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
902 aPaintAllRegion.SetEmpty();
903 break;
905 else
906 aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
909 while ( !pPaintAllWindow->ImplIsOverlapWindow() );
910 if ( !aPaintAllRegion.IsEmpty() )
912 aPaintAllRegion.Move( nHorzScroll, nVertScroll );
913 InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
914 if ( bChildren )
915 nPaintFlags |= InvalidateFlags::Children;
916 ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
920 void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
922 if ( !pRegion )
923 mpWindowImpl->maInvalidateRegion.SetEmpty();
924 else
926 // when all child windows have to be drawn we need to invalidate them before doing so
927 if ( (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren) && mpWindowImpl->mpFirstChild )
929 vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
930 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
932 aChildRegion = GetOutputRectPixel();
934 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
935 while ( pChild )
937 pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
938 pChild = pChild->mpWindowImpl->mpNext;
941 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
943 mpWindowImpl->maInvalidateRegion = GetOutputRectPixel();
945 mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
947 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAll;
949 if ( nFlags & ValidateFlags::Children )
951 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
952 while ( pChild )
954 pChild->ImplValidateFrameRegion( pRegion, nFlags );
955 pChild = pChild->mpWindowImpl->mpNext;
960 void Window::ImplValidate()
962 // assemble region
963 bool bValidateAll = true;
964 ValidateFlags nFlags = ValidateFlags::NONE;
965 if ( GetStyle() & WB_CLIPCHILDREN )
966 nFlags |= ValidateFlags::NoChildren;
967 else
968 nFlags |= ValidateFlags::Children;
969 if ( (nFlags & ValidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
970 bValidateAll = false;
971 if ( bValidateAll )
972 ImplValidateFrameRegion( nullptr, nFlags );
973 else
975 vcl::Region aRegion( GetOutputRectPixel() );
976 ImplClipBoundaries( aRegion, true, true );
977 if ( nFlags & ValidateFlags::NoChildren )
979 nFlags &= ~ValidateFlags::Children;
980 if ( ImplClipChildren( aRegion ) )
981 nFlags |= ValidateFlags::Children;
983 if ( !aRegion.IsEmpty() )
984 ImplValidateFrameRegion( &aRegion, nFlags );
988 void Window::ImplUpdateAll()
990 if ( !mpWindowImpl || !mpWindowImpl->mbReallyVisible )
991 return;
993 bool bFlush = false;
994 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
996 Point aPoint( 0, 0 );
997 vcl::Region aRegion( tools::Rectangle( aPoint, GetOutputSizePixel() ) );
998 ImplInvalidateOverlapFrameRegion( aRegion );
999 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1000 bFlush = true;
1003 // an update changes the OverlapWindow, such that for later paints
1004 // not too much has to be drawn, if ALLCHILDREN etc. is set
1005 vcl::Window* pWindow = ImplGetFirstOverlapWindow();
1006 pWindow->ImplCallOverlapPaint();
1008 if ( bFlush )
1009 GetOutDev()->Flush();
1012 void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1016 void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1020 void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect)
1022 CallEventListeners(VclEventId::WindowPaint, const_cast<tools::Rectangle *>(&rRect));
1025 void Window::SetPaintTransparent( bool bTransparent )
1027 // transparency is not useful for frames as the background would have to be provided by a different frame
1028 if( bTransparent && mpWindowImpl->mbFrame )
1029 return;
1031 if ( mpWindowImpl->mpBorderWindow )
1032 mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1034 mpWindowImpl->mbPaintTransparent = bTransparent;
1037 void Window::SetWindowRegionPixel()
1040 if ( mpWindowImpl->mpBorderWindow )
1041 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1042 else if( mpWindowImpl->mbFrame )
1044 mpWindowImpl->maWinRegion = vcl::Region(true);
1045 mpWindowImpl->mbWinRegion = false;
1046 mpWindowImpl->mpFrame->ResetClipRegion();
1048 else
1050 if ( mpWindowImpl->mbWinRegion )
1052 mpWindowImpl->maWinRegion = vcl::Region(true);
1053 mpWindowImpl->mbWinRegion = false;
1054 ImplSetClipFlag();
1056 if ( IsReallyVisible() )
1058 vcl::Region aRegion( GetOutputRectPixel() );
1059 ImplInvalidateParentFrameRegion( aRegion );
1065 void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1068 if ( mpWindowImpl->mpBorderWindow )
1069 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1070 else if( mpWindowImpl->mbFrame )
1072 if( !rRegion.IsNull() )
1074 mpWindowImpl->maWinRegion = rRegion;
1075 mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1077 if( mpWindowImpl->mbWinRegion )
1079 // set/update ClipRegion
1080 RectangleVector aRectangles;
1081 mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1082 mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1084 for (auto const& rectangle : aRectangles)
1086 mpWindowImpl->mpFrame->UnionClipRegion(
1087 rectangle.Left(),
1088 rectangle.Top(),
1089 rectangle.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1090 rectangle.GetHeight()); // same for height
1093 mpWindowImpl->mpFrame->EndSetClipRegion();
1095 else
1096 SetWindowRegionPixel();
1098 else
1099 SetWindowRegionPixel();
1101 else
1103 if ( rRegion.IsNull() )
1105 if ( mpWindowImpl->mbWinRegion )
1107 mpWindowImpl->maWinRegion = vcl::Region(true);
1108 mpWindowImpl->mbWinRegion = false;
1109 ImplSetClipFlag();
1112 else
1114 mpWindowImpl->maWinRegion = rRegion;
1115 mpWindowImpl->mbWinRegion = true;
1116 ImplSetClipFlag();
1119 if ( IsReallyVisible() )
1121 vcl::Region aRegion( GetOutputRectPixel() );
1122 ImplInvalidateParentFrameRegion( aRegion );
1127 vcl::Region Window::GetPaintRegion() const
1130 if ( mpWindowImpl->mpPaintRegion )
1132 vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1133 aRegion.Move( -GetOutDev()->mnOutOffX, -GetOutDev()->mnOutOffY );
1134 return PixelToLogic( aRegion );
1136 else
1138 vcl::Region aPaintRegion(true);
1139 return aPaintRegion;
1143 void Window::Invalidate( InvalidateFlags nFlags )
1145 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1146 return;
1148 ImplInvalidate( nullptr, nFlags );
1149 LogicInvalidate(nullptr);
1152 void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1154 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1155 return;
1157 OutputDevice *pOutDev = GetOutDev();
1158 tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1159 if ( !aRect.IsEmpty() )
1161 vcl::Region aRegion( aRect );
1162 ImplInvalidate( &aRegion, nFlags );
1163 tools::Rectangle aLogicRectangle(rRect);
1164 LogicInvalidate(&aLogicRectangle);
1168 void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1170 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1171 return;
1173 if ( rRegion.IsNull() )
1175 ImplInvalidate( nullptr, nFlags );
1176 LogicInvalidate(nullptr);
1178 else
1180 vcl::Region aRegion = GetOutDev()->ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1181 if ( !aRegion.IsEmpty() )
1183 ImplInvalidate( &aRegion, nFlags );
1184 tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1185 LogicInvalidate(&aLogicRectangle);
1190 void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1192 if(pRectangle)
1194 tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1195 PixelInvalidate(&aRect);
1197 else
1198 PixelInvalidate(nullptr);
1201 bool Window::InvalidateByForeignEditView(EditView* )
1203 return false;
1206 void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1208 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1209 return;
1211 Size aSize = GetSizePixel();
1212 if (aSize.IsEmpty())
1213 return;
1215 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1217 // In case we are routing the window, notify the client
1218 std::vector<vcl::LOKPayloadItem> aPayload;
1219 tools::Rectangle aRect(Point(0, 0), aSize);
1220 if (pRectangle)
1221 aRect = *pRectangle;
1223 if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
1224 GetOutDev()->ReMirror(aRect);
1226 aPayload.emplace_back("rectangle", aRect.toString());
1228 pNotifier->notifyWindow(GetLOKWindowId(), u"invalidate"_ustr, aPayload);
1230 // Added for dialog items. Pass invalidation to the parent window.
1231 else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1233 const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1234 pParent->PixelInvalidate(&aRect);
1238 void Window::Validate()
1240 if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1241 return;
1243 ImplValidate();
1246 bool Window::HasPaintEvent() const
1249 if ( !mpWindowImpl->mbReallyVisible )
1250 return false;
1252 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1253 return true;
1255 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1256 return true;
1258 if ( !ImplIsOverlapWindow() )
1260 const vcl::Window* pTempWindow = this;
1263 pTempWindow = pTempWindow->ImplGetParent();
1264 if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1265 return true;
1267 while ( !pTempWindow->ImplIsOverlapWindow() );
1270 return false;
1273 void Window::PaintImmediately()
1275 if (!mpWindowImpl)
1276 return;
1278 if ( mpWindowImpl->mpBorderWindow )
1280 mpWindowImpl->mpBorderWindow->PaintImmediately();
1281 return;
1284 if ( !mpWindowImpl->mbReallyVisible )
1285 return;
1287 bool bFlush = false;
1288 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1290 Point aPoint( 0, 0 );
1291 vcl::Region aRegion( tools::Rectangle( aPoint, GetOutputSizePixel() ) );
1292 ImplInvalidateOverlapFrameRegion( aRegion );
1293 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1294 bFlush = true;
1297 // First we should skip all windows which are Paint-Transparent
1298 vcl::Window* pUpdateWindow = this;
1299 vcl::Window* pWindow = pUpdateWindow;
1300 while ( !pWindow->ImplIsOverlapWindow() )
1302 if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1304 pUpdateWindow = pWindow;
1305 break;
1307 pWindow = pWindow->ImplGetParent();
1309 // In order to limit drawing, an update only draws the window which
1310 // has PAINTALLCHILDREN set
1311 pWindow = pUpdateWindow;
1314 if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
1315 pUpdateWindow = pWindow;
1316 if ( pWindow->ImplIsOverlapWindow() )
1317 break;
1318 pWindow = pWindow->ImplGetParent();
1320 while ( pWindow );
1322 // if there is something to paint, trigger a Paint
1323 if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
1325 VclPtr<vcl::Window> xWindow(this);
1327 // trigger an update also for system windows on top of us,
1328 // otherwise holes would remain
1329 vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow();
1330 if (pUpdateOverlapWindow->mpWindowImpl)
1331 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpFirstOverlap;
1332 else
1333 pUpdateOverlapWindow = nullptr;
1334 while ( pUpdateOverlapWindow )
1336 pUpdateOverlapWindow->PaintImmediately();
1337 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1340 pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1342 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1343 pUpdateWindow->LogicInvalidate(nullptr);
1345 if (xWindow->isDisposed())
1346 return;
1348 bFlush = true;
1351 if ( bFlush )
1352 GetOutDev()->Flush();
1355 void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1357 // Special drawing when called through LOKit
1358 // TODO: Move to its own method
1359 if (comphelper::LibreOfficeKit::isActive())
1361 VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1362 pDevice->EnableRTL(IsRTLEnabled());
1364 Size aSize(GetOutputSizePixel());
1365 pDevice->SetOutputSizePixel(aSize);
1367 vcl::Font aCopyFont = GetFont();
1368 pDevice->SetFont(aCopyFont);
1370 pDevice->SetTextColor(GetTextColor());
1371 if (GetOutDev()->IsLineColor())
1372 pDevice->SetLineColor(GetOutDev()->GetLineColor());
1373 else
1374 pDevice->SetLineColor();
1376 if (GetOutDev()->IsFillColor())
1377 pDevice->SetFillColor(GetOutDev()->GetFillColor());
1378 else
1379 pDevice->SetFillColor();
1381 if (IsTextLineColor())
1382 pDevice->SetTextLineColor(GetTextLineColor());
1383 else
1384 pDevice->SetTextLineColor();
1386 if (IsOverlineColor())
1387 pDevice->SetOverlineColor(GetOverlineColor());
1388 else
1389 pDevice->SetOverlineColor();
1391 if (IsTextFillColor())
1392 pDevice->SetTextFillColor(GetTextFillColor());
1393 else
1394 pDevice->SetTextFillColor();
1396 pDevice->SetTextAlign(GetTextAlign());
1397 pDevice->SetRasterOp(GetOutDev()->GetRasterOp());
1399 tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1401 vcl::Region aClipRegion(GetOutDev()->GetClipRegion());
1402 pDevice->SetClipRegion();
1403 aClipRegion.Intersect(aPaintRect);
1404 pDevice->SetClipRegion(aClipRegion);
1406 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1407 Erase(*pDevice);
1409 pDevice->SetMapMode(GetMapMode());
1411 Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1413 i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1415 bool bHasMirroredGraphics = pDevice->HasMirroredGraphics();
1417 // get rid of virtual device now so they don't pile up during recursive calls
1418 pDevice.disposeAndClear();
1421 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1423 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1425 tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1426 if( bHasMirroredGraphics )
1427 nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1429 tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1431 Point aPos( i_rPos );
1432 aPos += Point(nDeltaX, nDeltaY);
1434 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1437 return;
1441 bool bRVisible = mpWindowImpl->mbReallyVisible;
1442 mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1443 bool bDevOutput = GetOutDev()->mbDevOutput;
1444 GetOutDev()->mbDevOutput = true;
1446 const OutputDevice *pOutDev = GetOutDev();
1447 tools::Long nOldDPIX = pOutDev->GetDPIX();
1448 tools::Long nOldDPIY = pOutDev->GetDPIY();
1449 GetOutDev()->mnDPIX = i_pTargetOutDev->GetDPIX();
1450 GetOutDev()->mnDPIY = i_pTargetOutDev->GetDPIY();
1451 bool bOutput = GetOutDev()->IsOutputEnabled();
1452 GetOutDev()->EnableOutput();
1454 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1455 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1456 return;
1458 // preserve graphicsstate
1459 GetOutDev()->Push();
1460 vcl::Region aClipRegion( GetOutDev()->GetClipRegion() );
1461 GetOutDev()->SetClipRegion();
1463 GDIMetaFile* pOldMtf = GetOutDev()->GetConnectMetaFile();
1464 GDIMetaFile aMtf;
1465 GetOutDev()->SetConnectMetaFile( &aMtf );
1467 // put a push action to metafile
1468 GetOutDev()->Push();
1469 // copy graphics state to metafile
1470 vcl::Font aCopyFont = GetFont();
1471 if( nOldDPIX != GetOutDev()->mnDPIX || nOldDPIY != GetOutDev()->mnDPIY )
1473 aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * GetOutDev()->mnDPIY / nOldDPIY );
1474 aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * GetOutDev()->mnDPIX / nOldDPIX );
1476 SetFont( aCopyFont );
1477 SetTextColor( GetTextColor() );
1478 if( GetOutDev()->IsLineColor() )
1479 GetOutDev()->SetLineColor( GetOutDev()->GetLineColor() );
1480 else
1481 GetOutDev()->SetLineColor();
1482 if( GetOutDev()->IsFillColor() )
1483 GetOutDev()->SetFillColor( GetOutDev()->GetFillColor() );
1484 else
1485 GetOutDev()->SetFillColor();
1486 if( IsTextLineColor() )
1487 SetTextLineColor( GetTextLineColor() );
1488 else
1489 SetTextLineColor();
1490 if( IsOverlineColor() )
1491 SetOverlineColor( GetOverlineColor() );
1492 else
1493 SetOverlineColor();
1494 if( IsTextFillColor() )
1495 SetTextFillColor( GetTextFillColor() );
1496 else
1497 SetTextFillColor();
1498 SetTextAlign( GetTextAlign() );
1499 GetOutDev()->SetRasterOp( GetOutDev()->GetRasterOp() );
1500 if( GetOutDev()->IsRefPoint() )
1501 GetOutDev()->SetRefPoint( GetOutDev()->GetRefPoint() );
1502 else
1503 GetOutDev()->SetRefPoint();
1504 GetOutDev()->SetLayoutMode( GetOutDev()->GetLayoutMode() );
1506 GetOutDev()->SetDigitLanguage( GetOutDev()->GetDigitLanguage() );
1507 tools::Rectangle aPaintRect(Point(0, 0), GetOutputSizePixel());
1508 aClipRegion.Intersect( aPaintRect );
1509 GetOutDev()->SetClipRegion( aClipRegion );
1511 // do the actual paint
1513 // background
1514 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1516 Erase(*GetOutDev());
1518 // foreground
1519 Paint(*GetOutDev(), aPaintRect);
1520 // put a pop action to metafile
1521 GetOutDev()->Pop();
1523 GetOutDev()->SetConnectMetaFile( pOldMtf );
1524 GetOutDev()->EnableOutput( bOutput );
1525 mpWindowImpl->mbReallyVisible = bRVisible;
1527 // paint metafile to VDev
1528 VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1529 DeviceFormat::WITH_ALPHA);
1531 pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel(), true, true );
1532 pMaskedDevice->EnableRTL( IsRTLEnabled() );
1533 aMtf.WindStart();
1534 aMtf.Play(*pMaskedDevice);
1535 BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), aPaintRect.GetSize() ) );
1536 i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
1537 // get rid of virtual device now so they don't pile up during recursive calls
1538 pMaskedDevice.disposeAndClear();
1540 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1542 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1544 tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1546 if( pOutDev->HasMirroredGraphics() )
1547 nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1548 tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1549 Point aPos( i_rPos );
1550 Point aDelta( nDeltaX, nDeltaY );
1551 aPos += aDelta;
1552 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1556 // restore graphics state
1557 GetOutDev()->Pop();
1559 GetOutDev()->EnableOutput( bOutput );
1560 mpWindowImpl->mbReallyVisible = bRVisible;
1561 GetOutDev()->mbDevOutput = bDevOutput;
1562 GetOutDev()->mnDPIX = nOldDPIX;
1563 GetOutDev()->mnDPIY = nOldDPIY;
1566 void Window::PaintToDevice(OutputDevice* pDev, const Point& rPos)
1568 if( !mpWindowImpl )
1569 return;
1571 SAL_WARN_IF( pDev->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1572 SAL_WARN_IF( pDev->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1574 vcl::Window* pRealParent = nullptr;
1575 if( ! mpWindowImpl->mbVisible )
1577 vcl::Window* pTempParent = ImplGetDefaultWindow();
1578 pTempParent->EnableChildTransparentMode();
1579 pRealParent = GetParent();
1580 SetParent( pTempParent );
1581 // trigger correct visibility flags for children
1582 Show();
1583 Hide();
1586 bool bVisible = mpWindowImpl->mbVisible;
1587 mpWindowImpl->mbVisible = true;
1589 if( mpWindowImpl->mpBorderWindow )
1590 mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1591 else
1592 ImplPaintToDevice( pDev, rPos );
1594 mpWindowImpl->mbVisible = bVisible;
1596 if( pRealParent )
1597 SetParent( pRealParent );
1600 void Window::Erase(vcl::RenderContext& rRenderContext)
1602 if (!GetOutDev()->IsDeviceOutputNecessary() || GetOutDev()->ImplIsRecordLayout())
1603 return;
1605 bool bNativeOK = false;
1607 ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1609 if (aCtrlPart == ControlPart::Entire && IsControlBackground())
1611 // nothing to do here; background is drawn in corresponding drawNativeControl implementation
1612 bNativeOK = true;
1614 else if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1616 tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1617 ControlState nState = ControlState::NONE;
1619 if (IsEnabled())
1620 nState |= ControlState::ENABLED;
1622 bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1623 nState, ImplControlValue(), OUString());
1626 if (GetOutDev()->mbBackground && !bNativeOK)
1628 RasterOp eRasterOp = GetOutDev()->GetRasterOp();
1629 if (eRasterOp != RasterOp::OverPaint)
1630 GetOutDev()->SetRasterOp(RasterOp::OverPaint);
1631 rRenderContext.DrawWallpaper(0, 0, GetOutDev()->mnOutWidth, GetOutDev()->mnOutHeight, GetOutDev()->maBackground);
1632 if (eRasterOp != RasterOp::OverPaint)
1633 rRenderContext.SetRasterOp(eRasterOp);
1636 if (GetOutDev()->mpAlphaVDev)
1637 GetOutDev()->mpAlphaVDev->Erase();
1640 void Window::ImplScroll( const tools::Rectangle& rRect,
1641 tools::Long nHorzScroll, tools::Long nVertScroll, ScrollFlags nFlags )
1643 if ( !GetOutDev()->IsDeviceOutputNecessary() )
1644 return;
1646 nHorzScroll = GetOutDev()->ImplLogicWidthToDevicePixel( nHorzScroll );
1647 nVertScroll = GetOutDev()->ImplLogicHeightToDevicePixel( nVertScroll );
1649 if ( !nHorzScroll && !nVertScroll )
1650 return;
1652 // There will be no CopyArea() call below, so invalidate the whole visible
1653 // area, not only the smaller one that was just scrolled in.
1654 // Do this when we have a double buffer anyway, or (tdf#152094) the device has a map mode enabled which
1655 // makes the conversion to pixel inaccurate
1656 const bool bCopyExistingAreaAndElideInvalidate = !SupportsDoubleBuffering() && !GetOutDev()->IsMapModeEnabled();
1658 if ( mpWindowImpl->mpCursor )
1659 mpWindowImpl->mpCursor->ImplSuspend();
1661 ScrollFlags nOrgFlags = nFlags;
1662 if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1664 if ( GetStyle() & WB_CLIPCHILDREN )
1665 nFlags |= ScrollFlags::NoChildren;
1666 else
1667 nFlags |= ScrollFlags::Children;
1670 vcl::Region aInvalidateRegion;
1671 bool bScrollChildren(nFlags & ScrollFlags::Children);
1673 if ( !mpWindowImpl->mpFirstChild )
1674 bScrollChildren = false;
1676 OutputDevice *pOutDev = GetOutDev();
1678 // RTL: check if this window requires special action
1679 bool bReMirror = GetOutDev()->ImplIsAntiparallel();
1681 tools::Rectangle aRectMirror( rRect );
1682 if( bReMirror )
1684 // make sure the invalidate region of this window is
1685 // computed in the same coordinate space as the one from the overlap windows
1686 pOutDev->ReMirror( aRectMirror );
1689 // adapt paint areas
1690 ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1692 ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1694 // if the scrolling on the device is performed in the opposite direction
1695 // then move the overlaps in that direction to compute the invalidate region
1696 // on the correct side, i.e., revert nHorzScroll
1697 if (!aInvalidateRegion.IsEmpty())
1699 aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1702 tools::Rectangle aDestRect(aRectMirror);
1703 aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1704 vcl::Region aWinInvalidateRegion(aRectMirror);
1705 if (bCopyExistingAreaAndElideInvalidate)
1706 aWinInvalidateRegion.Exclude(aDestRect);
1708 aInvalidateRegion.Union(aWinInvalidateRegion);
1710 vcl::Region aRegion( GetOutputRectPixel() );
1711 if ( nFlags & ScrollFlags::Clip )
1712 aRegion.Intersect( rRect );
1713 if ( mpWindowImpl->mbWinRegion )
1714 aRegion.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1716 aRegion.Exclude( aInvalidateRegion );
1718 ImplClipBoundaries( aRegion, false, true );
1719 if ( !bScrollChildren )
1721 if ( nOrgFlags & ScrollFlags::NoChildren )
1722 ImplClipAllChildren( aRegion );
1723 else
1724 ImplClipChildren( aRegion );
1726 if ( GetOutDev()->mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1727 aRegion.Intersect( GetOutDev()->maRegion );
1728 if ( !aRegion.IsEmpty() )
1730 if ( mpWindowImpl->mpWinData )
1732 if ( mpWindowImpl->mbFocusVisible )
1733 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1734 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1735 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1737 #ifndef IOS
1738 // This seems completely unnecessary with tiled rendering, and
1739 // causes the "AquaSalGraphics::copyArea() for non-layered
1740 // graphics" message. Presumably we should bypass this on all
1741 // platforms when dealing with a "window" that uses tiled
1742 // rendering at the moment. Unclear how to figure that out,
1743 // though. Also unclear whether we actually could just not
1744 // create a "frame window", whatever that exactly is, in the
1745 // tiled rendering case, or at least for platforms where tiles
1746 // rendering is all there is.
1748 SalGraphics* pGraphics = ImplGetFrameGraphics();
1749 // The invalidation area contains the area what would be copied here,
1750 // so avoid copying in case of double buffering.
1751 if (pGraphics && bCopyExistingAreaAndElideInvalidate)
1753 if( bReMirror )
1755 pOutDev->ReMirror( aRegion );
1758 pOutDev->SelectClipRegion( aRegion, pGraphics );
1759 pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1760 rRect.Left(), rRect.Top(),
1761 rRect.GetWidth(), rRect.GetHeight(),
1762 *GetOutDev() );
1764 #endif
1765 if ( mpWindowImpl->mpWinData )
1767 if ( mpWindowImpl->mbFocusVisible )
1768 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1769 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1770 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1774 if ( !aInvalidateRegion.IsEmpty() )
1776 // RTL: the invalidate region for this windows is already computed in frame coordinates
1777 // so it has to be re-mirrored before calling the Paint-handler
1778 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
1780 if ( !bScrollChildren )
1782 if ( nOrgFlags & ScrollFlags::NoChildren )
1783 ImplClipAllChildren( aInvalidateRegion );
1784 else
1785 ImplClipChildren( aInvalidateRegion );
1787 ImplInvalidateFrameRegion( &aInvalidateRegion, InvalidateFlags::Children );
1790 if ( bScrollChildren )
1792 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1793 while ( pWindow )
1795 Point aPos = pWindow->GetPosPixel();
1796 aPos += Point( nHorzScroll, nVertScroll );
1797 pWindow->SetPosPixel( aPos );
1799 pWindow = pWindow->mpWindowImpl->mpNext;
1803 if ( nFlags & ScrollFlags::Update )
1804 PaintImmediately();
1806 if ( mpWindowImpl->mpCursor )
1807 mpWindowImpl->mpCursor->ImplResume();
1810 } /* namespace vcl */
1813 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */