nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / window / paint.cxx
blob034eef555d6a7eedf16baec4564f450d60cbf183
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 PushFlags nFlags = PushFlags::NONE;
69 nFlags |= PushFlags::CLIPREGION;
70 nFlags |= PushFlags::FILLCOLOR;
71 nFlags |= PushFlags::FONT;
72 nFlags |= PushFlags::LINECOLOR;
73 nFlags |= PushFlags::MAPMODE;
74 maSettings = pFrameData->mpBuffer->GetSettings();
75 nFlags |= PushFlags::REFPOINT;
76 nFlags |= PushFlags::TEXTCOLOR;
77 nFlags |= PushFlags::TEXTLINECOLOR;
78 nFlags |= PushFlags::OVERLINECOLOR;
79 nFlags |= PushFlags::TEXTFILLCOLOR;
80 nFlags |= PushFlags::TEXTALIGN;
81 nFlags |= PushFlags::RASTEROP;
82 nFlags |= PushFlags::TEXTLAYOUTMODE;
83 nFlags |= PushFlags::TEXTLANGUAGE;
84 pFrameData->mpBuffer->Push(nFlags);
85 pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());
86 pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());
87 pFrameData->mpBuffer->SetFont(pWindow->GetFont());
88 pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());
89 pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
90 pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());
91 pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
92 pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
93 pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
94 pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
95 pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
96 pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
97 pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());
98 pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());
99 pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());
101 mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
102 mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
103 pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
104 pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
105 pFrameData->mpBuffer->EnableRTL(pWindow->IsRTLEnabled());
108 PaintBufferGuard::~PaintBufferGuard()
110 if (!mpFrameData->mpBuffer)
111 return;
113 if (!m_aPaintRect.IsEmpty())
115 // copy the buffer content to the actual window
116 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
117 // painting directly instead of using Invalidate()
118 // [ie. everything you can see was painted directly to the
119 // window either above or in eg. an event handler]
120 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
122 // Make sure that the +1 value GetSize() adds to the size is in pixels.
123 Size aPaintRectSize;
124 if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
126 aPaintRectSize = m_aPaintRect.GetSize();
128 else
130 tools::Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
131 aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
134 m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer);
138 // Restore buffer state.
139 mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
140 mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
142 mpFrameData->mpBuffer->Pop();
143 mpFrameData->mpBuffer->SetSettings(maSettings);
144 if (mbBackground)
145 mpFrameData->mpBuffer->SetBackground(maBackground);
146 else
147 mpFrameData->mpBuffer->SetBackground();
150 void PaintBufferGuard::SetPaintRect(const tools::Rectangle& rRectangle)
152 m_aPaintRect = rRectangle;
155 vcl::RenderContext* PaintBufferGuard::GetRenderContext()
157 if (mpFrameData->mpBuffer)
158 return mpFrameData->mpBuffer;
159 else
160 return m_pWindow;
164 class PaintHelper
166 private:
167 VclPtr<vcl::Window> m_pWindow;
168 std::unique_ptr<vcl::Region> m_pChildRegion;
169 tools::Rectangle m_aSelectionRect;
170 tools::Rectangle m_aPaintRect;
171 vcl::Region m_aPaintRegion;
172 ImplPaintFlags m_nPaintFlags;
173 bool m_bPop : 1;
174 bool m_bRestoreCursor : 1;
175 bool m_bStartedBufferedPaint : 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
176 public:
177 PaintHelper(vcl::Window* pWindow, ImplPaintFlags nPaintFlags);
178 void SetPop()
180 m_bPop = true;
182 void SetPaintRect(const tools::Rectangle& rRect)
184 m_aPaintRect = rRect;
186 void SetSelectionRect(const tools::Rectangle& rRect)
188 m_aSelectionRect = rRect;
190 void SetRestoreCursor(bool bRestoreCursor)
192 m_bRestoreCursor = bRestoreCursor;
194 bool GetRestoreCursor() const
196 return m_bRestoreCursor;
198 ImplPaintFlags GetPaintFlags() const
200 return m_nPaintFlags;
202 vcl::Region& GetPaintRegion()
204 return m_aPaintRegion;
206 void DoPaint(const vcl::Region* pRegion);
208 /// Start buffered paint: set it up to have the same settings as m_pWindow.
209 void StartBufferedPaint();
211 /// Paint the content of the buffer to the current m_pWindow.
212 void PaintBuffer();
214 ~PaintHelper();
217 PaintHelper::PaintHelper(vcl::Window *pWindow, ImplPaintFlags nPaintFlags)
218 : m_pWindow(pWindow)
219 , m_nPaintFlags(nPaintFlags)
220 , m_bPop(false)
221 , m_bRestoreCursor(false)
222 , m_bStartedBufferedPaint(false)
226 void PaintHelper::StartBufferedPaint()
228 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
229 assert(!pFrameData->mbInBufferedPaint);
231 pFrameData->mbInBufferedPaint = true;
232 pFrameData->maBufferedRect = tools::Rectangle();
233 m_bStartedBufferedPaint = true;
236 void PaintHelper::PaintBuffer()
238 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
239 assert(pFrameData->mbInBufferedPaint);
240 assert(m_bStartedBufferedPaint);
242 vcl::PaintBufferGuard aGuard(pFrameData, m_pWindow);
243 aGuard.SetPaintRect(pFrameData->maBufferedRect);
246 void PaintHelper::DoPaint(const vcl::Region* pRegion)
248 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
250 vcl::Region* pWinChildClipRegion = m_pWindow->ImplGetWinChildClipRegion();
251 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
252 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll || pFrameData->mbInBufferedPaint)
254 pWindowImpl->maInvalidateRegion = *pWinChildClipRegion;
256 else
258 if (pRegion)
259 pWindowImpl->maInvalidateRegion.Union( *pRegion );
261 if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible)
262 /* #98602# need to repaint all children within the
263 * tracking rectangle, so the following invert
264 * operation takes places without traces of the previous
265 * one.
267 pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
269 if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren)
270 m_pChildRegion.reset( new vcl::Region(pWindowImpl->maInvalidateRegion) );
271 pWindowImpl->maInvalidateRegion.Intersect(*pWinChildClipRegion);
273 pWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
274 if (pWindowImpl->maInvalidateRegion.IsEmpty())
275 return;
277 #if HAVE_FEATURE_OPENGL
278 VCL_GL_INFO("PaintHelper::DoPaint on " <<
279 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
280 #endif
281 // double-buffering: setup the buffer if it does not exist
282 if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
283 StartBufferedPaint();
285 // double-buffering: if this window does not support double-buffering,
286 // but we are in the middle of double-buffered paint, we might be
287 // losing information
288 if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
289 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
291 if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
293 // double-buffering
294 vcl::PaintBufferGuard g(pFrameData, m_pWindow);
295 m_pWindow->ApplySettings(*pFrameData->mpBuffer);
297 m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer);
298 m_pWindow->Paint(*pFrameData->mpBuffer, m_aPaintRect);
299 pFrameData->maBufferedRect.Union(m_aPaintRect);
301 else
303 // direct painting
304 Wallpaper aBackground = m_pWindow->GetBackground();
305 m_pWindow->ApplySettings(*m_pWindow);
306 // Restore bitmap background if it was lost.
307 if (aBackground.IsBitmap() && !m_pWindow->GetBackground().IsBitmap())
309 m_pWindow->SetBackground(aBackground);
311 m_pWindow->PushPaintHelper(this, *m_pWindow);
312 m_pWindow->Paint(*m_pWindow, m_aPaintRect);
314 #if HAVE_FEATURE_OPENGL
315 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
316 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
317 #endif
320 namespace vcl
323 void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window const & rWindow,
324 const tools::Rectangle& rRect, sal_uInt16 nHighlight,
325 bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
326 Color* pSelectionTextColor, tools::Long nCornerRadius, Color const * pPaintColor)
328 if (rRect.IsEmpty())
329 return;
331 bool bRoundEdges = nCornerRadius > 0;
333 const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
335 // colors used for item highlighting
336 Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
337 Color aSelectionFillColor(aSelectionBorderColor);
339 bool bDark = rStyles.GetFaceColor().IsDark();
340 bool bBright = ( rStyles.GetFaceColor() == COL_WHITE );
342 int c1 = aSelectionBorderColor.GetLuminance();
343 int c2 = rWindow.GetBackgroundColor().GetLuminance();
345 if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
347 // contrast too low
348 sal_uInt16 h, s, b;
349 aSelectionFillColor.RGBtoHSB( h, s, b );
350 if( b > 50 ) b -= 40;
351 else b += 40;
352 aSelectionFillColor = Color::HSBtoRGB( h, s, b );
353 aSelectionBorderColor = aSelectionFillColor;
356 if (bRoundEdges)
358 if (aSelectionBorderColor.IsDark())
359 aSelectionBorderColor.IncreaseLuminance(128);
360 else
361 aSelectionBorderColor.DecreaseLuminance(128);
364 tools::Rectangle aRect(rRect);
365 if (bDrawExtBorderOnly)
367 aRect.AdjustLeft( -1 );
368 aRect.AdjustTop( -1 );
369 aRect.AdjustRight(1 );
370 aRect.AdjustBottom(1 );
372 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
374 if (bDrawBorder)
375 rRenderContext.SetLineColor(bDark ? COL_WHITE : (bBright ? COL_BLACK : aSelectionBorderColor));
376 else
377 rRenderContext.SetLineColor();
379 sal_uInt16 nPercent = 0;
380 if (!nHighlight)
382 if (bDark)
383 aSelectionFillColor = COL_BLACK;
384 else
385 nPercent = 80; // just checked (light)
387 else
389 if (bChecked && nHighlight == 2)
391 if (bDark)
392 aSelectionFillColor = COL_LIGHTGRAY;
393 else if (bBright)
395 aSelectionFillColor = COL_BLACK;
396 rRenderContext.SetLineColor(COL_BLACK);
397 nPercent = 0;
399 else
400 nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
402 else if (bChecked || nHighlight == 1)
404 if (bDark)
405 aSelectionFillColor = COL_GRAY;
406 else if (bBright)
408 aSelectionFillColor = COL_BLACK;
409 rRenderContext.SetLineColor(COL_BLACK);
410 nPercent = 0;
412 else
413 nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
415 else
417 if (bDark)
418 aSelectionFillColor = COL_LIGHTGRAY;
419 else if (bBright)
421 aSelectionFillColor = COL_BLACK;
422 rRenderContext.SetLineColor(COL_BLACK);
423 if (nHighlight == 3)
424 nPercent = 80;
425 else
426 nPercent = 0;
428 else
429 nPercent = 70; // selected ( dark )
433 if (bDark && bDrawExtBorderOnly)
435 rRenderContext.SetFillColor();
436 if (pSelectionTextColor)
437 *pSelectionTextColor = rStyles.GetHighlightTextColor();
439 else
441 rRenderContext.SetFillColor(aSelectionFillColor);
442 if (pSelectionTextColor)
444 Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
445 Color aHLTextColor = rStyles.GetHighlightTextColor();
446 int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
447 int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
448 *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
452 if (bDark)
454 rRenderContext.DrawRect(aRect);
456 else
458 if (bRoundEdges)
460 tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
461 tools::PolyPolygon aPolyPoly(aPoly);
462 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
464 else
466 tools::Polygon aPoly(aRect);
467 tools::PolyPolygon aPolyPoly(aPoly);
468 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
472 rRenderContext.Pop(); // LINECOLOR | FILLCOLOR
475 void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
477 pHelper->SetPop();
479 if ( mpWindowImpl->mpCursor )
480 pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
482 mbInitClipRegion = true;
483 mpWindowImpl->mbInPaint = true;
485 // restore Paint-Region
486 vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
487 rPaintRegion = mpWindowImpl->maInvalidateRegion;
488 tools::Rectangle aPaintRect = rPaintRegion.GetBoundRect();
490 // RTL: re-mirror paint rect and region at this window
491 if (ImplIsAntiparallel())
493 rRenderContext.ReMirror(aPaintRect);
494 rRenderContext.ReMirror(rPaintRegion);
496 aPaintRect = ImplDevicePixelToLogic(aPaintRect);
497 mpWindowImpl->mpPaintRegion = &rPaintRegion;
498 mpWindowImpl->maInvalidateRegion.SetEmpty();
500 if ((pHelper->GetPaintFlags() & ImplPaintFlags::Erase) && rRenderContext.IsBackground())
502 if (rRenderContext.IsClipRegion())
504 vcl::Region aOldRegion = rRenderContext.GetClipRegion();
505 rRenderContext.SetClipRegion();
506 Erase(rRenderContext);
507 rRenderContext.SetClipRegion(aOldRegion);
509 else
510 Erase(rRenderContext);
513 // #98943# trigger drawing of toolbox selection after all children are painted
514 if (mpWindowImpl->mbDrawSelectionBackground)
515 pHelper->SetSelectionRect(aPaintRect);
516 pHelper->SetPaintRect(aPaintRect);
519 void Window::PopPaintHelper(PaintHelper const *pHelper)
521 if (mpWindowImpl->mpWinData)
523 if (mpWindowImpl->mbFocusVisible)
524 ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
526 mpWindowImpl->mbInPaint = false;
527 mbInitClipRegion = true;
528 mpWindowImpl->mpPaintRegion = nullptr;
529 if (mpWindowImpl->mpCursor)
530 mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
533 } /* namespace vcl */
535 PaintHelper::~PaintHelper()
537 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
538 if (m_bPop)
540 m_pWindow->PopPaintHelper(this);
543 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
544 if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
546 // Paint from the bottom child window and frontward.
547 vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
548 while (pTempWindow)
550 if (pTempWindow->mpWindowImpl->mbVisible)
551 pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
552 pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
556 if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
557 /* #98602# need to invert the tracking rect AFTER
558 * the children have painted
560 m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
562 // double-buffering: paint in case we created the buffer, the children are
563 // already painted inside
564 if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
566 PaintBuffer();
567 pFrameData->mbInBufferedPaint = false;
568 pFrameData->maBufferedRect = tools::Rectangle();
571 // #98943# draw toolbox selection
572 if( !m_aSelectionRect.IsEmpty() )
573 m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
576 namespace vcl {
578 void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
580 // call PrePaint. PrePaint may add to the invalidate region as well as
581 // other parameters used below.
582 PrePaint(*this);
584 mpWindowImpl->mbPaintFrame = false;
586 if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
587 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll);
588 if (nPaintFlags & ImplPaintFlags::PaintChildren)
589 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren;
590 if (nPaintFlags & ImplPaintFlags::Erase)
591 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
592 if (nPaintFlags & ImplPaintFlags::CheckRtl)
593 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
594 if (!mpWindowImpl->mpFirstChild)
595 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
597 if (mpWindowImpl->mbPaintDisabled)
599 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
600 Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
601 else if ( pRegion )
602 Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
604 // call PostPaint before returning
605 PostPaint(*this);
607 return;
610 nPaintFlags = mpWindowImpl->mnPaintFlags & ~ImplPaintFlags::Paint;
612 PaintHelper aHelper(this, nPaintFlags);
614 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
615 aHelper.DoPaint(pRegion);
616 else
617 mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
619 // call PostPaint
620 PostPaint(*this);
623 void Window::ImplCallOverlapPaint()
625 // emit overlapping windows first
626 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
627 while ( pTempWindow )
629 if ( pTempWindow->mpWindowImpl->mbReallyVisible )
630 pTempWindow->ImplCallOverlapPaint();
631 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
634 // only then ourself
635 if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
637 // RTL: notify ImplCallPaint to check for re-mirroring
638 // because we were called from the Sal layer
639 ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
643 IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void)
645 #ifndef IOS
646 comphelper::ProfileZone aZone("VCL idle re-paint");
648 // save paint events until layout is done
649 if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
651 mpWindowImpl->mpFrameData->maPaintIdle.Start();
652 return;
655 // save paint events until resizing or initial sizing done
656 if (mpWindowImpl->mbFrame &&
657 mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
659 mpWindowImpl->mpFrameData->maPaintIdle.Start();
661 else if ( mpWindowImpl->mbReallyVisible )
663 ImplCallOverlapPaint();
664 if (comphelper::LibreOfficeKit::isActive() &&
665 mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
666 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
668 #endif
671 IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void)
673 comphelper::ProfileZone aZone("VCL idle resize");
675 if( mpWindowImpl->mbReallyVisible )
677 ImplCallResize();
678 if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
680 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
681 mpWindowImpl->mpFrameData->maPaintIdle.Invoke( nullptr );
686 void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
688 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
689 if ( !ImplIsOverlapWindow() )
691 vcl::Window* pTempWindow = this;
692 ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE;
695 pTempWindow = pTempWindow->ImplGetParent();
696 if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren )
697 break;
698 pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint;
699 if( ! pTempWindow->IsPaintTransparent() )
700 nTranspPaint = ImplPaintFlags::NONE;
702 while ( !pTempWindow->ImplIsOverlapWindow() );
705 // set Paint-Flags
706 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint;
707 if ( nFlags & InvalidateFlags::Children )
708 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren;
709 if ( !(nFlags & InvalidateFlags::NoErase) )
710 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
712 if ( !pRegion )
713 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll;
714 else if ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
716 // if not everything has to be redrawn, add the region to it
717 mpWindowImpl->maInvalidateRegion.Union( *pRegion );
720 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
721 if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
722 && ImplGetParent() )
724 vcl::Window *pParent = ImplGetParent();
725 while( pParent && pParent->IsPaintTransparent() )
726 pParent = pParent->ImplGetParent();
727 if( pParent )
729 vcl::Region *pChildRegion;
730 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
731 // invalidate the whole child window region in the parent
732 pChildRegion = ImplGetWinChildClipRegion();
733 else
734 // invalidate the same region in the parent that has to be repainted in the child
735 pChildRegion = &mpWindowImpl->maInvalidateRegion;
737 nFlags |= InvalidateFlags::Children; // paint should also be done on all children
738 nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
739 pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
743 if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
744 mpWindowImpl->mpFrameData->maPaintIdle.Start();
747 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
749 vcl::Region aRegion = rRegion;
751 ImplClipBoundaries( aRegion, true, true );
752 if ( !aRegion.IsEmpty() )
753 ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
755 // now we invalidate the overlapping windows
756 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
757 while ( pTempWindow )
759 if ( pTempWindow->IsVisible() )
760 pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
762 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
766 void Window::ImplInvalidateParentFrameRegion( vcl::Region& rRegion )
768 if ( mpWindowImpl->mbOverlapWin )
769 mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
770 else
772 if( ImplGetParent() )
773 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
777 void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
779 // check what has to be redrawn
780 bool bInvalidateAll = !pRegion;
782 // take Transparent-Invalidate into account
783 vcl::Window* pOpaqueWindow = this;
784 if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
786 vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
787 while ( pTempWindow )
789 if ( !pTempWindow->IsPaintTransparent() )
791 pOpaqueWindow = pTempWindow;
792 nFlags |= InvalidateFlags::Children;
793 bInvalidateAll = false;
794 break;
797 if ( pTempWindow->ImplIsOverlapWindow() )
798 break;
800 pTempWindow = pTempWindow->ImplGetParent();
804 // assemble region
805 InvalidateFlags nOrgFlags = nFlags;
806 if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
808 if ( GetStyle() & WB_CLIPCHILDREN )
809 nFlags |= InvalidateFlags::NoChildren;
810 else
811 nFlags |= InvalidateFlags::Children;
813 if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
814 bInvalidateAll = false;
815 if ( bInvalidateAll )
816 ImplInvalidateFrameRegion( nullptr, nFlags );
817 else
819 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
820 vcl::Region aRegion( aRect );
821 if ( pRegion )
823 // RTL: remirror region before intersecting it
824 if ( ImplIsAntiparallel() )
826 const OutputDevice *pOutDev = GetOutDev();
828 vcl::Region aRgn( *pRegion );
829 pOutDev->ReMirror( aRgn );
830 aRegion.Intersect( aRgn );
832 else
833 aRegion.Intersect( *pRegion );
835 ImplClipBoundaries( aRegion, true, true );
836 if ( nFlags & InvalidateFlags::NoChildren )
838 nFlags &= ~InvalidateFlags::Children;
839 if ( !(nFlags & InvalidateFlags::NoClipChildren) )
841 if ( nOrgFlags & InvalidateFlags::NoChildren )
842 ImplClipAllChildren( aRegion );
843 else
845 if ( ImplClipChildren( aRegion ) )
846 nFlags |= InvalidateFlags::Children;
850 if ( !aRegion.IsEmpty() )
851 ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
854 if ( nFlags & InvalidateFlags::Update )
855 pOpaqueWindow->PaintImmediately(); // start painting at the opaque parent
858 void Window::ImplMoveInvalidateRegion( const tools::Rectangle& rRect,
859 tools::Long nHorzScroll, tools::Long nVertScroll,
860 bool bChildren )
862 if ( (mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintAll)) == ImplPaintFlags::Paint )
864 vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
865 aTempRegion.Intersect( rRect );
866 aTempRegion.Move( nHorzScroll, nVertScroll );
867 mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
870 if ( bChildren && (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren) )
872 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
873 while ( pWindow )
875 pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
876 pWindow = pWindow->mpWindowImpl->mpNext;
881 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
882 tools::Long nHorzScroll, tools::Long nVertScroll,
883 bool bChildren )
885 // also shift Paint-Region when paints need processing
886 ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
887 // Paint-Region should be shifted, as drawn by the parents
888 if ( ImplIsOverlapWindow() )
889 return;
891 vcl::Region aPaintAllRegion;
892 vcl::Window* pPaintAllWindow = this;
895 pPaintAllWindow = pPaintAllWindow->ImplGetParent();
896 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
898 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
900 aPaintAllRegion.SetEmpty();
901 break;
903 else
904 aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
907 while ( !pPaintAllWindow->ImplIsOverlapWindow() );
908 if ( !aPaintAllRegion.IsEmpty() )
910 aPaintAllRegion.Move( nHorzScroll, nVertScroll );
911 InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
912 if ( bChildren )
913 nPaintFlags |= InvalidateFlags::Children;
914 ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
918 void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
920 if ( !pRegion )
921 mpWindowImpl->maInvalidateRegion.SetEmpty();
922 else
924 // when all child windows have to be drawn we need to invalidate them before doing so
925 if ( (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren) && mpWindowImpl->mpFirstChild )
927 vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
928 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
930 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
931 aChildRegion = aRect;
933 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
934 while ( pChild )
936 pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
937 pChild = pChild->mpWindowImpl->mpNext;
940 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
942 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
943 mpWindowImpl->maInvalidateRegion = aRect;
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 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
976 vcl::Region aRegion( aRect );
977 ImplClipBoundaries( aRegion, true, true );
978 if ( nFlags & ValidateFlags::NoChildren )
980 nFlags &= ~ValidateFlags::Children;
981 if ( ImplClipChildren( aRegion ) )
982 nFlags |= ValidateFlags::Children;
984 if ( !aRegion.IsEmpty() )
985 ImplValidateFrameRegion( &aRegion, nFlags );
989 void Window::ImplUpdateAll()
991 if ( !mpWindowImpl->mbReallyVisible )
992 return;
994 bool bFlush = false;
995 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
997 Point aPoint( 0, 0 );
998 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
999 ImplInvalidateOverlapFrameRegion( aRegion );
1000 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1001 bFlush = true;
1004 // an update changes the OverlapWindow, such that for later paints
1005 // not too much has to be drawn, if ALLCHILDREN etc. is set
1006 vcl::Window* pWindow = ImplGetFirstOverlapWindow();
1007 pWindow->ImplCallOverlapPaint();
1009 if ( bFlush )
1010 Flush();
1013 void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1017 void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1021 void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect)
1023 CallEventListeners(VclEventId::WindowPaint, const_cast<tools::Rectangle *>(&rRect));
1026 void Window::SetPaintTransparent( bool bTransparent )
1028 // transparency is not useful for frames as the background would have to be provided by a different frame
1029 if( bTransparent && mpWindowImpl->mbFrame )
1030 return;
1032 if ( mpWindowImpl->mpBorderWindow )
1033 mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1035 mpWindowImpl->mbPaintTransparent = bTransparent;
1038 void Window::SetWindowRegionPixel()
1041 if ( mpWindowImpl->mpBorderWindow )
1042 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1043 else if( mpWindowImpl->mbFrame )
1045 mpWindowImpl->maWinRegion = vcl::Region(true);
1046 mpWindowImpl->mbWinRegion = false;
1047 mpWindowImpl->mpFrame->ResetClipRegion();
1049 else
1051 if ( mpWindowImpl->mbWinRegion )
1053 mpWindowImpl->maWinRegion = vcl::Region(true);
1054 mpWindowImpl->mbWinRegion = false;
1055 ImplSetClipFlag();
1057 if ( IsReallyVisible() )
1059 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1060 vcl::Region aRegion( aRect );
1061 ImplInvalidateParentFrameRegion( aRegion );
1067 void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1070 if ( mpWindowImpl->mpBorderWindow )
1071 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1072 else if( mpWindowImpl->mbFrame )
1074 if( !rRegion.IsNull() )
1076 mpWindowImpl->maWinRegion = rRegion;
1077 mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1079 if( mpWindowImpl->mbWinRegion )
1081 // set/update ClipRegion
1082 RectangleVector aRectangles;
1083 mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1084 mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1086 for (auto const& rectangle : aRectangles)
1088 mpWindowImpl->mpFrame->UnionClipRegion(
1089 rectangle.Left(),
1090 rectangle.Top(),
1091 rectangle.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1092 rectangle.GetHeight()); // same for height
1095 mpWindowImpl->mpFrame->EndSetClipRegion();
1097 //long nX;
1098 //long nY;
1099 //long nWidth;
1100 //long nHeight;
1101 //sal_uLong nRectCount;
1102 //ImplRegionInfo aInfo;
1103 //sal_Bool bRegionRect;
1105 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1106 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1107 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1108 //while ( bRegionRect )
1110 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1111 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1113 //mpWindowImpl->mpFrame->EndSetClipRegion();
1115 else
1116 SetWindowRegionPixel();
1118 else
1119 SetWindowRegionPixel();
1121 else
1123 if ( rRegion.IsNull() )
1125 if ( mpWindowImpl->mbWinRegion )
1127 mpWindowImpl->maWinRegion = vcl::Region(true);
1128 mpWindowImpl->mbWinRegion = false;
1129 ImplSetClipFlag();
1132 else
1134 mpWindowImpl->maWinRegion = rRegion;
1135 mpWindowImpl->mbWinRegion = true;
1136 ImplSetClipFlag();
1139 if ( IsReallyVisible() )
1141 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1142 vcl::Region aRegion( aRect );
1143 ImplInvalidateParentFrameRegion( aRegion );
1148 vcl::Region Window::GetPaintRegion() const
1151 if ( mpWindowImpl->mpPaintRegion )
1153 vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1154 aRegion.Move( -mnOutOffX, -mnOutOffY );
1155 return PixelToLogic( aRegion );
1157 else
1159 vcl::Region aPaintRegion(true);
1160 return aPaintRegion;
1164 void Window::Invalidate( InvalidateFlags nFlags )
1166 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1167 return;
1169 ImplInvalidate( nullptr, nFlags );
1170 LogicInvalidate(nullptr);
1173 void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1175 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1176 return;
1178 OutputDevice *pOutDev = GetOutDev();
1179 tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1180 if ( !aRect.IsEmpty() )
1182 vcl::Region aRegion( aRect );
1183 ImplInvalidate( &aRegion, nFlags );
1184 tools::Rectangle aLogicRectangle(rRect);
1185 LogicInvalidate(&aLogicRectangle);
1189 void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1191 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1192 return;
1194 if ( rRegion.IsNull() )
1196 ImplInvalidate( nullptr, nFlags );
1197 LogicInvalidate(nullptr);
1199 else
1201 vcl::Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1202 if ( !aRegion.IsEmpty() )
1204 ImplInvalidate( &aRegion, nFlags );
1205 tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1206 LogicInvalidate(&aLogicRectangle);
1211 void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1213 if(pRectangle)
1215 tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1216 PixelInvalidate(&aRect);
1218 else
1219 PixelInvalidate(nullptr);
1222 void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1224 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1225 return;
1227 Size aSize = GetSizePixel();
1228 if (aSize.IsEmpty())
1229 return;
1231 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1233 // In case we are routing the window, notify the client
1234 std::vector<vcl::LOKPayloadItem> aPayload;
1235 if (pRectangle)
1236 aPayload.emplace_back("rectangle", pRectangle->toString());
1237 else
1239 const tools::Rectangle aRect(Point(0, 0), aSize);
1240 aPayload.emplace_back("rectangle", aRect.toString());
1243 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
1245 // Added for dialog items. Pass invalidation to the parent window.
1246 else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1248 const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1249 pParent->PixelInvalidate(&aRect);
1253 void Window::Validate()
1255 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1256 return;
1258 ImplValidate();
1261 bool Window::HasPaintEvent() const
1264 if ( !mpWindowImpl->mbReallyVisible )
1265 return false;
1267 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1268 return true;
1270 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1271 return true;
1273 if ( !ImplIsOverlapWindow() )
1275 const vcl::Window* pTempWindow = this;
1278 pTempWindow = pTempWindow->ImplGetParent();
1279 if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1280 return true;
1282 while ( !pTempWindow->ImplIsOverlapWindow() );
1285 return false;
1288 void Window::PaintImmediately()
1290 if ( mpWindowImpl->mpBorderWindow )
1292 mpWindowImpl->mpBorderWindow->PaintImmediately();
1293 return;
1296 if ( !mpWindowImpl->mbReallyVisible )
1297 return;
1299 bool bFlush = false;
1300 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1302 Point aPoint( 0, 0 );
1303 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1304 ImplInvalidateOverlapFrameRegion( aRegion );
1305 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1306 bFlush = true;
1309 // First we should skip all windows which are Paint-Transparent
1310 vcl::Window* pUpdateWindow = this;
1311 vcl::Window* pWindow = pUpdateWindow;
1312 while ( !pWindow->ImplIsOverlapWindow() )
1314 if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1316 pUpdateWindow = pWindow;
1317 break;
1319 pWindow = pWindow->ImplGetParent();
1321 // In order to limit drawing, an update only draws the window which
1322 // has PAINTALLCHILDREN set
1323 pWindow = pUpdateWindow;
1326 if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
1327 pUpdateWindow = pWindow;
1328 if ( pWindow->ImplIsOverlapWindow() )
1329 break;
1330 pWindow = pWindow->ImplGetParent();
1332 while ( pWindow );
1334 // if there is something to paint, trigger a Paint
1335 if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
1337 VclPtr<vcl::Window> xWindow(this);
1339 // trigger an update also for system windows on top of us,
1340 // otherwise holes would remain
1341 vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap;
1342 while ( pUpdateOverlapWindow )
1344 pUpdateOverlapWindow->PaintImmediately();
1345 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1348 pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1350 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1351 pUpdateWindow->LogicInvalidate(nullptr);
1353 if (xWindow->IsDisposed())
1354 return;
1356 bFlush = true;
1359 if ( bFlush )
1360 Flush();
1363 void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1365 // Special drawing when called through LOKit
1366 // TODO: Move to its own method
1367 if (comphelper::LibreOfficeKit::isActive())
1369 VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1371 Size aSize(GetOutputSizePixel());
1372 pDevice->SetOutputSizePixel(aSize);
1374 vcl::Font aCopyFont = GetFont();
1375 pDevice->SetFont(aCopyFont);
1377 pDevice->SetTextColor(GetTextColor());
1378 if (IsLineColor())
1379 pDevice->SetLineColor(GetLineColor());
1380 else
1381 pDevice->SetLineColor();
1383 if (IsFillColor())
1384 pDevice->SetFillColor(GetFillColor());
1385 else
1386 pDevice->SetFillColor();
1388 if (IsTextLineColor())
1389 pDevice->SetTextLineColor(GetTextLineColor());
1390 else
1391 pDevice->SetTextLineColor();
1393 if (IsOverlineColor())
1394 pDevice->SetOverlineColor(GetOverlineColor());
1395 else
1396 pDevice->SetOverlineColor();
1398 if (IsTextFillColor())
1399 pDevice->SetTextFillColor(GetTextFillColor());
1400 else
1401 pDevice->SetTextFillColor();
1403 pDevice->SetTextAlign(GetTextAlign());
1404 pDevice->SetRasterOp(GetRasterOp());
1406 tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1408 vcl::Region aClipRegion(GetClipRegion());
1409 pDevice->SetClipRegion();
1410 aClipRegion.Intersect(aPaintRect);
1411 pDevice->SetClipRegion(aClipRegion);
1413 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1414 Erase(*pDevice);
1416 pDevice->SetMapMode(GetMapMode());
1418 Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1420 i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1422 // get rid of virtual device now so they don't pile up during recursive calls
1423 pDevice.disposeAndClear();
1426 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1428 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1430 tools::Long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1431 tools::Long nDeltaY = pChild->mnOutOffY - mnOutOffY;
1433 Point aPos( i_rPos );
1434 aPos += Point(nDeltaX, nDeltaY);
1436 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1439 return;
1443 bool bRVisible = mpWindowImpl->mbReallyVisible;
1444 mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1445 bool bDevOutput = mbDevOutput;
1446 mbDevOutput = true;
1448 const OutputDevice *pOutDev = GetOutDev();
1449 tools::Long nOldDPIX = pOutDev->GetDPIX();
1450 tools::Long nOldDPIY = pOutDev->GetDPIY();
1451 mnDPIX = i_pTargetOutDev->GetDPIX();
1452 mnDPIY = i_pTargetOutDev->GetDPIY();
1453 bool bOutput = IsOutputEnabled();
1454 EnableOutput();
1456 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1457 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1458 return;
1460 // preserve graphicsstate
1461 Push();
1462 vcl::Region aClipRegion( GetClipRegion() );
1463 SetClipRegion();
1465 GDIMetaFile* pOldMtf = GetConnectMetaFile();
1466 GDIMetaFile aMtf;
1467 SetConnectMetaFile( &aMtf );
1469 // put a push action to metafile
1470 Push();
1471 // copy graphics state to metafile
1472 vcl::Font aCopyFont = GetFont();
1473 if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY )
1475 aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * mnDPIY / nOldDPIY );
1476 aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * mnDPIX / nOldDPIX );
1478 SetFont( aCopyFont );
1479 SetTextColor( GetTextColor() );
1480 if( IsLineColor() )
1481 SetLineColor( GetLineColor() );
1482 else
1483 SetLineColor();
1484 if( IsFillColor() )
1485 SetFillColor( GetFillColor() );
1486 else
1487 SetFillColor();
1488 if( IsTextLineColor() )
1489 SetTextLineColor( GetTextLineColor() );
1490 else
1491 SetTextLineColor();
1492 if( IsOverlineColor() )
1493 SetOverlineColor( GetOverlineColor() );
1494 else
1495 SetOverlineColor();
1496 if( IsTextFillColor() )
1497 SetTextFillColor( GetTextFillColor() );
1498 else
1499 SetTextFillColor();
1500 SetTextAlign( GetTextAlign() );
1501 SetRasterOp( GetRasterOp() );
1502 if( IsRefPoint() )
1503 SetRefPoint( GetRefPoint() );
1504 else
1505 SetRefPoint();
1506 SetLayoutMode( GetLayoutMode() );
1508 SetDigitLanguage( GetDigitLanguage() );
1509 tools::Rectangle aPaintRect(Point(0, 0), GetOutputSizePixel());
1510 aClipRegion.Intersect( aPaintRect );
1511 SetClipRegion( aClipRegion );
1513 // do the actual paint
1515 // background
1516 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1518 Erase(*this);
1520 // foreground
1521 Paint(*this, aPaintRect);
1522 // put a pop action to metafile
1523 Pop();
1525 SetConnectMetaFile( pOldMtf );
1526 EnableOutput( bOutput );
1527 mpWindowImpl->mbReallyVisible = bRVisible;
1529 // paint metafile to VDev
1530 VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1531 DeviceFormat::DEFAULT,
1532 DeviceFormat::DEFAULT);
1534 pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() );
1535 pMaskedDevice->EnableRTL( IsRTLEnabled() );
1536 aMtf.WindStart();
1537 aMtf.Play( pMaskedDevice );
1538 BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), aPaintRect.GetSize() ) );
1539 i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
1540 // get rid of virtual device now so they don't pile up during recursive calls
1541 pMaskedDevice.disposeAndClear();
1543 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1545 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1547 tools::Long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1549 if( pOutDev->HasMirroredGraphics() )
1550 nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth;
1551 tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1552 Point aPos( i_rPos );
1553 Point aDelta( nDeltaX, nDeltaY );
1554 aPos += aDelta;
1555 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1559 // restore graphics state
1560 Pop();
1562 EnableOutput( bOutput );
1563 mpWindowImpl->mbReallyVisible = bRVisible;
1564 mbDevOutput = bDevOutput;
1565 mnDPIX = nOldDPIX;
1566 mnDPIY = nOldDPIY;
1569 void Window::PaintToDevice(OutputDevice* pDev, const Point& rPos)
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 (!IsDeviceOutputNecessary() || 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 (mbBackground && !bNativeOK)
1628 RasterOp eRasterOp = GetRasterOp();
1629 if (eRasterOp != RasterOp::OverPaint)
1630 SetRasterOp(RasterOp::OverPaint);
1631 rRenderContext.DrawWallpaper(0, 0, mnOutWidth, mnOutHeight, maBackground);
1632 if (eRasterOp != RasterOp::OverPaint)
1633 rRenderContext.SetRasterOp(eRasterOp);
1636 if (mpAlphaVDev)
1637 mpAlphaVDev->Erase();
1640 void Window::ImplScroll( const tools::Rectangle& rRect,
1641 tools::Long nHorzScroll, tools::Long nVertScroll, ScrollFlags nFlags )
1643 if ( !IsDeviceOutputNecessary() )
1644 return;
1646 nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll );
1647 nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll );
1649 if ( !nHorzScroll && !nVertScroll )
1650 return;
1652 if ( mpWindowImpl->mpCursor )
1653 mpWindowImpl->mpCursor->ImplSuspend();
1655 ScrollFlags nOrgFlags = nFlags;
1656 if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1658 if ( GetStyle() & WB_CLIPCHILDREN )
1659 nFlags |= ScrollFlags::NoChildren;
1660 else
1661 nFlags |= ScrollFlags::Children;
1664 vcl::Region aInvalidateRegion;
1665 bool bScrollChildren(nFlags & ScrollFlags::Children);
1667 if ( !mpWindowImpl->mpFirstChild )
1668 bScrollChildren = false;
1670 OutputDevice *pOutDev = GetOutDev();
1672 // RTL: check if this window requires special action
1673 bool bReMirror = ImplIsAntiparallel();
1675 tools::Rectangle aRectMirror( rRect );
1676 if( bReMirror )
1678 // make sure the invalidate region of this window is
1679 // computed in the same coordinate space as the one from the overlap windows
1680 pOutDev->ReMirror( aRectMirror );
1683 // adapt paint areas
1684 ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1686 ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1688 // if the scrolling on the device is performed in the opposite direction
1689 // then move the overlaps in that direction to compute the invalidate region
1690 // on the correct side, i.e., revert nHorzScroll
1691 if (!aInvalidateRegion.IsEmpty())
1693 aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1696 tools::Rectangle aDestRect(aRectMirror);
1697 aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1698 vcl::Region aWinInvalidateRegion(aRectMirror);
1699 if (!SupportsDoubleBuffering())
1701 // There will be no CopyArea() call below, so invalidate the
1702 // whole visible area, not only the smaller one that was just
1703 // scrolled in.
1704 aWinInvalidateRegion.Exclude(aDestRect);
1707 aInvalidateRegion.Union(aWinInvalidateRegion);
1709 Point aPoint( mnOutOffX, mnOutOffY );
1710 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1711 if ( nFlags & ScrollFlags::Clip )
1712 aRegion.Intersect( rRect );
1713 if ( mpWindowImpl->mbWinRegion )
1714 aRegion.Intersect( 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 ( mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1727 aRegion.Intersect( 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 && !SupportsDoubleBuffering())
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 this );
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: */