bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / window / paint.cxx
bloba99ae752de4525db1e42b194c12018945e53d255
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 const 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())
276 #if HAVE_FEATURE_OPENGL
277 VCL_GL_INFO("PaintHelper::DoPaint on " <<
278 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
279 #endif
280 // double-buffering: setup the buffer if it does not exist
281 if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
282 StartBufferedPaint();
284 // double-buffering: if this window does not support double-buffering,
285 // but we are in the middle of double-buffered paint, we might be
286 // losing information
287 if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
288 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
290 if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
292 // double-buffering
293 vcl::PaintBufferGuard g(pFrameData, m_pWindow);
294 m_pWindow->ApplySettings(*pFrameData->mpBuffer);
296 m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer);
297 m_pWindow->Paint(*pFrameData->mpBuffer, m_aPaintRect);
298 pFrameData->maBufferedRect.Union(m_aPaintRect);
300 else
302 // direct painting
303 Wallpaper aBackground = m_pWindow->GetBackground();
304 m_pWindow->ApplySettings(*m_pWindow);
305 // Restore lost bitmap background.
306 if (aBackground.IsBitmap())
307 m_pWindow->SetBackground(aBackground);
308 m_pWindow->PushPaintHelper(this, *m_pWindow);
309 m_pWindow->Paint(*m_pWindow, m_aPaintRect);
311 #if HAVE_FEATURE_OPENGL
312 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
313 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
314 #endif
318 namespace vcl
321 void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window const & rWindow,
322 const tools::Rectangle& rRect, sal_uInt16 nHighlight,
323 bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
324 Color* pSelectionTextColor, long nCornerRadius, Color const * pPaintColor)
326 if (rRect.IsEmpty())
327 return;
329 bool bRoundEdges = nCornerRadius > 0;
331 const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
333 // colors used for item highlighting
334 Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
335 Color aSelectionFillColor(aSelectionBorderColor);
337 bool bDark = rStyles.GetFaceColor().IsDark();
338 bool bBright = ( rStyles.GetFaceColor() == COL_WHITE );
340 int c1 = aSelectionBorderColor.GetLuminance();
341 int c2 = rWindow.GetBackgroundColor().GetLuminance();
343 if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
345 // contrast too low
346 sal_uInt16 h, s, b;
347 aSelectionFillColor.RGBtoHSB( h, s, b );
348 if( b > 50 ) b -= 40;
349 else b += 40;
350 aSelectionFillColor = Color::HSBtoRGB( h, s, b );
351 aSelectionBorderColor = aSelectionFillColor;
354 if (bRoundEdges)
356 if (aSelectionBorderColor.IsDark())
357 aSelectionBorderColor.IncreaseLuminance(128);
358 else
359 aSelectionBorderColor.DecreaseLuminance(128);
362 tools::Rectangle aRect(rRect);
363 if (bDrawExtBorderOnly)
365 aRect.AdjustLeft( -1 );
366 aRect.AdjustTop( -1 );
367 aRect.AdjustRight(1 );
368 aRect.AdjustBottom(1 );
370 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
372 if (bDrawBorder)
373 rRenderContext.SetLineColor(bDark ? COL_WHITE : (bBright ? COL_BLACK : aSelectionBorderColor));
374 else
375 rRenderContext.SetLineColor();
377 sal_uInt16 nPercent = 0;
378 if (!nHighlight)
380 if (bDark)
381 aSelectionFillColor = COL_BLACK;
382 else
383 nPercent = 80; // just checked (light)
385 else
387 if (bChecked && nHighlight == 2)
389 if (bDark)
390 aSelectionFillColor = COL_LIGHTGRAY;
391 else if (bBright)
393 aSelectionFillColor = COL_BLACK;
394 rRenderContext.SetLineColor(COL_BLACK);
395 nPercent = 0;
397 else
398 nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
400 else if (bChecked || nHighlight == 1)
402 if (bDark)
403 aSelectionFillColor = COL_GRAY;
404 else if (bBright)
406 aSelectionFillColor = COL_BLACK;
407 rRenderContext.SetLineColor(COL_BLACK);
408 nPercent = 0;
410 else
411 nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
413 else
415 if (bDark)
416 aSelectionFillColor = COL_LIGHTGRAY;
417 else if (bBright)
419 aSelectionFillColor = COL_BLACK;
420 rRenderContext.SetLineColor(COL_BLACK);
421 if (nHighlight == 3)
422 nPercent = 80;
423 else
424 nPercent = 0;
426 else
427 nPercent = 70; // selected ( dark )
431 if (bDark && bDrawExtBorderOnly)
433 rRenderContext.SetFillColor();
434 if (pSelectionTextColor)
435 *pSelectionTextColor = rStyles.GetHighlightTextColor();
437 else
439 rRenderContext.SetFillColor(aSelectionFillColor);
440 if (pSelectionTextColor)
442 Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
443 Color aHLTextColor = rStyles.GetHighlightTextColor();
444 int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
445 int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
446 *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
450 if (bDark)
452 rRenderContext.DrawRect(aRect);
454 else
456 if (bRoundEdges)
458 tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
459 tools::PolyPolygon aPolyPoly(aPoly);
460 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
462 else
464 tools::Polygon aPoly(aRect);
465 tools::PolyPolygon aPolyPoly(aPoly);
466 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
470 rRenderContext.Pop(); // LINECOLOR | FILLCOLOR
473 void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
475 pHelper->SetPop();
477 if ( mpWindowImpl->mpCursor )
478 pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
480 mbInitClipRegion = true;
481 mpWindowImpl->mbInPaint = true;
483 // restore Paint-Region
484 vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
485 rPaintRegion = mpWindowImpl->maInvalidateRegion;
486 tools::Rectangle aPaintRect = rPaintRegion.GetBoundRect();
488 // RTL: re-mirror paint rect and region at this window
489 if (ImplIsAntiparallel())
491 rRenderContext.ReMirror(aPaintRect);
492 rRenderContext.ReMirror(rPaintRegion);
494 aPaintRect = ImplDevicePixelToLogic(aPaintRect);
495 mpWindowImpl->mpPaintRegion = &rPaintRegion;
496 mpWindowImpl->maInvalidateRegion.SetEmpty();
498 if ((pHelper->GetPaintFlags() & ImplPaintFlags::Erase) && rRenderContext.IsBackground())
500 if (rRenderContext.IsClipRegion())
502 vcl::Region aOldRegion = rRenderContext.GetClipRegion();
503 rRenderContext.SetClipRegion();
504 Erase(rRenderContext);
505 rRenderContext.SetClipRegion(aOldRegion);
507 else
508 Erase(rRenderContext);
511 // #98943# trigger drawing of toolbox selection after all children are painted
512 if (mpWindowImpl->mbDrawSelectionBackground)
513 pHelper->SetSelectionRect(aPaintRect);
514 pHelper->SetPaintRect(aPaintRect);
517 void Window::PopPaintHelper(PaintHelper const *pHelper)
519 if (mpWindowImpl->mpWinData)
521 if (mpWindowImpl->mbFocusVisible)
522 ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
524 mpWindowImpl->mbInPaint = false;
525 mbInitClipRegion = true;
526 mpWindowImpl->mpPaintRegion = nullptr;
527 if (mpWindowImpl->mpCursor)
528 mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
531 } /* namespace vcl */
533 PaintHelper::~PaintHelper()
535 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
536 if (m_bPop)
538 m_pWindow->PopPaintHelper(this);
541 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
542 if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
544 // Paint from the bottom child window and frontward.
545 vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
546 while (pTempWindow)
548 if (pTempWindow->mpWindowImpl->mbVisible)
549 pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
550 pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
554 if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
555 /* #98602# need to invert the tracking rect AFTER
556 * the children have painted
558 m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
560 // double-buffering: paint in case we created the buffer, the children are
561 // already painted inside
562 if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
564 PaintBuffer();
565 pFrameData->mbInBufferedPaint = false;
566 pFrameData->maBufferedRect = tools::Rectangle();
569 // #98943# draw toolbox selection
570 if( !m_aSelectionRect.IsEmpty() )
571 m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
574 namespace vcl {
576 void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
578 // call PrePaint. PrePaint may add to the invalidate region as well as
579 // other parameters used below.
580 PrePaint(*this);
582 mpWindowImpl->mbPaintFrame = false;
584 if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
585 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll);
586 if (nPaintFlags & ImplPaintFlags::PaintChildren)
587 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren;
588 if (nPaintFlags & ImplPaintFlags::Erase)
589 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
590 if (nPaintFlags & ImplPaintFlags::CheckRtl)
591 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
592 if (!mpWindowImpl->mpFirstChild)
593 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
595 if (mpWindowImpl->mbPaintDisabled)
597 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
598 Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
599 else if ( pRegion )
600 Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
602 // call PostPaint before returning
603 PostPaint(*this);
605 return;
608 nPaintFlags = mpWindowImpl->mnPaintFlags & ~ImplPaintFlags::Paint;
610 PaintHelper aHelper(this, nPaintFlags);
612 if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
613 aHelper.DoPaint(pRegion);
614 else
615 mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
617 // call PostPaint
618 PostPaint(*this);
621 void Window::ImplCallOverlapPaint()
623 // emit overlapping windows first
624 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
625 while ( pTempWindow )
627 if ( pTempWindow->mpWindowImpl->mbReallyVisible )
628 pTempWindow->ImplCallOverlapPaint();
629 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
632 // only then ourself
633 if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
635 // RTL: notify ImplCallPaint to check for re-mirroring
636 // because we were called from the Sal layer
637 ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
641 IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void)
643 comphelper::ProfileZone aZone("VCL idle re-paint");
645 // save paint events until layout is done
646 if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
648 mpWindowImpl->mpFrameData->maPaintIdle.Start();
649 return;
652 // save paint events until resizing or initial sizing done
653 if (mpWindowImpl->mbFrame &&
654 mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
656 mpWindowImpl->mpFrameData->maPaintIdle.Start();
658 else if ( mpWindowImpl->mbReallyVisible )
660 ImplCallOverlapPaint();
661 if (comphelper::LibreOfficeKit::isActive() &&
662 mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
663 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
667 IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void)
669 comphelper::ProfileZone aZone("VCL idle resize");
671 if( mpWindowImpl->mbReallyVisible )
673 ImplCallResize();
674 if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
676 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
677 mpWindowImpl->mpFrameData->maPaintIdle.Invoke( nullptr );
682 void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
684 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
685 if ( !ImplIsOverlapWindow() )
687 vcl::Window* pTempWindow = this;
688 ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE;
691 pTempWindow = pTempWindow->ImplGetParent();
692 if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren )
693 break;
694 pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint;
695 if( ! pTempWindow->IsPaintTransparent() )
696 nTranspPaint = ImplPaintFlags::NONE;
698 while ( !pTempWindow->ImplIsOverlapWindow() );
701 // set Paint-Flags
702 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint;
703 if ( nFlags & InvalidateFlags::Children )
704 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren;
705 if ( !(nFlags & InvalidateFlags::NoErase) )
706 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
708 if ( !pRegion )
709 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll;
710 else if ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
712 // if not everything has to be redrawn, add the region to it
713 mpWindowImpl->maInvalidateRegion.Union( *pRegion );
716 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
717 if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
718 && ImplGetParent() )
720 vcl::Window *pParent = ImplGetParent();
721 while( pParent && pParent->IsPaintTransparent() )
722 pParent = pParent->ImplGetParent();
723 if( pParent )
725 vcl::Region *pChildRegion;
726 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
727 // invalidate the whole child window region in the parent
728 pChildRegion = ImplGetWinChildClipRegion();
729 else
730 // invalidate the same region in the parent that has to be repainted in the child
731 pChildRegion = &mpWindowImpl->maInvalidateRegion;
733 nFlags |= InvalidateFlags::Children; // paint should also be done on all children
734 nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
735 pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
739 if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
740 mpWindowImpl->mpFrameData->maPaintIdle.Start();
743 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
745 vcl::Region aRegion = rRegion;
747 ImplClipBoundaries( aRegion, true, true );
748 if ( !aRegion.IsEmpty() )
749 ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
751 // now we invalidate the overlapping windows
752 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
753 while ( pTempWindow )
755 if ( pTempWindow->IsVisible() )
756 pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
758 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
762 void Window::ImplInvalidateParentFrameRegion( vcl::Region& rRegion )
764 if ( mpWindowImpl->mbOverlapWin )
765 mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
766 else
768 if( ImplGetParent() )
769 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
773 void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
775 // check what has to be redrawn
776 bool bInvalidateAll = !pRegion;
778 // take Transparent-Invalidate into account
779 vcl::Window* pOpaqueWindow = this;
780 if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
782 vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
783 while ( pTempWindow )
785 if ( !pTempWindow->IsPaintTransparent() )
787 pOpaqueWindow = pTempWindow;
788 nFlags |= InvalidateFlags::Children;
789 bInvalidateAll = false;
790 break;
793 if ( pTempWindow->ImplIsOverlapWindow() )
794 break;
796 pTempWindow = pTempWindow->ImplGetParent();
800 // assemble region
801 InvalidateFlags nOrgFlags = nFlags;
802 if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
804 if ( GetStyle() & WB_CLIPCHILDREN )
805 nFlags |= InvalidateFlags::NoChildren;
806 else
807 nFlags |= InvalidateFlags::Children;
809 if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
810 bInvalidateAll = false;
811 if ( bInvalidateAll )
812 ImplInvalidateFrameRegion( nullptr, nFlags );
813 else
815 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
816 vcl::Region aRegion( aRect );
817 if ( pRegion )
819 // RTL: remirror region before intersecting it
820 if ( ImplIsAntiparallel() )
822 const OutputDevice *pOutDev = GetOutDev();
824 vcl::Region aRgn( *pRegion );
825 pOutDev->ReMirror( aRgn );
826 aRegion.Intersect( aRgn );
828 else
829 aRegion.Intersect( *pRegion );
831 ImplClipBoundaries( aRegion, true, true );
832 if ( nFlags & InvalidateFlags::NoChildren )
834 nFlags &= ~InvalidateFlags::Children;
835 if ( !(nFlags & InvalidateFlags::NoClipChildren) )
837 if ( nOrgFlags & InvalidateFlags::NoChildren )
838 ImplClipAllChildren( aRegion );
839 else
841 if ( ImplClipChildren( aRegion ) )
842 nFlags |= InvalidateFlags::Children;
846 if ( !aRegion.IsEmpty() )
847 ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
850 if ( nFlags & InvalidateFlags::Update )
851 pOpaqueWindow->Update(); // start painting at the opaque parent
854 void Window::ImplMoveInvalidateRegion( const tools::Rectangle& rRect,
855 long nHorzScroll, long nVertScroll,
856 bool bChildren )
858 if ( (mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintAll)) == ImplPaintFlags::Paint )
860 vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
861 aTempRegion.Intersect( rRect );
862 aTempRegion.Move( nHorzScroll, nVertScroll );
863 mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
866 if ( bChildren && (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren) )
868 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
869 while ( pWindow )
871 pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
872 pWindow = pWindow->mpWindowImpl->mpNext;
877 void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
878 long nHorzScroll, long nVertScroll,
879 bool bChildren )
881 // also shift Paint-Region when paints need processing
882 ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
883 // Paint-Region should be shifted, as drawn by the parents
884 if ( !ImplIsOverlapWindow() )
886 vcl::Region aPaintAllRegion;
887 vcl::Window* pPaintAllWindow = this;
890 pPaintAllWindow = pPaintAllWindow->ImplGetParent();
891 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
893 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
895 aPaintAllRegion.SetEmpty();
896 break;
898 else
899 aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
902 while ( !pPaintAllWindow->ImplIsOverlapWindow() );
903 if ( !aPaintAllRegion.IsEmpty() )
905 aPaintAllRegion.Move( nHorzScroll, nVertScroll );
906 InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
907 if ( bChildren )
908 nPaintFlags |= InvalidateFlags::Children;
909 ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
914 void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
916 if ( !pRegion )
917 mpWindowImpl->maInvalidateRegion.SetEmpty();
918 else
920 // when all child windows have to be drawn we need to invalidate them before doing so
921 if ( (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren) && mpWindowImpl->mpFirstChild )
923 vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
924 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
926 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
927 aChildRegion = aRect;
929 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
930 while ( pChild )
932 pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
933 pChild = pChild->mpWindowImpl->mpNext;
936 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
938 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
939 mpWindowImpl->maInvalidateRegion = aRect;
941 mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
943 mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAll;
945 if ( nFlags & ValidateFlags::Children )
947 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
948 while ( pChild )
950 pChild->ImplValidateFrameRegion( pRegion, nFlags );
951 pChild = pChild->mpWindowImpl->mpNext;
956 void Window::ImplValidate()
958 // assemble region
959 bool bValidateAll = true;
960 ValidateFlags nFlags = ValidateFlags::NONE;
961 if ( GetStyle() & WB_CLIPCHILDREN )
962 nFlags |= ValidateFlags::NoChildren;
963 else
964 nFlags |= ValidateFlags::Children;
965 if ( (nFlags & ValidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
966 bValidateAll = false;
967 if ( bValidateAll )
968 ImplValidateFrameRegion( nullptr, nFlags );
969 else
971 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
972 vcl::Region aRegion( aRect );
973 ImplClipBoundaries( aRegion, true, true );
974 if ( nFlags & ValidateFlags::NoChildren )
976 nFlags &= ~ValidateFlags::Children;
977 if ( ImplClipChildren( aRegion ) )
978 nFlags |= ValidateFlags::Children;
980 if ( !aRegion.IsEmpty() )
981 ImplValidateFrameRegion( &aRegion, nFlags );
985 void Window::ImplUpdateAll()
987 if ( !mpWindowImpl->mbReallyVisible )
988 return;
990 bool bFlush = false;
991 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
993 Point aPoint( 0, 0 );
994 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
995 ImplInvalidateOverlapFrameRegion( aRegion );
996 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
997 bFlush = true;
1000 // an update changes the OverlapWindow, such that for later paints
1001 // not too much has to be drawn, if ALLCHILDREN etc. is set
1002 vcl::Window* pWindow = ImplGetFirstOverlapWindow();
1003 pWindow->ImplCallOverlapPaint();
1005 if ( bFlush )
1006 Flush();
1009 void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1013 void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1017 void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect)
1019 CallEventListeners(VclEventId::WindowPaint, const_cast<tools::Rectangle *>(&rRect));
1022 void Window::SetPaintTransparent( bool bTransparent )
1024 // transparency is not useful for frames as the background would have to be provided by a different frame
1025 if( bTransparent && mpWindowImpl->mbFrame )
1026 return;
1028 if ( mpWindowImpl->mpBorderWindow )
1029 mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1031 mpWindowImpl->mbPaintTransparent = bTransparent;
1034 void Window::SetWindowRegionPixel()
1037 if ( mpWindowImpl->mpBorderWindow )
1038 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1039 else if( mpWindowImpl->mbFrame )
1041 mpWindowImpl->maWinRegion = vcl::Region(true);
1042 mpWindowImpl->mbWinRegion = false;
1043 mpWindowImpl->mpFrame->ResetClipRegion();
1045 else
1047 if ( mpWindowImpl->mbWinRegion )
1049 mpWindowImpl->maWinRegion = vcl::Region(true);
1050 mpWindowImpl->mbWinRegion = false;
1051 ImplSetClipFlag();
1053 if ( IsReallyVisible() )
1055 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1056 vcl::Region aRegion( aRect );
1057 ImplInvalidateParentFrameRegion( aRegion );
1063 void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1066 if ( mpWindowImpl->mpBorderWindow )
1067 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1068 else if( mpWindowImpl->mbFrame )
1070 if( !rRegion.IsNull() )
1072 mpWindowImpl->maWinRegion = rRegion;
1073 mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1075 if( mpWindowImpl->mbWinRegion )
1077 // set/update ClipRegion
1078 RectangleVector aRectangles;
1079 mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1080 mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1082 for (auto const& rectangle : aRectangles)
1084 mpWindowImpl->mpFrame->UnionClipRegion(
1085 rectangle.Left(),
1086 rectangle.Top(),
1087 rectangle.GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1088 rectangle.GetHeight()); // same for height
1091 mpWindowImpl->mpFrame->EndSetClipRegion();
1093 //long nX;
1094 //long nY;
1095 //long nWidth;
1096 //long nHeight;
1097 //sal_uLong nRectCount;
1098 //ImplRegionInfo aInfo;
1099 //sal_Bool bRegionRect;
1101 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1102 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1103 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1104 //while ( bRegionRect )
1106 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1107 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1109 //mpWindowImpl->mpFrame->EndSetClipRegion();
1111 else
1112 SetWindowRegionPixel();
1114 else
1115 SetWindowRegionPixel();
1117 else
1119 if ( rRegion.IsNull() )
1121 if ( mpWindowImpl->mbWinRegion )
1123 mpWindowImpl->maWinRegion = vcl::Region(true);
1124 mpWindowImpl->mbWinRegion = false;
1125 ImplSetClipFlag();
1128 else
1130 mpWindowImpl->maWinRegion = rRegion;
1131 mpWindowImpl->mbWinRegion = true;
1132 ImplSetClipFlag();
1135 if ( IsReallyVisible() )
1137 tools::Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1138 vcl::Region aRegion( aRect );
1139 ImplInvalidateParentFrameRegion( aRegion );
1144 vcl::Region Window::GetPaintRegion() const
1147 if ( mpWindowImpl->mpPaintRegion )
1149 vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1150 aRegion.Move( -mnOutOffX, -mnOutOffY );
1151 return PixelToLogic( aRegion );
1153 else
1155 vcl::Region aPaintRegion(true);
1156 return aPaintRegion;
1160 void Window::Invalidate( InvalidateFlags nFlags )
1162 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1163 return;
1165 ImplInvalidate( nullptr, nFlags );
1166 LogicInvalidate(nullptr);
1169 void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1171 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1172 return;
1174 OutputDevice *pOutDev = GetOutDev();
1175 tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1176 if ( !aRect.IsEmpty() )
1178 vcl::Region aRegion( aRect );
1179 ImplInvalidate( &aRegion, nFlags );
1180 tools::Rectangle aLogicRectangle(rRect);
1181 LogicInvalidate(&aLogicRectangle);
1185 void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1187 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1188 return;
1190 if ( rRegion.IsNull() )
1192 ImplInvalidate( nullptr, nFlags );
1193 LogicInvalidate(nullptr);
1195 else
1197 vcl::Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1198 if ( !aRegion.IsEmpty() )
1200 ImplInvalidate( &aRegion, nFlags );
1201 tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1202 LogicInvalidate(&aLogicRectangle);
1207 void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1209 if(pRectangle)
1211 tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1212 PixelInvalidate(&aRect);
1214 else
1215 PixelInvalidate(nullptr);
1218 void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1220 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1221 return;
1223 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1225 // In case we are routing the window, notify the client
1226 std::vector<vcl::LOKPayloadItem> aPayload;
1227 if (pRectangle)
1228 aPayload.push_back(std::make_pair(OString("rectangle"), pRectangle->toString()));
1229 else
1231 const tools::Rectangle aRect(Point(0, 0), GetSizePixel());
1232 aPayload.push_back(std::make_pair(OString("rectangle"), aRect.toString()));
1235 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
1237 // Added for dialog items. Pass invalidation to the parent window.
1238 else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1240 const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1241 pParent->PixelInvalidate(&aRect);
1245 void Window::Validate()
1247 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1248 return;
1250 ImplValidate();
1253 bool Window::HasPaintEvent() const
1256 if ( !mpWindowImpl->mbReallyVisible )
1257 return false;
1259 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1260 return true;
1262 if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1263 return true;
1265 if ( !ImplIsOverlapWindow() )
1267 const vcl::Window* pTempWindow = this;
1270 pTempWindow = pTempWindow->ImplGetParent();
1271 if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1272 return true;
1274 while ( !pTempWindow->ImplIsOverlapWindow() );
1277 return false;
1280 void Window::Update()
1282 if ( mpWindowImpl->mpBorderWindow )
1284 mpWindowImpl->mpBorderWindow->Update();
1285 return;
1288 if ( !mpWindowImpl->mbReallyVisible )
1289 return;
1291 bool bFlush = false;
1292 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1294 Point aPoint( 0, 0 );
1295 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1296 ImplInvalidateOverlapFrameRegion( aRegion );
1297 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1298 bFlush = true;
1301 // First we should skip all windows which are Paint-Transparent
1302 vcl::Window* pUpdateWindow = this;
1303 vcl::Window* pWindow = pUpdateWindow;
1304 while ( !pWindow->ImplIsOverlapWindow() )
1306 if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1308 pUpdateWindow = pWindow;
1309 break;
1311 pWindow = pWindow->ImplGetParent();
1313 // In order to limit drawing, an update only draws the window which
1314 // has PAINTALLCHILDREN set
1315 pWindow = pUpdateWindow;
1318 if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
1319 pUpdateWindow = pWindow;
1320 if ( pWindow->ImplIsOverlapWindow() )
1321 break;
1322 pWindow = pWindow->ImplGetParent();
1324 while ( pWindow );
1326 // if there is something to paint, trigger a Paint
1327 if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
1329 VclPtr<vcl::Window> xWindow(this);
1331 // trigger an update also for system windows on top of us,
1332 // otherwise holes would remain
1333 vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap;
1334 while ( pUpdateOverlapWindow )
1336 pUpdateOverlapWindow->Update();
1337 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1340 pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1342 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1343 pUpdateWindow->LogicInvalidate(nullptr);
1345 if (xWindow->IsDisposed())
1346 return;
1348 bFlush = true;
1351 if ( bFlush )
1352 Flush();
1355 void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1357 // Special drawing when called through LOKit
1358 // TODO: Move to its own method
1359 if (comphelper::LibreOfficeKit::isActive())
1361 VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1363 Size aSize(GetOutputSizePixel());
1364 pDevice->SetOutputSizePixel(aSize);
1366 vcl::Font aCopyFont = GetFont();
1367 pDevice->SetFont(aCopyFont);
1369 pDevice->SetTextColor(GetTextColor());
1370 if (IsLineColor())
1371 pDevice->SetLineColor(GetLineColor());
1372 else
1373 pDevice->SetLineColor();
1375 if (IsFillColor())
1376 pDevice->SetFillColor(GetFillColor());
1377 else
1378 pDevice->SetFillColor();
1380 if (IsTextLineColor())
1381 pDevice->SetTextLineColor(GetTextLineColor());
1382 else
1383 pDevice->SetTextLineColor();
1385 if (IsOverlineColor())
1386 pDevice->SetOverlineColor(GetOverlineColor());
1387 else
1388 pDevice->SetOverlineColor();
1390 if (IsTextFillColor())
1391 pDevice->SetTextFillColor(GetTextFillColor());
1392 else
1393 pDevice->SetTextFillColor();
1395 pDevice->SetTextAlign(GetTextAlign());
1396 pDevice->SetRasterOp(GetRasterOp());
1398 tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1400 vcl::Region aClipRegion(GetClipRegion());
1401 pDevice->SetClipRegion();
1402 aClipRegion.Intersect(aPaintRect);
1403 pDevice->SetClipRegion(aClipRegion);
1405 if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1406 Erase(*pDevice);
1408 pDevice->SetMapMode(GetMapMode());
1410 Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1412 i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1414 // get rid of virtual device now so they don't pile up during recursive calls
1415 pDevice.disposeAndClear();
1418 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1420 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1422 long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1423 long nDeltaY = pChild->mnOutOffY - mnOutOffY;
1425 Point aPos( i_rPos );
1426 aPos += Point(nDeltaX, nDeltaY);
1428 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1431 return;
1435 bool bRVisible = mpWindowImpl->mbReallyVisible;
1436 mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1437 bool bDevOutput = mbDevOutput;
1438 mbDevOutput = true;
1440 const OutputDevice *pOutDev = GetOutDev();
1441 long nOldDPIX = pOutDev->GetDPIX();
1442 long nOldDPIY = pOutDev->GetDPIY();
1443 mnDPIX = i_pTargetOutDev->GetDPIX();
1444 mnDPIY = i_pTargetOutDev->GetDPIY();
1445 bool bOutput = IsOutputEnabled();
1446 EnableOutput();
1448 double fScaleX = 1;
1449 double fScaleY = 1;
1450 bool bNeedsScaling = false;
1451 if(comphelper::LibreOfficeKit::isActive())
1453 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel &&
1454 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1455 // For these preview we don't need to scale even though the unit is not pixel.
1456 GetMapMode().GetMapUnit() != MapUnit::Map100thMM)
1458 bNeedsScaling = true;
1459 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1460 Size aLogicSize = PixelToLogic(Size(1000.0, 1000.0));
1461 fScaleX = aLogicSize.Width() / 1000.0;
1462 fScaleY = aLogicSize.Height() / 1000.0;
1465 else
1466 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1467 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1468 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1469 return;
1472 // preserve graphicsstate
1473 Push();
1474 vcl::Region aClipRegion( GetClipRegion() );
1475 SetClipRegion();
1477 GDIMetaFile* pOldMtf = GetConnectMetaFile();
1478 GDIMetaFile aMtf;
1479 SetConnectMetaFile( &aMtf );
1481 // put a push action to metafile
1482 Push();
1483 // copy graphics state to metafile
1484 vcl::Font aCopyFont = GetFont();
1485 if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY )
1487 aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * mnDPIY / nOldDPIY );
1488 aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * mnDPIX / nOldDPIX );
1490 SetFont( aCopyFont );
1491 SetTextColor( GetTextColor() );
1492 if( IsLineColor() )
1493 SetLineColor( GetLineColor() );
1494 else
1495 SetLineColor();
1496 if( IsFillColor() )
1497 SetFillColor( GetFillColor() );
1498 else
1499 SetFillColor();
1500 if( IsTextLineColor() )
1501 SetTextLineColor( GetTextLineColor() );
1502 else
1503 SetTextLineColor();
1504 if( IsOverlineColor() )
1505 SetOverlineColor( GetOverlineColor() );
1506 else
1507 SetOverlineColor();
1508 if( IsTextFillColor() )
1509 SetTextFillColor( GetTextFillColor() );
1510 else
1511 SetTextFillColor();
1512 SetTextAlign( GetTextAlign() );
1513 SetRasterOp( GetRasterOp() );
1514 if( IsRefPoint() )
1515 SetRefPoint( GetRefPoint() );
1516 else
1517 SetRefPoint();
1518 SetLayoutMode( GetLayoutMode() );
1519 SetDigitLanguage( GetDigitLanguage() );
1521 tools::Rectangle aPaintRect;
1522 if(bNeedsScaling)
1524 aPaintRect = tools::Rectangle( Point( 0, 0 ),
1525 Size(GetOutputSizePixel().Width() * fScaleX, GetOutputSizePixel().Height() * fScaleY) );
1527 else
1529 aPaintRect = tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1531 aClipRegion.Intersect( aPaintRect );
1532 SetClipRegion( aClipRegion );
1534 // do the actual paint
1536 // background
1537 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1539 Erase(*this);
1540 if(bNeedsScaling)
1541 aMtf.Scale(fScaleX, fScaleY);
1543 // foreground
1544 Paint(*this, aPaintRect);
1545 // put a pop action to metafile
1546 Pop();
1548 SetConnectMetaFile( pOldMtf );
1549 EnableOutput( bOutput );
1550 mpWindowImpl->mbReallyVisible = bRVisible;
1552 // paint metafile to VDev
1553 VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1554 DeviceFormat::DEFAULT,
1555 DeviceFormat::DEFAULT);
1557 if(bNeedsScaling)
1558 pMaskedDevice->SetMapMode( GetMapMode() );
1559 pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() );
1560 pMaskedDevice->EnableRTL( IsRTLEnabled() );
1561 aMtf.WindStart();
1562 aMtf.Play( pMaskedDevice );
1563 BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), aPaintRect.GetSize() ) );
1564 i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
1565 // get rid of virtual device now so they don't pile up during recursive calls
1566 pMaskedDevice.disposeAndClear();
1568 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1570 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1572 long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1574 if( pOutDev->HasMirroredGraphics() )
1575 nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth;
1576 long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1577 Point aPos( i_rPos );
1578 Point aDelta( nDeltaX, nDeltaY );
1579 aPos += aDelta;
1580 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1584 // restore graphics state
1585 Pop();
1587 EnableOutput( bOutput );
1588 mpWindowImpl->mbReallyVisible = bRVisible;
1589 mbDevOutput = bDevOutput;
1590 mnDPIX = nOldDPIX;
1591 mnDPIY = nOldDPIY;
1594 void Window::PaintToDevice( OutputDevice* pDev, const Point& rPos, const Size& /*rSize*/ )
1596 SAL_WARN_IF( pDev->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1597 SAL_WARN_IF( pDev->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1599 vcl::Window* pRealParent = nullptr;
1600 if( ! mpWindowImpl->mbVisible )
1602 vcl::Window* pTempParent = ImplGetDefaultWindow();
1603 pTempParent->EnableChildTransparentMode();
1604 pRealParent = GetParent();
1605 SetParent( pTempParent );
1606 // trigger correct visibility flags for children
1607 Show();
1608 Hide();
1611 bool bVisible = mpWindowImpl->mbVisible;
1612 mpWindowImpl->mbVisible = true;
1614 if( mpWindowImpl->mpBorderWindow )
1615 mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1616 else
1617 ImplPaintToDevice( pDev, rPos );
1619 mpWindowImpl->mbVisible = bVisible;
1621 if( pRealParent )
1622 SetParent( pRealParent );
1625 void Window::Erase(vcl::RenderContext& rRenderContext)
1627 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1628 return;
1630 bool bNativeOK = false;
1632 ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1633 if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1635 tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1636 ControlState nState = ControlState::NONE;
1638 if (IsEnabled())
1639 nState |= ControlState::ENABLED;
1641 bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1642 nState, ImplControlValue(), OUString());
1645 if (mbBackground && !bNativeOK)
1647 RasterOp eRasterOp = GetRasterOp();
1648 if (eRasterOp != RasterOp::OverPaint)
1649 SetRasterOp(RasterOp::OverPaint);
1650 rRenderContext.DrawWallpaper(0, 0, mnOutWidth, mnOutHeight, maBackground);
1651 if (eRasterOp != RasterOp::OverPaint)
1652 rRenderContext.SetRasterOp(eRasterOp);
1655 if (mpAlphaVDev)
1656 mpAlphaVDev->Erase();
1659 void Window::ImplScroll( const tools::Rectangle& rRect,
1660 long nHorzScroll, long nVertScroll, ScrollFlags nFlags )
1662 if ( !IsDeviceOutputNecessary() )
1663 return;
1665 nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll );
1666 nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll );
1668 if ( !nHorzScroll && !nVertScroll )
1669 return;
1671 if ( mpWindowImpl->mpCursor )
1672 mpWindowImpl->mpCursor->ImplSuspend();
1674 ScrollFlags nOrgFlags = nFlags;
1675 if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1677 if ( GetStyle() & WB_CLIPCHILDREN )
1678 nFlags |= ScrollFlags::NoChildren;
1679 else
1680 nFlags |= ScrollFlags::Children;
1683 vcl::Region aInvalidateRegion;
1684 bool bScrollChildren(nFlags & ScrollFlags::Children);
1686 if ( !mpWindowImpl->mpFirstChild )
1687 bScrollChildren = false;
1689 OutputDevice *pOutDev = GetOutDev();
1691 // RTL: check if this window requires special action
1692 bool bReMirror = ImplIsAntiparallel();
1694 tools::Rectangle aRectMirror( rRect );
1695 if( bReMirror )
1697 // make sure the invalidate region of this window is
1698 // computed in the same coordinate space as the one from the overlap windows
1699 pOutDev->ReMirror( aRectMirror );
1702 // adapt paint areas
1703 ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1705 ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1707 // if the scrolling on the device is performed in the opposite direction
1708 // then move the overlaps in that direction to compute the invalidate region
1709 // on the correct side, i.e., revert nHorzScroll
1710 if (!aInvalidateRegion.IsEmpty())
1712 aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1715 tools::Rectangle aDestRect(aRectMirror);
1716 aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1717 vcl::Region aWinInvalidateRegion(aRectMirror);
1718 if (!SupportsDoubleBuffering())
1720 // There will be no CopyArea() call below, so invalidate the
1721 // whole visible area, not only the smaller one that was just
1722 // scrolled in.
1723 aWinInvalidateRegion.Exclude(aDestRect);
1726 aInvalidateRegion.Union(aWinInvalidateRegion);
1728 Point aPoint( mnOutOffX, mnOutOffY );
1729 vcl::Region aRegion( tools::Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1730 if ( nFlags & ScrollFlags::Clip )
1731 aRegion.Intersect( rRect );
1732 if ( mpWindowImpl->mbWinRegion )
1733 aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1735 aRegion.Exclude( aInvalidateRegion );
1737 ImplClipBoundaries( aRegion, false, true );
1738 if ( !bScrollChildren )
1740 if ( nOrgFlags & ScrollFlags::NoChildren )
1741 ImplClipAllChildren( aRegion );
1742 else
1743 ImplClipChildren( aRegion );
1745 if ( mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1746 aRegion.Intersect( maRegion );
1747 if ( !aRegion.IsEmpty() )
1749 if ( mpWindowImpl->mpWinData )
1751 if ( mpWindowImpl->mbFocusVisible )
1752 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1753 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1754 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1756 #ifndef IOS
1757 // This seems completely unnecessary with tiled rendering, and
1758 // causes the "AquaSalGraphics::copyArea() for non-layered
1759 // graphics" message. Presumably we should bypass this on all
1760 // platforms when dealing with a "window" that uses tiled
1761 // rendering at the moment. Unclear how to figure that out,
1762 // though. Also unclear whether we actually could just not
1763 // create a "frame window", whatever that exactly is, in the
1764 // tiled rendering case, or at least for platforms where tiles
1765 // rendering is all there is.
1767 SalGraphics* pGraphics = ImplGetFrameGraphics();
1768 // The invalidation area contains the area what would be copied here,
1769 // so avoid copying in case of double buffering.
1770 if (pGraphics && !SupportsDoubleBuffering())
1772 if( bReMirror )
1774 pOutDev->ReMirror( aRegion );
1777 pOutDev->SelectClipRegion( aRegion, pGraphics );
1778 pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1779 rRect.Left(), rRect.Top(),
1780 rRect.GetWidth(), rRect.GetHeight(),
1781 this );
1783 #endif
1784 if ( mpWindowImpl->mpWinData )
1786 if ( mpWindowImpl->mbFocusVisible )
1787 ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1788 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1789 InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1793 if ( !aInvalidateRegion.IsEmpty() )
1795 // RTL: the invalidate region for this windows is already computed in frame coordinates
1796 // so it has to be re-mirrored before calling the Paint-handler
1797 mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
1799 if ( !bScrollChildren )
1801 if ( nOrgFlags & ScrollFlags::NoChildren )
1802 ImplClipAllChildren( aInvalidateRegion );
1803 else
1804 ImplClipChildren( aInvalidateRegion );
1806 ImplInvalidateFrameRegion( &aInvalidateRegion, InvalidateFlags::Children );
1809 if ( bScrollChildren )
1811 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1812 while ( pWindow )
1814 Point aPos = pWindow->GetPosPixel();
1815 aPos += Point( nHorzScroll, nVertScroll );
1816 pWindow->SetPosPixel( aPos );
1818 pWindow = pWindow->mpWindowImpl->mpNext;
1822 if ( nFlags & ScrollFlags::Update )
1823 Update();
1825 if ( mpWindowImpl->mpCursor )
1826 mpWindowImpl->mpCursor->ImplResume();
1829 } /* namespace vcl */
1832 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */