Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / window / paint.cxx
blob377d7d46d37af598ce426f4178e7ae24715d0173
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 PaintBufferGuard::PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
44 : mpFrameData(pFrameData),
45 m_pWindow(pWindow),
46 mbBackground(false),
47 mnOutOffX(0),
48 mnOutOffY(0)
50 if (!pFrameData->mpBuffer)
51 return;
53 // transfer various settings
54 // FIXME: this must disappear as we move to RenderContext only,
55 // the painting must become state-less, so that no actual
56 // vcl::Window setting affects this
57 mbBackground = pFrameData->mpBuffer->IsBackground();
58 if (pWindow->IsBackground())
60 maBackground = pFrameData->mpBuffer->GetBackground();
61 pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
63 //else
64 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
66 PushFlags nFlags = PushFlags::NONE;
67 nFlags |= PushFlags::CLIPREGION;
68 nFlags |= PushFlags::FILLCOLOR;
69 nFlags |= PushFlags::FONT;
70 nFlags |= PushFlags::LINECOLOR;
71 nFlags |= PushFlags::MAPMODE;
72 maSettings = pFrameData->mpBuffer->GetSettings();
73 nFlags |= PushFlags::REFPOINT;
74 nFlags |= PushFlags::TEXTCOLOR;
75 nFlags |= PushFlags::TEXTLINECOLOR;
76 nFlags |= PushFlags::OVERLINECOLOR;
77 nFlags |= PushFlags::TEXTFILLCOLOR;
78 nFlags |= PushFlags::TEXTALIGN;
79 nFlags |= PushFlags::RASTEROP;
80 nFlags |= PushFlags::TEXTLAYOUTMODE;
81 nFlags |= PushFlags::TEXTLANGUAGE;
82 pFrameData->mpBuffer->Push(nFlags);
83 pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());
84 pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());
85 pFrameData->mpBuffer->SetFont(pWindow->GetFont());
86 pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());
87 pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
88 pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());
89 pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
90 pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
91 pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
92 pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
93 pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
94 pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
95 pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());
96 pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());
97 pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());
99 mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
100 mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
101 pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
102 pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
105 PaintBufferGuard::~PaintBufferGuard()
107 if (!mpFrameData->mpBuffer)
108 return;
110 if (!m_aPaintRect.IsEmpty())
112 // copy the buffer content to the actual window
113 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
114 // painting directly instead of using Invalidate()
115 // [ie. everything you can see was painted directly to the
116 // window either above or in eg. an event handler]
117 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
119 // Make sure that the +1 value GetSize() adds to the size is in pixels.
120 Size aPaintRectSize;
121 if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
123 aPaintRectSize = m_aPaintRect.GetSize();
125 else
127 tools::Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
128 aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
131 m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer);
135 // Restore buffer state.
136 mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
137 mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
139 mpFrameData->mpBuffer->Pop();
140 mpFrameData->mpBuffer->SetSettings(maSettings);
141 if (mbBackground)
142 mpFrameData->mpBuffer->SetBackground(maBackground);
143 else
144 mpFrameData->mpBuffer->SetBackground();
147 void PaintBufferGuard::SetPaintRect(const tools::Rectangle& rRectangle)
149 m_aPaintRect = rRectangle;
152 vcl::RenderContext* PaintBufferGuard::GetRenderContext()
154 if (mpFrameData->mpBuffer)
155 return mpFrameData->mpBuffer;
156 else
157 return m_pWindow;
160 class PaintHelper
162 private:
163 VclPtr<vcl::Window> m_pWindow;
164 std::unique_ptr<vcl::Region> m_pChildRegion;
165 tools::Rectangle m_aSelectionRect;
166 tools::Rectangle m_aPaintRect;
167 vcl::Region m_aPaintRegion;
168 ImplPaintFlags const m_nPaintFlags;
169 bool m_bPop : 1;
170 bool m_bRestoreCursor : 1;
171 bool m_bStartedBufferedPaint : 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
172 public:
173 PaintHelper(vcl::Window* pWindow, ImplPaintFlags nPaintFlags);
174 void SetPop()
176 m_bPop = true;
178 void SetPaintRect(const tools::Rectangle& rRect)
180 m_aPaintRect = rRect;
182 void SetSelectionRect(const tools::Rectangle& rRect)
184 m_aSelectionRect = rRect;
186 void SetRestoreCursor(bool bRestoreCursor)
188 m_bRestoreCursor = bRestoreCursor;
190 bool GetRestoreCursor() const
192 return m_bRestoreCursor;
194 ImplPaintFlags GetPaintFlags() const
196 return m_nPaintFlags;
198 vcl::Region& GetPaintRegion()
200 return m_aPaintRegion;
202 void DoPaint(const vcl::Region* pRegion);
204 /// Start buffered paint: set it up to have the same settings as m_pWindow.
205 void StartBufferedPaint();
207 /// Paint the content of the buffer to the current m_pWindow.
208 void PaintBuffer();
210 ~PaintHelper();
213 PaintHelper::PaintHelper(vcl::Window *pWindow, ImplPaintFlags nPaintFlags)
214 : m_pWindow(pWindow)
215 , m_nPaintFlags(nPaintFlags)
216 , m_bPop(false)
217 , m_bRestoreCursor(false)
218 , m_bStartedBufferedPaint(false)
222 void PaintHelper::StartBufferedPaint()
224 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
225 assert(!pFrameData->mbInBufferedPaint);
227 pFrameData->mbInBufferedPaint = true;
228 pFrameData->maBufferedRect = tools::Rectangle();
229 m_bStartedBufferedPaint = true;
232 void PaintHelper::PaintBuffer()
234 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
235 assert(pFrameData->mbInBufferedPaint);
236 assert(m_bStartedBufferedPaint);
238 PaintBufferGuard aGuard(pFrameData, m_pWindow);
239 aGuard.SetPaintRect(pFrameData->maBufferedRect);
242 void PaintHelper::DoPaint(const vcl::Region* pRegion)
244 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
246 vcl::Region* pWinChildClipRegion = m_pWindow->ImplGetWinChildClipRegion();
247 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
248 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll || pFrameData->mbInBufferedPaint)
250 pWindowImpl->maInvalidateRegion = *pWinChildClipRegion;
252 else
254 if (pRegion)
255 pWindowImpl->maInvalidateRegion.Union( *pRegion );
257 if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible)
258 /* #98602# need to repaint all children within the
259 * tracking rectangle, so the following invert
260 * operation takes places without traces of the previous
261 * one.
263 pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
265 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren)
266 m_pChildRegion.reset( new vcl::Region(pWindowImpl->maInvalidateRegion) );
267 pWindowImpl->maInvalidateRegion.Intersect(*pWinChildClipRegion);
269 pWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
270 if (!pWindowImpl->maInvalidateRegion.IsEmpty())
272 #if HAVE_FEATURE_OPENGL
273 VCL_GL_INFO("PaintHelper::DoPaint on " <<
274 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
275 #endif
276 // double-buffering: setup the buffer if it does not exist
277 if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
278 StartBufferedPaint();
280 // double-buffering: if this window does not support double-buffering,
281 // but we are in the middle of double-buffered paint, we might be
282 // losing information
283 if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
284 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
286 if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
288 // double-buffering
289 PaintBufferGuard g(pFrameData, m_pWindow);
290 m_pWindow->ApplySettings(*pFrameData->mpBuffer);
292 m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer);
293 m_pWindow->Paint(*pFrameData->mpBuffer, m_aPaintRect);
294 pFrameData->maBufferedRect.Union(m_aPaintRect);
296 else
298 // direct painting
299 Wallpaper aBackground = m_pWindow->GetBackground();
300 m_pWindow->ApplySettings(*m_pWindow);
301 // Restore lost bitmap background.
302 if (aBackground.IsBitmap())
303 m_pWindow->SetBackground(aBackground);
304 m_pWindow->PushPaintHelper(this, *m_pWindow);
305 m_pWindow->Paint(*m_pWindow, m_aPaintRect);
307 #if HAVE_FEATURE_OPENGL
308 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
309 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
310 #endif
314 namespace vcl
317 void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window const & rWindow,
318 const tools::Rectangle& rRect, sal_uInt16 nHighlight,
319 bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
320 Color* pSelectionTextColor, long nCornerRadius, Color const * pPaintColor)
322 if (rRect.IsEmpty())
323 return;
325 bool bRoundEdges = nCornerRadius > 0;
327 const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
329 // colors used for item highlighting
330 Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
331 Color aSelectionFillColor(aSelectionBorderColor);
333 bool bDark = rStyles.GetFaceColor().IsDark();
334 bool bBright = ( rStyles.GetFaceColor() == COL_WHITE );
336 int c1 = aSelectionBorderColor.GetLuminance();
337 int c2 = rWindow.GetBackgroundColor().GetLuminance();
339 if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
341 // contrast too low
342 sal_uInt16 h, s, b;
343 aSelectionFillColor.RGBtoHSB( h, s, b );
344 if( b > 50 ) b -= 40;
345 else b += 40;
346 aSelectionFillColor = Color::HSBtoRGB( h, s, b );
347 aSelectionBorderColor = aSelectionFillColor;
350 if (bRoundEdges)
352 if (aSelectionBorderColor.IsDark())
353 aSelectionBorderColor.IncreaseLuminance(128);
354 else
355 aSelectionBorderColor.DecreaseLuminance(128);
358 tools::Rectangle aRect(rRect);
359 if (bDrawExtBorderOnly)
361 aRect.AdjustLeft( -1 );
362 aRect.AdjustTop( -1 );
363 aRect.AdjustRight(1 );
364 aRect.AdjustBottom(1 );
366 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
368 if (bDrawBorder)
369 rRenderContext.SetLineColor(bDark ? COL_WHITE : (bBright ? COL_BLACK : aSelectionBorderColor));
370 else
371 rRenderContext.SetLineColor();
373 sal_uInt16 nPercent = 0;
374 if (!nHighlight)
376 if (bDark)
377 aSelectionFillColor = COL_BLACK;
378 else
379 nPercent = 80; // just checked (light)
381 else
383 if (bChecked && nHighlight == 2)
385 if (bDark)
386 aSelectionFillColor = COL_LIGHTGRAY;
387 else if (bBright)
389 aSelectionFillColor = COL_BLACK;
390 rRenderContext.SetLineColor(COL_BLACK);
391 nPercent = 0;
393 else
394 nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
396 else if (bChecked || nHighlight == 1)
398 if (bDark)
399 aSelectionFillColor = COL_GRAY;
400 else if (bBright)
402 aSelectionFillColor = COL_BLACK;
403 rRenderContext.SetLineColor(COL_BLACK);
404 nPercent = 0;
406 else
407 nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
409 else
411 if (bDark)
412 aSelectionFillColor = COL_LIGHTGRAY;
413 else if (bBright)
415 aSelectionFillColor = COL_BLACK;
416 rRenderContext.SetLineColor(COL_BLACK);
417 if (nHighlight == 3)
418 nPercent = 80;
419 else
420 nPercent = 0;
422 else
423 nPercent = 70; // selected ( dark )
427 if (bDark && bDrawExtBorderOnly)
429 rRenderContext.SetFillColor();
430 if (pSelectionTextColor)
431 *pSelectionTextColor = rStyles.GetHighlightTextColor();
433 else
435 rRenderContext.SetFillColor(aSelectionFillColor);
436 if (pSelectionTextColor)
438 Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
439 Color aHLTextColor = rStyles.GetHighlightTextColor();
440 int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
441 int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
442 *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
446 if (bDark)
448 rRenderContext.DrawRect(aRect);
450 else
452 if (bRoundEdges)
454 tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
455 tools::PolyPolygon aPolyPoly(aPoly);
456 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
458 else
460 tools::Polygon aPoly(aRect);
461 tools::PolyPolygon aPolyPoly(aPoly);
462 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
466 rRenderContext.Pop(); // LINECOLOR | FILLCOLOR
469 void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
471 pHelper->SetPop();
473 if ( mpWindowImpl->mpCursor )
474 pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
476 mbInitClipRegion = true;
477 mpWindowImpl->mbInPaint = true;
479 // restore Paint-Region
480 vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
481 rPaintRegion = mpWindowImpl->maInvalidateRegion;
482 tools::Rectangle aPaintRect = rPaintRegion.GetBoundRect();
484 // RTL: re-mirror paint rect and region at this window
485 if (ImplIsAntiparallel())
487 rRenderContext.ReMirror(aPaintRect);
488 rRenderContext.ReMirror(rPaintRegion);
490 aPaintRect = ImplDevicePixelToLogic(aPaintRect);
491 mpWindowImpl->mpPaintRegion = &rPaintRegion;
492 mpWindowImpl->maInvalidateRegion.SetEmpty();
494 if ((pHelper->GetPaintFlags() & ImplPaintFlags::Erase) && rRenderContext.IsBackground())
496 if (rRenderContext.IsClipRegion())
498 vcl::Region aOldRegion = rRenderContext.GetClipRegion();
499 rRenderContext.SetClipRegion();
500 Erase(rRenderContext);
501 rRenderContext.SetClipRegion(aOldRegion);
503 else
504 Erase(rRenderContext);
507 // #98943# trigger drawing of toolbox selection after all children are painted
508 if (mpWindowImpl->mbDrawSelectionBackground)
509 pHelper->SetSelectionRect(aPaintRect);
510 pHelper->SetPaintRect(aPaintRect);
513 void Window::PopPaintHelper(PaintHelper const *pHelper)
515 if (mpWindowImpl->mpWinData)
517 if (mpWindowImpl->mbFocusVisible)
518 ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
520 mpWindowImpl->mbInPaint = false;
521 mbInitClipRegion = true;
522 mpWindowImpl->mpPaintRegion = nullptr;
523 if (mpWindowImpl->mpCursor)
524 mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
527 } /* namespace vcl */
529 PaintHelper::~PaintHelper()
531 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
532 if (m_bPop)
534 m_pWindow->PopPaintHelper(this);
537 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
538 if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
540 // Paint from the bottom child window and frontward.
541 vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
542 while (pTempWindow)
544 if (pTempWindow->mpWindowImpl->mbVisible)
545 pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
546 pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
550 if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
551 /* #98602# need to invert the tracking rect AFTER
552 * the children have painted
554 m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
556 // double-buffering: paint in case we created the buffer, the children are
557 // already painted inside
558 if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
560 PaintBuffer();
561 pFrameData->mbInBufferedPaint = false;
562 pFrameData->maBufferedRect = tools::Rectangle();
565 // #98943# draw toolbox selection
566 if( !m_aSelectionRect.IsEmpty() )
567 m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
570 namespace vcl {
572 void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
574 // call PrePaint. PrePaint may add to the invalidate region as well as
575 // other parameters used below.
576 PrePaint(*this);
578 mpWindowImpl->mbPaintFrame = false;
580 if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
581 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll);
582 if (nPaintFlags & ImplPaintFlags::PaintChildren)
583 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren;
584 if (nPaintFlags & ImplPaintFlags::Erase)
585 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
586 if (nPaintFlags & ImplPaintFlags::CheckRtl)
587 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
588 if (!mpWindowImpl->mpFirstChild)
589 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
591 if (mpWindowImpl->mbPaintDisabled)
593 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
594 Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
595 else if ( pRegion )
596 Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
598 // call PostPaint before returning
599 PostPaint(*this);
601 return;
604 nPaintFlags = mpWindowImpl->mnPaintFlags & ~ImplPaintFlags::Paint;
606 PaintHelper aHelper(this, nPaintFlags);
608 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
609 aHelper.DoPaint(pRegion);
610 else
611 mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
613 // call PostPaint
614 PostPaint(*this);
617 void Window::ImplCallOverlapPaint()
619 // emit overlapping windows first
620 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
621 while ( pTempWindow )
623 if ( pTempWindow->mpWindowImpl->mbReallyVisible )
624 pTempWindow->ImplCallOverlapPaint();
625 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
628 // only then ourself
629 if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
631 // RTL: notify ImplCallPaint to check for re-mirroring
632 // because we were called from the Sal layer
633 ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
637 IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void)
639 comphelper::ProfileZone aZone("VCL idle re-paint");
641 // save paint events until layout is done
642 if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
644 mpWindowImpl->mpFrameData->maPaintIdle.Start();
645 return;
648 // save paint events until resizing or initial sizing done
649 if (mpWindowImpl->mbFrame &&
650 mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
652 mpWindowImpl->mpFrameData->maPaintIdle.Start();
654 else if ( mpWindowImpl->mbReallyVisible )
656 ImplCallOverlapPaint();
657 if (comphelper::LibreOfficeKit::isActive() &&
658 mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
659 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
663 IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void)
665 comphelper::ProfileZone aZone("VCL idle resize");
667 if( mpWindowImpl->mbReallyVisible )
669 ImplCallResize();
670 if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
672 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
673 mpWindowImpl->mpFrameData->maPaintIdle.Invoke( nullptr );
678 void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
680 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
681 if ( !ImplIsOverlapWindow() )
683 vcl::Window* pTempWindow = this;
684 ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE;
687 pTempWindow = pTempWindow->ImplGetParent();
688 if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren )
689 break;
690 pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint;
691 if( ! pTempWindow->IsPaintTransparent() )
692 nTranspPaint = ImplPaintFlags::NONE;
694 while ( !pTempWindow->ImplIsOverlapWindow() );
697 // set Paint-Flags
698 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint;
699 if ( nFlags & InvalidateFlags::Children )
700 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren;
701 if ( !(nFlags & InvalidateFlags::NoErase) )
702 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
704 if ( !pRegion )
705 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll;
706 else if ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
708 // if not everything has to be redrawn, add the region to it
709 mpWindowImpl->maInvalidateRegion.Union( *pRegion );
712 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
713 if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
714 && ImplGetParent() )
716 vcl::Window *pParent = ImplGetParent();
717 while( pParent && pParent->IsPaintTransparent() )
718 pParent = pParent->ImplGetParent();
719 if( pParent )
721 vcl::Region *pChildRegion;
722 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
723 // invalidate the whole child window region in the parent
724 pChildRegion = ImplGetWinChildClipRegion();
725 else
726 // invalidate the same region in the parent that has to be repainted in the child
727 pChildRegion = &mpWindowImpl->maInvalidateRegion;
729 nFlags |= InvalidateFlags::Children; // paint should also be done on all children
730 nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
731 pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
735 if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
736 mpWindowImpl->mpFrameData->maPaintIdle.Start();
739 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
741 vcl::Region aRegion = rRegion;
743 ImplClipBoundaries( aRegion, true, true );
744 if ( !aRegion.IsEmpty() )
745 ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
747 // now we invalidate the overlapping windows
748 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
749 while ( pTempWindow )
751 if ( pTempWindow->IsVisible() )
752 pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
754 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
758 void Window::ImplInvalidateParentFrameRegion( vcl::Region& rRegion )
760 if ( mpWindowImpl->mbOverlapWin )
761 mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
762 else
764 if( ImplGetParent() )
765 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
769 void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
771 // check what has to be redrawn
772 bool bInvalidateAll = !pRegion;
774 // take Transparent-Invalidate into account
775 vcl::Window* pOpaqueWindow = this;
776 if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
778 vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
779 while ( pTempWindow )
781 if ( !pTempWindow->IsPaintTransparent() )
783 pOpaqueWindow = pTempWindow;
784 nFlags |= InvalidateFlags::Children;
785 bInvalidateAll = false;
786 break;
789 if ( pTempWindow->ImplIsOverlapWindow() )
790 break;
792 pTempWindow = pTempWindow->ImplGetParent();
796 // assemble region
797 InvalidateFlags nOrgFlags = nFlags;
798 if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
800 if ( GetStyle() & WB_CLIPCHILDREN )
801 nFlags |= InvalidateFlags::NoChildren;
802 else
803 nFlags |= InvalidateFlags::Children;
805 if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
806 bInvalidateAll = false;
807 if ( bInvalidateAll )
808 ImplInvalidateFrameRegion( nullptr, nFlags );
809 else
811 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
812 vcl::Region aRegion( aRect );
813 if ( pRegion )
815 // RTL: remirror region before intersecting it
816 if ( ImplIsAntiparallel() )
818 const OutputDevice *pOutDev = GetOutDev();
820 vcl::Region aRgn( *pRegion );
821 pOutDev->ReMirror( aRgn );
822 aRegion.Intersect( aRgn );
824 else
825 aRegion.Intersect( *pRegion );
827 ImplClipBoundaries( aRegion, true, true );
828 if ( nFlags & InvalidateFlags::NoChildren )
830 nFlags &= ~InvalidateFlags::Children;
831 if ( !(nFlags & InvalidateFlags::NoClipChildren) )
833 if ( nOrgFlags & InvalidateFlags::NoChildren )
834 ImplClipAllChildren( aRegion );
835 else
837 if ( ImplClipChildren( aRegion ) )
838 nFlags |= InvalidateFlags::Children;
842 if ( !aRegion.IsEmpty() )
843 ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
846 if ( nFlags & InvalidateFlags::Update )
847 pOpaqueWindow->Update(); // start painting at the opaque parent
850 void Window::ImplMoveInvalidateRegion( const tools::Rectangle& rRect,
851 long nHorzScroll, long nVertScroll,
852 bool bChildren )
854 if ( (mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintAll)) == ImplPaintFlags::Paint )
856 vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
857 aTempRegion.Intersect( rRect );
858 aTempRegion.Move( nHorzScroll, nVertScroll );
859 mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
862 if ( bChildren && (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren) )
864 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
865 while ( pWindow )
867 pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
868 pWindow = pWindow->mpWindowImpl->mpNext;
873 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
874 long nHorzScroll, long nVertScroll,
875 bool bChildren )
877 // also shift Paint-Region when paints need processing
878 ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
879 // Paint-Region should be shifted, as drawn by the parents
880 if ( !ImplIsOverlapWindow() )
882 vcl::Region aPaintAllRegion;
883 vcl::Window* pPaintAllWindow = this;
886 pPaintAllWindow = pPaintAllWindow->ImplGetParent();
887 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
889 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
891 aPaintAllRegion.SetEmpty();
892 break;
894 else
895 aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
898 while ( !pPaintAllWindow->ImplIsOverlapWindow() );
899 if ( !aPaintAllRegion.IsEmpty() )
901 aPaintAllRegion.Move( nHorzScroll, nVertScroll );
902 InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
903 if ( bChildren )
904 nPaintFlags |= InvalidateFlags::Children;
905 ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
910 void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
912 if ( !pRegion )
913 mpWindowImpl->maInvalidateRegion.SetEmpty();
914 else
916 // when all child windows have to be drawn we need to invalidate them before doing so
917 if ( (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren) && mpWindowImpl->mpFirstChild )
919 vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
920 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
922 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
923 aChildRegion = aRect;
925 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
926 while ( pChild )
928 pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
929 pChild = pChild->mpWindowImpl->mpNext;
932 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
934 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
935 mpWindowImpl->maInvalidateRegion = aRect;
937 mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
939 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAll;
941 if ( nFlags & ValidateFlags::Children )
943 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
944 while ( pChild )
946 pChild->ImplValidateFrameRegion( pRegion, nFlags );
947 pChild = pChild->mpWindowImpl->mpNext;
952 void Window::ImplValidate()
954 // assemble region
955 bool bValidateAll = true;
956 ValidateFlags nFlags = ValidateFlags::NONE;
957 if ( GetStyle() & WB_CLIPCHILDREN )
958 nFlags |= ValidateFlags::NoChildren;
959 else
960 nFlags |= ValidateFlags::Children;
961 if ( (nFlags & ValidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
962 bValidateAll = false;
963 if ( bValidateAll )
964 ImplValidateFrameRegion( nullptr, nFlags );
965 else
967 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
968 vcl::Region aRegion( aRect );
969 ImplClipBoundaries( aRegion, true, true );
970 if ( nFlags & ValidateFlags::NoChildren )
972 nFlags &= ~ValidateFlags::Children;
973 if ( ImplClipChildren( aRegion ) )
974 nFlags |= ValidateFlags::Children;
976 if ( !aRegion.IsEmpty() )
977 ImplValidateFrameRegion( &aRegion, nFlags );
981 void Window::ImplUpdateAll()
983 if ( !mpWindowImpl->mbReallyVisible )
984 return;
986 bool bFlush = false;
987 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
989 Point aPoint( 0, 0 );
990 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
991 ImplInvalidateOverlapFrameRegion( aRegion );
992 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
993 bFlush = true;
996 // an update changes the OverlapWindow, such that for later paints
997 // not too much has to be drawn, if ALLCHILDREN etc. is set
998 vcl::Window* pWindow = ImplGetFirstOverlapWindow();
999 pWindow->ImplCallOverlapPaint();
1001 if ( bFlush )
1002 Flush();
1005 void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1009 void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1013 void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect)
1015 CallEventListeners(VclEventId::WindowPaint, const_cast<tools::Rectangle *>(&rRect));
1018 void Window::SetPaintTransparent( bool bTransparent )
1020 // transparency is not useful for frames as the background would have to be provided by a different frame
1021 if( bTransparent && mpWindowImpl->mbFrame )
1022 return;
1024 if ( mpWindowImpl->mpBorderWindow )
1025 mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1027 mpWindowImpl->mbPaintTransparent = bTransparent;
1030 void Window::SetWindowRegionPixel()
1033 if ( mpWindowImpl->mpBorderWindow )
1034 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1035 else if( mpWindowImpl->mbFrame )
1037 mpWindowImpl->maWinRegion = vcl::Region(true);
1038 mpWindowImpl->mbWinRegion = false;
1039 mpWindowImpl->mpFrame->ResetClipRegion();
1041 else
1043 if ( mpWindowImpl->mbWinRegion )
1045 mpWindowImpl->maWinRegion = vcl::Region(true);
1046 mpWindowImpl->mbWinRegion = false;
1047 ImplSetClipFlag();
1049 if ( IsReallyVisible() )
1051 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1052 vcl::Region aRegion( aRect );
1053 ImplInvalidateParentFrameRegion( aRegion );
1059 void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1062 if ( mpWindowImpl->mpBorderWindow )
1063 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1064 else if( mpWindowImpl->mbFrame )
1066 if( !rRegion.IsNull() )
1068 mpWindowImpl->maWinRegion = rRegion;
1069 mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1071 if( mpWindowImpl->mbWinRegion )
1073 // set/update ClipRegion
1074 RectangleVector aRectangles;
1075 mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1076 mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1078 for (auto const& rectangle : aRectangles)
1080 mpWindowImpl->mpFrame->UnionClipRegion(
1081 rectangle.Left(),
1082 rectangle.Top(),
1083 rectangle.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1084 rectangle.GetHeight()); // same for height
1087 mpWindowImpl->mpFrame->EndSetClipRegion();
1089 //long nX;
1090 //long nY;
1091 //long nWidth;
1092 //long nHeight;
1093 //sal_uLong nRectCount;
1094 //ImplRegionInfo aInfo;
1095 //sal_Bool bRegionRect;
1097 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1098 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1099 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1100 //while ( bRegionRect )
1102 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1103 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1105 //mpWindowImpl->mpFrame->EndSetClipRegion();
1107 else
1108 SetWindowRegionPixel();
1110 else
1111 SetWindowRegionPixel();
1113 else
1115 if ( rRegion.IsNull() )
1117 if ( mpWindowImpl->mbWinRegion )
1119 mpWindowImpl->maWinRegion = vcl::Region(true);
1120 mpWindowImpl->mbWinRegion = false;
1121 ImplSetClipFlag();
1124 else
1126 mpWindowImpl->maWinRegion = rRegion;
1127 mpWindowImpl->mbWinRegion = true;
1128 ImplSetClipFlag();
1131 if ( IsReallyVisible() )
1133 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1134 vcl::Region aRegion( aRect );
1135 ImplInvalidateParentFrameRegion( aRegion );
1140 vcl::Region Window::GetPaintRegion() const
1143 if ( mpWindowImpl->mpPaintRegion )
1145 vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1146 aRegion.Move( -mnOutOffX, -mnOutOffY );
1147 return PixelToLogic( aRegion );
1149 else
1151 vcl::Region aPaintRegion(true);
1152 return aPaintRegion;
1156 void Window::Invalidate( InvalidateFlags nFlags )
1158 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1159 return;
1161 ImplInvalidate( nullptr, nFlags );
1162 LogicInvalidate(nullptr);
1165 void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1167 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1168 return;
1170 OutputDevice *pOutDev = GetOutDev();
1171 tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1172 if ( !aRect.IsEmpty() )
1174 vcl::Region aRegion( aRect );
1175 ImplInvalidate( &aRegion, nFlags );
1176 tools::Rectangle aLogicRectangle(rRect);
1177 LogicInvalidate(&aLogicRectangle);
1181 void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1183 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1184 return;
1186 if ( rRegion.IsNull() )
1188 ImplInvalidate( nullptr, nFlags );
1189 LogicInvalidate(nullptr);
1191 else
1193 vcl::Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1194 if ( !aRegion.IsEmpty() )
1196 ImplInvalidate( &aRegion, nFlags );
1197 tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1198 LogicInvalidate(&aLogicRectangle);
1203 void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1205 if(pRectangle)
1207 tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1208 PixelInvalidate(&aRect);
1210 else
1211 PixelInvalidate(nullptr);
1214 void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1216 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1217 return;
1219 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1221 // In case we are routing the window, notify the client
1222 std::vector<vcl::LOKPayloadItem> aPayload;
1223 if (pRectangle)
1224 aPayload.push_back(std::make_pair(OString("rectangle"), pRectangle->toString()));
1225 else
1227 const tools::Rectangle aRect(Point(0, 0), GetSizePixel());
1228 aPayload.push_back(std::make_pair(OString("rectangle"), aRect.toString()));
1231 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
1233 // Added for dialog items. Pass invalidation to the parent window.
1234 else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1236 const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1237 pParent->PixelInvalidate(&aRect);
1241 void Window::Validate()
1243 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1244 return;
1246 ImplValidate();
1249 bool Window::HasPaintEvent() const
1252 if ( !mpWindowImpl->mbReallyVisible )
1253 return false;
1255 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1256 return true;
1258 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1259 return true;
1261 if ( !ImplIsOverlapWindow() )
1263 const vcl::Window* pTempWindow = this;
1266 pTempWindow = pTempWindow->ImplGetParent();
1267 if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1268 return true;
1270 while ( !pTempWindow->ImplIsOverlapWindow() );
1273 return false;
1276 void Window::Update()
1278 if ( mpWindowImpl->mpBorderWindow )
1280 mpWindowImpl->mpBorderWindow->Update();
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, Size( mnOutWidth, mnOutHeight ) ) );
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()->mpWindowImpl->mpFirstOverlap;
1330 while ( pUpdateOverlapWindow )
1332 pUpdateOverlapWindow->Update();
1333 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1336 pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1338 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1339 pUpdateWindow->LogicInvalidate(nullptr);
1341 if (xWindow->IsDisposed())
1342 return;
1344 bFlush = true;
1347 if ( bFlush )
1348 Flush();
1351 void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1353 // Special drawing when called through LOKit
1354 // TODO: Move to its own method
1355 if (comphelper::LibreOfficeKit::isActive())
1357 VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1359 Size aSize(GetOutputSizePixel());
1360 pDevice->SetOutputSizePixel(aSize);
1362 vcl::Font aCopyFont = GetFont();
1363 pDevice->SetFont(aCopyFont);
1365 pDevice->SetTextColor(GetTextColor());
1366 if (IsLineColor())
1367 pDevice->SetLineColor(GetLineColor());
1368 else
1369 pDevice->SetLineColor();
1371 if (IsFillColor())
1372 pDevice->SetFillColor(GetFillColor());
1373 else
1374 pDevice->SetFillColor();
1376 if (IsTextLineColor())
1377 pDevice->SetTextLineColor(GetTextLineColor());
1378 else
1379 pDevice->SetTextLineColor();
1381 if (IsOverlineColor())
1382 pDevice->SetOverlineColor(GetOverlineColor());
1383 else
1384 pDevice->SetOverlineColor();
1386 if (IsTextFillColor())
1387 pDevice->SetTextFillColor(GetTextFillColor());
1388 else
1389 pDevice->SetTextFillColor();
1391 pDevice->SetTextAlign(GetTextAlign());
1392 pDevice->SetRasterOp(GetRasterOp());
1394 tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1396 vcl::Region aClipRegion(GetClipRegion());
1397 pDevice->SetClipRegion();
1398 aClipRegion.Intersect(aPaintRect);
1399 pDevice->SetClipRegion(aClipRegion);
1401 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1402 Erase(*pDevice);
1404 pDevice->SetMapMode(GetMapMode());
1406 Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1408 i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1410 // get rid of virtual device now so they don't pile up during recursive calls
1411 pDevice.disposeAndClear();
1414 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1416 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1418 long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1419 long nDeltaY = pChild->mnOutOffY - mnOutOffY;
1421 Point aPos( i_rPos );
1422 aPos += Point(nDeltaX, nDeltaY);
1424 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1427 return;
1431 bool bRVisible = mpWindowImpl->mbReallyVisible;
1432 mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1433 bool bDevOutput = mbDevOutput;
1434 mbDevOutput = true;
1436 const OutputDevice *pOutDev = GetOutDev();
1437 long nOldDPIX = pOutDev->GetDPIX();
1438 long nOldDPIY = pOutDev->GetDPIY();
1439 mnDPIX = i_pTargetOutDev->GetDPIX();
1440 mnDPIY = i_pTargetOutDev->GetDPIY();
1441 bool bOutput = IsOutputEnabled();
1442 EnableOutput();
1444 double fScaleX = 1;
1445 double fScaleY = 1;
1446 bool bNeedsScaling = false;
1447 if(comphelper::LibreOfficeKit::isActive())
1449 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel &&
1450 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1451 // For these preview we don't need to scale even though the unit is not pixel.
1452 GetMapMode().GetMapUnit() != MapUnit::Map100thMM)
1454 bNeedsScaling = true;
1455 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1456 Size aLogicSize = PixelToLogic(Size(1000.0, 1000.0));
1457 fScaleX = aLogicSize.Width() / 1000.0;
1458 fScaleY = aLogicSize.Height() / 1000.0;
1461 else
1462 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1463 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1464 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1465 return;
1468 // preserve graphicsstate
1469 Push();
1470 vcl::Region aClipRegion( GetClipRegion() );
1471 SetClipRegion();
1473 GDIMetaFile* pOldMtf = GetConnectMetaFile();
1474 GDIMetaFile aMtf;
1475 SetConnectMetaFile( &aMtf );
1477 // put a push action to metafile
1478 Push();
1479 // copy graphics state to metafile
1480 vcl::Font aCopyFont = GetFont();
1481 if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY )
1483 aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * mnDPIY / nOldDPIY );
1484 aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * mnDPIX / nOldDPIX );
1486 SetFont( aCopyFont );
1487 SetTextColor( GetTextColor() );
1488 if( IsLineColor() )
1489 SetLineColor( GetLineColor() );
1490 else
1491 SetLineColor();
1492 if( IsFillColor() )
1493 SetFillColor( GetFillColor() );
1494 else
1495 SetFillColor();
1496 if( IsTextLineColor() )
1497 SetTextLineColor( GetTextLineColor() );
1498 else
1499 SetTextLineColor();
1500 if( IsOverlineColor() )
1501 SetOverlineColor( GetOverlineColor() );
1502 else
1503 SetOverlineColor();
1504 if( IsTextFillColor() )
1505 SetTextFillColor( GetTextFillColor() );
1506 else
1507 SetTextFillColor();
1508 SetTextAlign( GetTextAlign() );
1509 SetRasterOp( GetRasterOp() );
1510 if( IsRefPoint() )
1511 SetRefPoint( GetRefPoint() );
1512 else
1513 SetRefPoint();
1514 SetLayoutMode( GetLayoutMode() );
1515 SetDigitLanguage( GetDigitLanguage() );
1517 tools::Rectangle aPaintRect;
1518 if(bNeedsScaling)
1520 aPaintRect = tools::Rectangle( Point( 0, 0 ),
1521 Size(GetOutputSizePixel().Width() * fScaleX, GetOutputSizePixel().Height() * fScaleY) );
1523 else
1525 aPaintRect = tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1527 aClipRegion.Intersect( aPaintRect );
1528 SetClipRegion( aClipRegion );
1530 // do the actual paint
1532 // background
1533 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1535 Erase(*this);
1536 if(bNeedsScaling)
1537 aMtf.Scale(fScaleX, fScaleY);
1539 // foreground
1540 Paint(*this, aPaintRect);
1541 // put a pop action to metafile
1542 Pop();
1544 SetConnectMetaFile( pOldMtf );
1545 EnableOutput( bOutput );
1546 mpWindowImpl->mbReallyVisible = bRVisible;
1548 // paint metafile to VDev
1549 VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1550 DeviceFormat::DEFAULT,
1551 DeviceFormat::DEFAULT);
1553 if(bNeedsScaling)
1554 pMaskedDevice->SetMapMode( GetMapMode() );
1555 pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() );
1556 pMaskedDevice->EnableRTL( IsRTLEnabled() );
1557 aMtf.WindStart();
1558 aMtf.Play( pMaskedDevice );
1559 BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), aPaintRect.GetSize() ) );
1560 i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
1561 // get rid of virtual device now so they don't pile up during recursive calls
1562 pMaskedDevice.disposeAndClear();
1564 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1566 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1568 long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1570 if( pOutDev->HasMirroredGraphics() )
1571 nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth;
1572 long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1573 Point aPos( i_rPos );
1574 Point aDelta( nDeltaX, nDeltaY );
1575 aPos += aDelta;
1576 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1580 // restore graphics state
1581 Pop();
1583 EnableOutput( bOutput );
1584 mpWindowImpl->mbReallyVisible = bRVisible;
1585 mbDevOutput = bDevOutput;
1586 mnDPIX = nOldDPIX;
1587 mnDPIY = nOldDPIY;
1590 void Window::PaintToDevice( OutputDevice* pDev, const Point& rPos, const Size& /*rSize*/ )
1592 SAL_WARN_IF( pDev->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1593 SAL_WARN_IF( pDev->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1595 vcl::Window* pRealParent = nullptr;
1596 if( ! mpWindowImpl->mbVisible )
1598 vcl::Window* pTempParent = ImplGetDefaultWindow();
1599 pTempParent->EnableChildTransparentMode();
1600 pRealParent = GetParent();
1601 SetParent( pTempParent );
1602 // trigger correct visibility flags for children
1603 Show();
1604 Hide();
1607 bool bVisible = mpWindowImpl->mbVisible;
1608 mpWindowImpl->mbVisible = true;
1610 if( mpWindowImpl->mpBorderWindow )
1611 mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1612 else
1613 ImplPaintToDevice( pDev, rPos );
1615 mpWindowImpl->mbVisible = bVisible;
1617 if( pRealParent )
1618 SetParent( pRealParent );
1621 void Window::Erase(vcl::RenderContext& rRenderContext)
1623 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1624 return;
1626 bool bNativeOK = false;
1628 ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1629 if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1631 tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1632 ControlState nState = ControlState::NONE;
1634 if (IsEnabled())
1635 nState |= ControlState::ENABLED;
1637 bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1638 nState, ImplControlValue(), OUString());
1641 if (mbBackground && !bNativeOK)
1643 RasterOp eRasterOp = GetRasterOp();
1644 if (eRasterOp != RasterOp::OverPaint)
1645 SetRasterOp(RasterOp::OverPaint);
1646 rRenderContext.DrawWallpaper(0, 0, mnOutWidth, mnOutHeight, maBackground);
1647 if (eRasterOp != RasterOp::OverPaint)
1648 rRenderContext.SetRasterOp(eRasterOp);
1651 if (mpAlphaVDev)
1652 mpAlphaVDev->Erase();
1655 void Window::ImplScroll( const tools::Rectangle& rRect,
1656 long nHorzScroll, long nVertScroll, ScrollFlags nFlags )
1658 if ( !IsDeviceOutputNecessary() )
1659 return;
1661 nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll );
1662 nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll );
1664 if ( !nHorzScroll && !nVertScroll )
1665 return;
1667 if ( mpWindowImpl->mpCursor )
1668 mpWindowImpl->mpCursor->ImplSuspend();
1670 ScrollFlags nOrgFlags = nFlags;
1671 if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1673 if ( GetStyle() & WB_CLIPCHILDREN )
1674 nFlags |= ScrollFlags::NoChildren;
1675 else
1676 nFlags |= ScrollFlags::Children;
1679 vcl::Region aInvalidateRegion;
1680 bool bScrollChildren(nFlags & ScrollFlags::Children);
1682 if ( !mpWindowImpl->mpFirstChild )
1683 bScrollChildren = false;
1685 OutputDevice *pOutDev = GetOutDev();
1687 // RTL: check if this window requires special action
1688 bool bReMirror = ImplIsAntiparallel();
1690 tools::Rectangle aRectMirror( rRect );
1691 if( bReMirror )
1693 // make sure the invalidate region of this window is
1694 // computed in the same coordinate space as the one from the overlap windows
1695 pOutDev->ReMirror( aRectMirror );
1698 // adapt paint areas
1699 ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1701 ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1703 // if the scrolling on the device is performed in the opposite direction
1704 // then move the overlaps in that direction to compute the invalidate region
1705 // on the correct side, i.e., revert nHorzScroll
1706 if (!aInvalidateRegion.IsEmpty())
1708 aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1711 tools::Rectangle aDestRect(aRectMirror);
1712 aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1713 vcl::Region aWinInvalidateRegion(aRectMirror);
1714 if (!SupportsDoubleBuffering())
1716 // There will be no CopyArea() call below, so invalidate the
1717 // whole visible area, not only the smaller one that was just
1718 // scrolled in.
1719 aWinInvalidateRegion.Exclude(aDestRect);
1722 aInvalidateRegion.Union(aWinInvalidateRegion);
1724 Point aPoint( mnOutOffX, mnOutOffY );
1725 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1726 if ( nFlags & ScrollFlags::Clip )
1727 aRegion.Intersect( rRect );
1728 if ( mpWindowImpl->mbWinRegion )
1729 aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1731 aRegion.Exclude( aInvalidateRegion );
1733 ImplClipBoundaries( aRegion, false, true );
1734 if ( !bScrollChildren )
1736 if ( nOrgFlags & ScrollFlags::NoChildren )
1737 ImplClipAllChildren( aRegion );
1738 else
1739 ImplClipChildren( aRegion );
1741 if ( mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1742 aRegion.Intersect( maRegion );
1743 if ( !aRegion.IsEmpty() )
1745 if ( mpWindowImpl->mpWinData )
1747 if ( mpWindowImpl->mbFocusVisible )
1748 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1749 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1750 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1752 #ifndef IOS
1753 // This seems completely unnecessary with tiled rendering, and
1754 // causes the "AquaSalGraphics::copyArea() for non-layered
1755 // graphics" message. Presumably we should bypass this on all
1756 // platforms when dealing with a "window" that uses tiled
1757 // rendering at the moment. Unclear how to figure that out,
1758 // though. Also unclear whether we actually could just not
1759 // create a "frame window", whatever that exactly is, in the
1760 // tiled rendering case, or at least for platforms where tiles
1761 // rendering is all there is.
1763 SalGraphics* pGraphics = ImplGetFrameGraphics();
1764 // The invalidation area contains the area what would be copied here,
1765 // so avoid copying in case of double buffering.
1766 if (pGraphics && !SupportsDoubleBuffering())
1768 if( bReMirror )
1770 pOutDev->ReMirror( aRegion );
1773 pOutDev->SelectClipRegion( aRegion, pGraphics );
1774 pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1775 rRect.Left(), rRect.Top(),
1776 rRect.GetWidth(), rRect.GetHeight(),
1777 this );
1779 #endif
1780 if ( mpWindowImpl->mpWinData )
1782 if ( mpWindowImpl->mbFocusVisible )
1783 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1784 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1785 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1789 if ( !aInvalidateRegion.IsEmpty() )
1791 // RTL: the invalidate region for this windows is already computed in frame coordinates
1792 // so it has to be re-mirrored before calling the Paint-handler
1793 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
1795 if ( !bScrollChildren )
1797 if ( nOrgFlags & ScrollFlags::NoChildren )
1798 ImplClipAllChildren( aInvalidateRegion );
1799 else
1800 ImplClipChildren( aInvalidateRegion );
1802 ImplInvalidateFrameRegion( &aInvalidateRegion, InvalidateFlags::Children );
1805 if ( bScrollChildren )
1807 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1808 while ( pWindow )
1810 Point aPos = pWindow->GetPosPixel();
1811 aPos += Point( nHorzScroll, nVertScroll );
1812 pWindow->SetPosPixel( aPos );
1814 pWindow = pWindow->mpWindowImpl->mpNext;
1818 if ( nFlags & ScrollFlags::Update )
1819 Update();
1821 if ( mpWindowImpl->mpCursor )
1822 mpWindowImpl->mpCursor->ImplResume();
1825 } /* namespace vcl */
1828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */