build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / window / paint.cxx
blobe289f68a1a57a3e223ee61ddce917d9334c57a12
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>
22 #include <vcl/window.hxx>
23 #include <vcl/dialog.hxx>
24 #include <vcl/virdev.hxx>
25 #include <vcl/cursor.hxx>
26 #include <vcl/settings.hxx>
28 #include <sal/types.h>
30 #include <window.h>
31 #include <salgdi.hxx>
32 #include <salframe.hxx>
33 #include <svdata.hxx>
34 #include <comphelper/lok.hxx>
35 #if HAVE_FEATURE_OPENGL
36 #include <vcl/opengl/OpenGLHelper.hxx>
37 #endif
39 #define IMPL_PAINT_PAINT ((sal_uInt16)0x0001)
40 #define IMPL_PAINT_PAINTALL ((sal_uInt16)0x0002)
41 #define IMPL_PAINT_PAINTALLCHILDREN ((sal_uInt16)0x0004)
42 #define IMPL_PAINT_PAINTCHILDREN ((sal_uInt16)0x0008)
43 #define IMPL_PAINT_ERASE ((sal_uInt16)0x0010)
44 #define IMPL_PAINT_CHECKRTL ((sal_uInt16)0x0020)
46 // PaintBufferGuard
48 PaintBufferGuard::PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
49 : mpFrameData(pFrameData),
50 m_pWindow(pWindow),
51 mbBackground(false),
52 mnOutOffX(0),
53 mnOutOffY(0)
55 if (!pFrameData->mpBuffer)
56 return;
58 // transfer various settings
59 // FIXME: this must disappear as we move to RenderContext only,
60 // the painting must become state-less, so that no actual
61 // vcl::Window setting affects this
62 mbBackground = pFrameData->mpBuffer->IsBackground();
63 if (pWindow->IsBackground())
65 maBackground = pFrameData->mpBuffer->GetBackground();
66 pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
68 //else
69 //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
71 PushFlags nFlags = PushFlags::NONE;
72 nFlags |= PushFlags::CLIPREGION;
73 nFlags |= PushFlags::FILLCOLOR;
74 nFlags |= PushFlags::FONT;
75 nFlags |= PushFlags::LINECOLOR;
76 nFlags |= PushFlags::MAPMODE;
77 maSettings = pFrameData->mpBuffer->GetSettings();
78 nFlags |= PushFlags::REFPOINT;
79 nFlags |= PushFlags::TEXTCOLOR;
80 nFlags |= PushFlags::TEXTLINECOLOR;
81 nFlags |= PushFlags::OVERLINECOLOR;
82 nFlags |= PushFlags::TEXTFILLCOLOR;
83 nFlags |= PushFlags::TEXTALIGN;
84 nFlags |= PushFlags::RASTEROP;
85 nFlags |= PushFlags::TEXTLAYOUTMODE;
86 nFlags |= PushFlags::TEXTLANGUAGE;
87 pFrameData->mpBuffer->Push(nFlags);
88 pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());
89 pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());
90 pFrameData->mpBuffer->SetFont(pWindow->GetFont());
91 pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());
92 pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
93 pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());
94 pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
95 pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
96 pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
97 pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
98 pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
99 pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
100 pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());
101 pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());
102 pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());
104 mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
105 mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
106 pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
107 pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
110 PaintBufferGuard::~PaintBufferGuard()
112 if (!mpFrameData->mpBuffer)
113 return;
115 if (!m_aPaintRect.IsEmpty())
117 // copy the buffer content to the actual window
118 // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
119 // painting directly instead of using Invalidate()
120 // [ie. everything you can see was painted directly to the
121 // window either above or in eg. an event handler]
122 if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
124 // Make sure that the +1 value GetSize() adds to the size is in pixels.
125 Size aPaintRectSize;
126 if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
128 aPaintRectSize = m_aPaintRect.GetSize();
130 else
132 Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
133 aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
136 m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer.get());
140 // Restore buffer state.
141 mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
142 mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
144 mpFrameData->mpBuffer->Pop();
145 mpFrameData->mpBuffer->SetSettings(maSettings);
146 if (mbBackground)
147 mpFrameData->mpBuffer->SetBackground(maBackground);
148 else
149 mpFrameData->mpBuffer->SetBackground();
152 void PaintBufferGuard::SetPaintRect(const Rectangle& rRectangle)
154 m_aPaintRect = rRectangle;
157 vcl::RenderContext* PaintBufferGuard::GetRenderContext()
159 if (mpFrameData->mpBuffer)
160 return mpFrameData->mpBuffer;
161 else
162 return m_pWindow;
165 class PaintHelper
167 private:
168 VclPtr<vcl::Window> m_pWindow;
169 vcl::Region* m_pChildRegion;
170 Rectangle m_aSelectionRect;
171 Rectangle m_aPaintRect;
172 vcl::Region m_aPaintRegion;
173 sal_uInt16 m_nPaintFlags;
174 bool m_bPop : 1;
175 bool m_bRestoreCursor : 1;
176 bool m_bStartedBufferedPaint : 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
177 public:
178 PaintHelper(vcl::Window* pWindow, sal_uInt16 nPaintFlags);
179 void SetPop()
181 m_bPop = true;
183 void SetPaintRect(const Rectangle& rRect)
185 m_aPaintRect = rRect;
187 void SetSelectionRect(const Rectangle& rRect)
189 m_aSelectionRect = rRect;
191 void SetRestoreCursor(bool bRestoreCursor)
193 m_bRestoreCursor = bRestoreCursor;
195 bool GetRestoreCursor() const
197 return m_bRestoreCursor;
199 sal_uInt16 GetPaintFlags() const
201 return m_nPaintFlags;
203 vcl::Region& GetPaintRegion()
205 return m_aPaintRegion;
207 void DoPaint(const vcl::Region* pRegion);
209 /// Start buffered paint: set it up to have the same settings as m_pWindow.
210 void StartBufferedPaint();
212 /// Paint the content of the buffer to the current m_pWindow.
213 void PaintBuffer();
215 ~PaintHelper();
218 PaintHelper::PaintHelper(vcl::Window *pWindow, sal_uInt16 nPaintFlags)
219 : m_pWindow(pWindow)
220 , m_pChildRegion(nullptr)
221 , m_nPaintFlags(nPaintFlags)
222 , m_bPop(false)
223 , m_bRestoreCursor(false)
224 , m_bStartedBufferedPaint(false)
228 void PaintHelper::StartBufferedPaint()
230 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
231 assert(!pFrameData->mbInBufferedPaint);
233 pFrameData->mbInBufferedPaint = true;
234 pFrameData->maBufferedRect = Rectangle();
235 m_bStartedBufferedPaint = true;
238 void PaintHelper::PaintBuffer()
240 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
241 assert(pFrameData->mbInBufferedPaint);
242 assert(m_bStartedBufferedPaint);
244 PaintBufferGuard aGuard(pFrameData, m_pWindow);
245 aGuard.SetPaintRect(pFrameData->maBufferedRect);
248 void PaintHelper::DoPaint(const vcl::Region* pRegion)
250 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
252 vcl::Region* pWinChildClipRegion = m_pWindow->ImplGetWinChildClipRegion();
253 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
254 if (pWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL || pFrameData->mbInBufferedPaint)
256 pWindowImpl->maInvalidateRegion = *pWinChildClipRegion;
258 else
260 if (pRegion)
261 pWindowImpl->maInvalidateRegion.Union( *pRegion );
263 if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible)
264 /* #98602# need to repaint all children within the
265 * tracking rectangle, so the following invert
266 * operation takes places without traces of the previous
267 * one.
269 pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
271 if (pWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDREN)
272 m_pChildRegion = new vcl::Region(pWindowImpl->maInvalidateRegion);
273 pWindowImpl->maInvalidateRegion.Intersect(*pWinChildClipRegion);
275 pWindowImpl->mnPaintFlags = 0;
276 if (!pWindowImpl->maInvalidateRegion.IsEmpty())
278 #if HAVE_FEATURE_OPENGL
279 VCL_GL_INFO("PaintHelper::DoPaint on " <<
280 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
281 #endif
282 // double-buffering: setup the buffer if it does not exist
283 if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
284 StartBufferedPaint();
286 // double-buffering: if this window does not support double-buffering,
287 // but we are in the middle of double-buffered paint, we might be
288 // losing information
289 if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
290 SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
292 if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
294 // double-buffering
295 PaintBufferGuard g(pFrameData, m_pWindow);
296 m_pWindow->ApplySettings(*pFrameData->mpBuffer.get());
298 m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer.get());
299 m_pWindow->Paint(*pFrameData->mpBuffer.get(), m_aPaintRect);
300 pFrameData->maBufferedRect.Union(m_aPaintRect);
302 else
304 // direct painting
305 m_pWindow->ApplySettings(*m_pWindow);
306 m_pWindow->PushPaintHelper(this, *m_pWindow);
307 m_pWindow->Paint(*m_pWindow, m_aPaintRect);
309 #if HAVE_FEATURE_OPENGL
310 VCL_GL_INFO("PaintHelper::DoPaint end on " <<
311 typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
312 #endif
316 namespace vcl
319 void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window& rWindow,
320 const Rectangle& rRect, sal_uInt16 nHighlight,
321 bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
322 Color* pSelectionTextColor, long nCornerRadius, Color* pPaintColor)
324 if (rRect.IsEmpty())
325 return;
327 bool bRoundEdges = nCornerRadius > 0;
329 const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
331 // colors used for item highlighting
332 Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
333 Color aSelectionFillColor(aSelectionBorderColor);
335 bool bDark = rStyles.GetFaceColor().IsDark();
336 bool bBright = ( rStyles.GetFaceColor() == Color( COL_WHITE ) );
338 int c1 = aSelectionBorderColor.GetLuminance();
339 int c2 = rWindow.GetDisplayBackground().GetColor().GetLuminance();
341 if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
343 // constrast too low
344 sal_uInt16 h, s, b;
345 aSelectionFillColor.RGBtoHSB( h, s, b );
346 if( b > 50 ) b -= 40;
347 else b += 40;
348 aSelectionFillColor.SetColor( Color::HSBtoRGB( h, s, b ) );
349 aSelectionBorderColor = aSelectionFillColor;
352 if (bRoundEdges)
354 if (aSelectionBorderColor.IsDark())
355 aSelectionBorderColor.IncreaseLuminance(128);
356 else
357 aSelectionBorderColor.DecreaseLuminance(128);
360 Rectangle aRect(rRect);
361 if (bDrawExtBorderOnly)
363 aRect.Left() -= 1;
364 aRect.Top() -= 1;
365 aRect.Right() += 1;
366 aRect.Bottom() += 1;
368 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
370 if (bDrawBorder)
371 rRenderContext.SetLineColor(bDark ? Color(COL_WHITE) : (bBright ? Color(COL_BLACK) : aSelectionBorderColor));
372 else
373 rRenderContext.SetLineColor();
375 sal_uInt16 nPercent = 0;
376 if (!nHighlight)
378 if (bDark)
379 aSelectionFillColor = COL_BLACK;
380 else
381 nPercent = 80; // just checked (light)
383 else
385 if (bChecked && nHighlight == 2)
387 if (bDark)
388 aSelectionFillColor = COL_LIGHTGRAY;
389 else if (bBright)
391 aSelectionFillColor = COL_BLACK;
392 rRenderContext.SetLineColor(COL_BLACK);
393 nPercent = 0;
395 else
396 nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
398 else if (bChecked || nHighlight == 1)
400 if (bDark)
401 aSelectionFillColor = COL_GRAY;
402 else if (bBright)
404 aSelectionFillColor = COL_BLACK;
405 rRenderContext.SetLineColor(COL_BLACK);
406 nPercent = 0;
408 else
409 nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
411 else
413 if (bDark)
414 aSelectionFillColor = COL_LIGHTGRAY;
415 else if (bBright)
417 aSelectionFillColor = COL_BLACK;
418 rRenderContext.SetLineColor(COL_BLACK);
419 if (nHighlight == 3)
420 nPercent = 80;
421 else
422 nPercent = 0;
424 else
425 nPercent = 70; // selected ( dark )
429 if (bDark && bDrawExtBorderOnly)
431 rRenderContext.SetFillColor();
432 if (pSelectionTextColor)
433 *pSelectionTextColor = rStyles.GetHighlightTextColor();
435 else
437 rRenderContext.SetFillColor(aSelectionFillColor);
438 if (pSelectionTextColor)
440 Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
441 Color aHLTextColor = rStyles.GetHighlightTextColor();
442 int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
443 int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
444 *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
448 if (bDark)
450 rRenderContext.DrawRect(aRect);
452 else
454 if (bRoundEdges)
456 tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
457 tools::PolyPolygon aPolyPoly(aPoly);
458 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
460 else
462 tools::Polygon aPoly(aRect);
463 tools::PolyPolygon aPolyPoly(aPoly);
464 rRenderContext.DrawTransparent(aPolyPoly, nPercent);
468 rRenderContext.Pop(); // LINECOLOR | FILLCOLOR
471 void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
473 pHelper->SetPop();
475 if ( mpWindowImpl->mpCursor )
476 pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
478 mbInitClipRegion = true;
479 mpWindowImpl->mbInPaint = true;
481 // restore Paint-Region
482 vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
483 rPaintRegion = mpWindowImpl->maInvalidateRegion;
484 Rectangle aPaintRect = rPaintRegion.GetBoundRect();
486 // - RTL - re-mirror paint rect and region at this window
487 if (ImplIsAntiparallel())
489 rRenderContext.ReMirror(aPaintRect);
490 rRenderContext.ReMirror(rPaintRegion);
492 aPaintRect = ImplDevicePixelToLogic(aPaintRect);
493 mpWindowImpl->mpPaintRegion = &rPaintRegion;
494 mpWindowImpl->maInvalidateRegion.SetEmpty();
496 if ((pHelper->GetPaintFlags() & IMPL_PAINT_ERASE) && rRenderContext.IsBackground())
498 if (rRenderContext.IsClipRegion())
500 vcl::Region aOldRegion = rRenderContext.GetClipRegion();
501 rRenderContext.SetClipRegion();
502 Erase(rRenderContext);
503 rRenderContext.SetClipRegion(aOldRegion);
505 else
506 Erase(rRenderContext);
509 // #98943# trigger drawing of toolbox selection after all children are painted
510 if (mpWindowImpl->mbDrawSelectionBackground)
511 pHelper->SetSelectionRect(aPaintRect);
512 pHelper->SetPaintRect(aPaintRect);
515 void Window::PopPaintHelper(PaintHelper *pHelper)
517 if (mpWindowImpl->mpWinData)
519 if (mpWindowImpl->mbFocusVisible)
520 ImplInvertFocus(*(mpWindowImpl->mpWinData->mpFocusRect));
522 mpWindowImpl->mbInPaint = false;
523 mbInitClipRegion = true;
524 mpWindowImpl->mpPaintRegion = nullptr;
525 if (mpWindowImpl->mpCursor)
526 mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
529 } /* namespace vcl */
531 PaintHelper::~PaintHelper()
533 WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
534 if (m_bPop)
536 m_pWindow->PopPaintHelper(this);
539 ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
540 if ( m_nPaintFlags & (IMPL_PAINT_PAINTALLCHILDREN | IMPL_PAINT_PAINTCHILDREN) )
542 // Paint from the bottom child window and frontward.
543 vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
544 while (pTempWindow)
546 if (pTempWindow->mpWindowImpl->mbVisible)
547 pTempWindow->ImplCallPaint(m_pChildRegion, m_nPaintFlags);
548 pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
552 if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
553 /* #98602# need to invert the tracking rect AFTER
554 * the children have painted
556 m_pWindow->InvertTracking( *(pWindowImpl->mpWinData->mpTrackRect), pWindowImpl->mpWinData->mnTrackFlags );
558 // double-buffering: paint in case we created the buffer, the children are
559 // already painted inside
560 if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
562 PaintBuffer();
563 pFrameData->mbInBufferedPaint = false;
564 pFrameData->maBufferedRect = Rectangle();
567 // #98943# draw toolbox selection
568 if( !m_aSelectionRect.IsEmpty() )
569 m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
571 delete m_pChildRegion;
574 namespace vcl {
576 void Window::ImplCallPaint(const vcl::Region* pRegion, sal_uInt16 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 & IMPL_PAINT_PAINTALLCHILDREN)
585 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALLCHILDREN | (nPaintFlags & IMPL_PAINT_PAINTALL);
586 if (nPaintFlags & IMPL_PAINT_PAINTCHILDREN)
587 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDREN;
588 if (nPaintFlags & IMPL_PAINT_ERASE)
589 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE;
590 if (nPaintFlags & IMPL_PAINT_CHECKRTL)
591 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL;
592 if (!mpWindowImpl->mpFirstChild)
593 mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALLCHILDREN;
595 if (mpWindowImpl->mbPaintDisabled)
597 if (mpWindowImpl->mnPaintFlags & IMPL_PAINT_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 & ~(IMPL_PAINT_PAINT);
610 PaintHelper aHelper(this, nPaintFlags);
612 if (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT)
613 aHelper.DoPaint(pRegion);
614 else
615 mpWindowImpl->mnPaintFlags = 0;
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 & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDREN) )
635 // - RTL - notify ImplCallPaint to check for re-mirroring (CHECKRTL)
636 // because we were called from the Sal layer
637 ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */);
641 IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Idle *, void)
643 // save paint events until layout is done
644 if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
646 mpWindowImpl->mpFrameData->maPaintIdle.Start();
647 return;
650 // save paint events until resizing or initial sizing done
651 if (mpWindowImpl->mbFrame &&
652 mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
654 mpWindowImpl->mpFrameData->maPaintIdle.Start();
656 else if ( mpWindowImpl->mbReallyVisible )
658 ImplCallOverlapPaint();
662 IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Idle *, void)
664 if( mpWindowImpl->mbReallyVisible )
666 ImplCallResize();
667 if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
669 mpWindowImpl->mpFrameData->maPaintIdle.Stop();
670 mpWindowImpl->mpFrameData->maPaintIdle.GetIdleHdl().Call( nullptr );
675 void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
677 // set PAINTCHILDREN for all parent windows till the first OverlapWindow
678 if ( !ImplIsOverlapWindow() )
680 vcl::Window* pTempWindow = this;
681 sal_uInt16 nTranspPaint = IsPaintTransparent() ? IMPL_PAINT_PAINT : 0;
684 pTempWindow = pTempWindow->ImplGetParent();
685 if ( pTempWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDREN )
686 break;
687 pTempWindow->mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDREN | nTranspPaint;
688 if( ! pTempWindow->IsPaintTransparent() )
689 nTranspPaint = 0;
691 while ( !pTempWindow->ImplIsOverlapWindow() );
694 // set Paint-Flags
695 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT;
696 if ( nFlags & InvalidateFlags::Children )
697 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALLCHILDREN;
698 if ( !(nFlags & InvalidateFlags::NoErase) )
699 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE;
700 if ( !pRegion )
701 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALL;
703 // if not everything has to be redrawn, add the region to it
704 if ( !(mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL) )
705 mpWindowImpl->maInvalidateRegion.Union( *pRegion );
707 // Handle transparent windows correctly: invalidate must be done on the first opaque parent
708 if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
709 && ImplGetParent() )
711 vcl::Window *pParent = ImplGetParent();
712 while( pParent && pParent->IsPaintTransparent() )
713 pParent = pParent->ImplGetParent();
714 if( pParent )
716 vcl::Region *pChildRegion;
717 if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
718 // invalidate the whole child window region in the parent
719 pChildRegion = ImplGetWinChildClipRegion();
720 else
721 // invalidate the same region in the parent that has to be repainted in the child
722 pChildRegion = &mpWindowImpl->maInvalidateRegion;
724 nFlags |= InvalidateFlags::Children; // paint should also be done on all children
725 nFlags &= ~InvalidateFlags::NoErase; // parent should paint and erase to create proper background
726 pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
730 if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
731 mpWindowImpl->mpFrameData->maPaintIdle.Start();
734 void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
736 vcl::Region aRegion = rRegion;
738 ImplClipBoundaries( aRegion, true, true );
739 if ( !aRegion.IsEmpty() )
740 ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
742 // now we invalidate the overlapping windows
743 vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
744 while ( pTempWindow )
746 if ( pTempWindow->IsVisible() )
747 pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
749 pTempWindow = pTempWindow->mpWindowImpl->mpNext;
753 void Window::ImplInvalidateParentFrameRegion( vcl::Region& rRegion )
755 if ( mpWindowImpl->mbOverlapWin )
756 mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
757 else
759 if( ImplGetParent() )
760 ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
764 void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
766 // check what has to be redrawn
767 bool bInvalidateAll = !pRegion;
769 // take Transparent-Invalidate into account
770 vcl::Window* pOpaqueWindow = this;
771 if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
773 vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
774 while ( pTempWindow )
776 if ( !pTempWindow->IsPaintTransparent() )
778 pOpaqueWindow = pTempWindow;
779 nFlags |= InvalidateFlags::Children;
780 bInvalidateAll = false;
781 break;
784 if ( pTempWindow->ImplIsOverlapWindow() )
785 break;
787 pTempWindow = pTempWindow->ImplGetParent();
791 // assemble region
792 InvalidateFlags nOrgFlags = nFlags;
793 if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
795 if ( GetStyle() & WB_CLIPCHILDREN )
796 nFlags |= InvalidateFlags::NoChildren;
797 else
798 nFlags |= InvalidateFlags::Children;
800 if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
801 bInvalidateAll = false;
802 if ( bInvalidateAll )
803 ImplInvalidateFrameRegion( nullptr, nFlags );
804 else
806 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
807 vcl::Region aRegion( aRect );
808 if ( pRegion )
810 // --- RTL --- remirror region before intersecting it
811 if ( ImplIsAntiparallel() )
813 const OutputDevice *pOutDev = GetOutDev();
815 vcl::Region aRgn( *pRegion );
816 pOutDev->ReMirror( aRgn );
817 aRegion.Intersect( aRgn );
819 else
820 aRegion.Intersect( *pRegion );
822 ImplClipBoundaries( aRegion, true, true );
823 if ( nFlags & InvalidateFlags::NoChildren )
825 nFlags &= ~InvalidateFlags::Children;
826 if ( !(nFlags & InvalidateFlags::NoClipChildren) )
828 if ( nOrgFlags & InvalidateFlags::NoChildren )
829 ImplClipAllChildren( aRegion );
830 else
832 if ( ImplClipChildren( aRegion ) )
833 nFlags |= InvalidateFlags::Children;
837 if ( !aRegion.IsEmpty() )
838 ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required
841 if ( nFlags & InvalidateFlags::Update )
842 pOpaqueWindow->Update(); // start painting at the opaque parent
845 void Window::ImplMoveInvalidateRegion( const Rectangle& rRect,
846 long nHorzScroll, long nVertScroll,
847 bool bChildren )
849 if ( (mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALL)) == IMPL_PAINT_PAINT )
851 vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
852 aTempRegion.Intersect( rRect );
853 aTempRegion.Move( nHorzScroll, nVertScroll );
854 mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
857 if ( bChildren && (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDREN) )
859 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
860 while ( pWindow )
862 pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
863 pWindow = pWindow->mpWindowImpl->mpNext;
868 void Window::ImplMoveAllInvalidateRegions( const Rectangle& rRect,
869 long nHorzScroll, long nVertScroll,
870 bool bChildren )
872 // also shift Paint-Region when paints need processing
873 ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
874 // Paint-Region should be shifted, as drawn by the parents
875 if ( !ImplIsOverlapWindow() )
877 vcl::Region aPaintAllRegion;
878 vcl::Window* pPaintAllWindow = this;
881 pPaintAllWindow = pPaintAllWindow->ImplGetParent();
882 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDREN )
884 if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
886 aPaintAllRegion.SetEmpty();
887 break;
889 else
890 aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
893 while ( !pPaintAllWindow->ImplIsOverlapWindow() );
894 if ( !aPaintAllRegion.IsEmpty() )
896 aPaintAllRegion.Move( nHorzScroll, nVertScroll );
897 InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
898 if ( bChildren )
899 nPaintFlags |= InvalidateFlags::Children;
900 ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
905 void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
907 if ( !pRegion )
908 mpWindowImpl->maInvalidateRegion.SetEmpty();
909 else
911 // when all child windows have to be drawn we need to invalidate them before doing so
912 if ( (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDREN) && mpWindowImpl->mpFirstChild )
914 vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
915 if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
917 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
918 aChildRegion = aRect;
920 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
921 while ( pChild )
923 pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
924 pChild = pChild->mpWindowImpl->mpNext;
927 if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL )
929 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
930 mpWindowImpl->maInvalidateRegion = aRect;
932 mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
934 mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALL;
936 if ( nFlags & ValidateFlags::Children )
938 vcl::Window* pChild = mpWindowImpl->mpFirstChild;
939 while ( pChild )
941 pChild->ImplValidateFrameRegion( pRegion, nFlags );
942 pChild = pChild->mpWindowImpl->mpNext;
947 void Window::ImplValidate()
949 // assemble region
950 bool bValidateAll = true;
951 ValidateFlags nFlags = ValidateFlags::NONE;
952 if ( GetStyle() & WB_CLIPCHILDREN )
953 nFlags |= ValidateFlags::NoChildren;
954 else
955 nFlags |= ValidateFlags::Children;
956 if ( (nFlags & ValidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
957 bValidateAll = false;
958 if ( bValidateAll )
959 ImplValidateFrameRegion( nullptr, nFlags );
960 else
962 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
963 vcl::Region aRegion( aRect );
964 ImplClipBoundaries( aRegion, true, true );
965 if ( nFlags & ValidateFlags::NoChildren )
967 nFlags &= ~ValidateFlags::Children;
968 if ( ImplClipChildren( aRegion ) )
969 nFlags |= ValidateFlags::Children;
971 if ( !aRegion.IsEmpty() )
972 ImplValidateFrameRegion( &aRegion, nFlags );
976 void Window::ImplUpdateAll()
978 if ( !mpWindowImpl->mbReallyVisible )
979 return;
981 bool bFlush = false;
982 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
984 Point aPoint( 0, 0 );
985 vcl::Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
986 ImplInvalidateOverlapFrameRegion( aRegion );
987 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
988 bFlush = true;
991 // an update changes the OverlapWindow, such that for later paints
992 // not too much has to be drawn, if ALLCHILDREN etc. is set
993 vcl::Window* pWindow = ImplGetFirstOverlapWindow();
994 pWindow->ImplCallOverlapPaint();
996 if ( bFlush )
997 Flush();
1000 void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1004 void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1008 void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const Rectangle& rRect)
1010 CallEventListeners(VCLEVENT_WINDOW_PAINT, const_cast<Rectangle *>(&rRect));
1013 void Window::SetPaintTransparent( bool bTransparent )
1015 // transparency is not useful for frames as the background would have to be provided by a different frame
1016 if( bTransparent && mpWindowImpl->mbFrame )
1017 return;
1019 if ( mpWindowImpl->mpBorderWindow )
1020 mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1022 mpWindowImpl->mbPaintTransparent = bTransparent;
1025 void Window::SetWindowRegionPixel()
1028 if ( mpWindowImpl->mpBorderWindow )
1029 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1030 else if( mpWindowImpl->mbFrame )
1032 mpWindowImpl->maWinRegion = vcl::Region(true);
1033 mpWindowImpl->mbWinRegion = false;
1034 mpWindowImpl->mpFrame->ResetClipRegion();
1036 else
1038 if ( mpWindowImpl->mbWinRegion )
1040 mpWindowImpl->maWinRegion = vcl::Region(true);
1041 mpWindowImpl->mbWinRegion = false;
1042 ImplSetClipFlag();
1044 if ( IsReallyVisible() )
1046 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1047 vcl::Region aRegion( aRect );
1048 ImplInvalidateParentFrameRegion( aRegion );
1054 void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1057 if ( mpWindowImpl->mpBorderWindow )
1058 mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1059 else if( mpWindowImpl->mbFrame )
1061 if( !rRegion.IsNull() )
1063 mpWindowImpl->maWinRegion = rRegion;
1064 mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1066 if( mpWindowImpl->mbWinRegion )
1068 // set/update ClipRegion
1069 RectangleVector aRectangles;
1070 mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1071 mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1073 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
1075 mpWindowImpl->mpFrame->UnionClipRegion(
1076 aRectIter->Left(),
1077 aRectIter->Top(),
1078 aRectIter->GetWidth(), // orig nWidth was ((R - L) + 1), same as GetWidth does
1079 aRectIter->GetHeight()); // same for height
1082 mpWindowImpl->mpFrame->EndSetClipRegion();
1084 //long nX;
1085 //long nY;
1086 //long nWidth;
1087 //long nHeight;
1088 //sal_uLong nRectCount;
1089 //ImplRegionInfo aInfo;
1090 //sal_Bool bRegionRect;
1092 //nRectCount = mpWindowImpl->maWinRegion.GetRectCount();
1093 //mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount );
1094 //bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight );
1095 //while ( bRegionRect )
1097 // mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight );
1098 // bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight );
1100 //mpWindowImpl->mpFrame->EndSetClipRegion();
1102 else
1103 SetWindowRegionPixel();
1105 else
1106 SetWindowRegionPixel();
1108 else
1110 if ( rRegion.IsNull() )
1112 if ( mpWindowImpl->mbWinRegion )
1114 mpWindowImpl->maWinRegion = vcl::Region(true);
1115 mpWindowImpl->mbWinRegion = false;
1116 ImplSetClipFlag();
1119 else
1121 mpWindowImpl->maWinRegion = rRegion;
1122 mpWindowImpl->mbWinRegion = true;
1123 ImplSetClipFlag();
1126 if ( IsReallyVisible() )
1128 Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) );
1129 vcl::Region aRegion( aRect );
1130 ImplInvalidateParentFrameRegion( aRegion );
1135 const vcl::Region& Window::GetWindowRegionPixel() const
1138 if ( mpWindowImpl->mpBorderWindow )
1139 return mpWindowImpl->mpBorderWindow->GetWindowRegionPixel();
1140 else
1141 return mpWindowImpl->maWinRegion;
1144 bool Window::IsWindowRegionPixel() const
1147 if ( mpWindowImpl->mpBorderWindow )
1148 return mpWindowImpl->mpBorderWindow->IsWindowRegionPixel();
1149 else
1150 return mpWindowImpl->mbWinRegion;
1153 vcl::Region Window::GetPaintRegion() const
1156 if ( mpWindowImpl->mpPaintRegion )
1158 vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1159 aRegion.Move( -mnOutOffX, -mnOutOffY );
1160 return PixelToLogic( aRegion );
1162 else
1164 vcl::Region aPaintRegion(true);
1165 return aPaintRegion;
1169 void Window::Invalidate( InvalidateFlags nFlags )
1171 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1172 return;
1174 ImplInvalidate( nullptr, nFlags );
1175 LogicInvalidate(nullptr);
1178 void Window::Invalidate( const Rectangle& rRect, InvalidateFlags nFlags )
1180 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1181 return;
1183 OutputDevice *pOutDev = GetOutDev();
1184 Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1185 if ( !aRect.IsEmpty() )
1187 vcl::Region aRegion( aRect );
1188 ImplInvalidate( &aRegion, nFlags );
1189 Rectangle aLogicRectangle(rRect);
1190 LogicInvalidate(&aLogicRectangle);
1194 void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1196 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1197 return;
1199 if ( rRegion.IsNull() )
1201 ImplInvalidate( nullptr, nFlags );
1202 LogicInvalidate(nullptr);
1204 else
1206 vcl::Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1207 if ( !aRegion.IsEmpty() )
1209 ImplInvalidate( &aRegion, nFlags );
1210 Rectangle aLogicRectangle = rRegion.GetBoundRect();
1211 LogicInvalidate(&aLogicRectangle);
1216 void Window::LogicInvalidate(const Rectangle* pRectangle)
1218 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1219 return;
1221 if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1223 // In case we are routing the window, notify the client
1224 std::vector<vcl::LOKPayloadItem> aPayload;
1225 if (pRectangle)
1226 aPayload.push_back(std::make_pair(OString("rectangle"), pRectangle->toString()));
1228 pNotifier->notifyWindow(GetLOKWindowId(), "invalidate", aPayload);
1230 // Added for dialog items. Pass invalidation to the parent window.
1231 else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1233 const Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), Size(GetOutputWidthPixel(), GetOutputHeightPixel()));
1234 pParent->LogicInvalidate(&aRect);
1238 void Window::Validate()
1240 if ( !comphelper::LibreOfficeKit::isActive() && (!IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight) )
1241 return;
1243 ImplValidate();
1246 bool Window::HasPaintEvent() const
1249 if ( !mpWindowImpl->mbReallyVisible )
1250 return false;
1252 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1253 return true;
1255 if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT )
1256 return true;
1258 if ( !ImplIsOverlapWindow() )
1260 const vcl::Window* pTempWindow = this;
1263 pTempWindow = pTempWindow->ImplGetParent();
1264 if ( pTempWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINTCHILDREN | IMPL_PAINT_PAINTALLCHILDREN) )
1265 return true;
1267 while ( !pTempWindow->ImplIsOverlapWindow() );
1270 return false;
1273 void Window::Update()
1275 if ( mpWindowImpl->mpBorderWindow )
1277 mpWindowImpl->mpBorderWindow->Update();
1278 return;
1281 if ( !mpWindowImpl->mbReallyVisible )
1282 return;
1284 bool bFlush = false;
1285 if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1287 Point aPoint( 0, 0 );
1288 vcl::Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1289 ImplInvalidateOverlapFrameRegion( aRegion );
1290 if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1291 bFlush = true;
1294 // First we should skip all windows which are Paint-Transparent
1295 vcl::Window* pUpdateWindow = this;
1296 vcl::Window* pWindow = pUpdateWindow;
1297 while ( !pWindow->ImplIsOverlapWindow() )
1299 if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1301 pUpdateWindow = pWindow;
1302 break;
1304 pWindow = pWindow->ImplGetParent();
1306 // In order to limit drawing, an update only draws the window which
1307 // has PAINTALLCHILDREN set
1308 pWindow = pUpdateWindow;
1311 if ( pWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDREN )
1312 pUpdateWindow = pWindow;
1313 if ( pWindow->ImplIsOverlapWindow() )
1314 break;
1315 pWindow = pWindow->ImplGetParent();
1317 while ( pWindow );
1319 // if there is something to paint, trigger a Paint
1320 if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDREN) )
1322 VclPtr<vcl::Window> xWindow(this);
1324 // trigger an update also for system windows on top of us,
1325 // otherwise holes would remain
1326 vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap;
1327 while ( pUpdateOverlapWindow )
1329 pUpdateOverlapWindow->Update();
1330 pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1333 pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1335 if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1336 pUpdateWindow->LogicInvalidate(nullptr);
1338 if (xWindow->IsDisposed())
1339 return;
1341 bFlush = true;
1344 if ( bFlush )
1345 Flush();
1348 void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1350 bool bRVisible = mpWindowImpl->mbReallyVisible;
1351 mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1352 bool bDevOutput = mbDevOutput;
1353 mbDevOutput = true;
1355 const OutputDevice *pOutDev = GetOutDev();
1356 long nOldDPIX = pOutDev->GetDPIX();
1357 long nOldDPIY = pOutDev->GetDPIY();
1358 mnDPIX = i_pTargetOutDev->GetDPIX();
1359 mnDPIY = i_pTargetOutDev->GetDPIY();
1360 bool bOutput = IsOutputEnabled();
1361 EnableOutput();
1363 double fScaleX = 1;
1364 double fScaleY = 1;
1365 bool bNeedsScaling = false;
1366 if(comphelper::LibreOfficeKit::isActive())
1368 if(GetMapMode().GetMapUnit() != MapUnit::MapPixel &&
1369 // Some of the preview windows (SvxPreviewBase) uses different painting (drawinglayer primitives)
1370 // For these preview we don't need to scale even tough the unit is not pixel.
1371 GetMapMode().GetMapUnit() != MapUnit::Map100thMM)
1373 bNeedsScaling = true;
1374 // 1000.0 is used to reduce rounding imprecision (Size uses integers)
1375 Size aLogicSize = PixelToLogic(Size(1000.0, 1000.0));
1376 fScaleX = aLogicSize.Width() / 1000.0;
1377 fScaleY = aLogicSize.Height() / 1000.0;
1380 else
1381 { // TODO: Above scaling was added for LOK only, would be good to check how it works in other use cases
1382 SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl", "MapMode must be PIXEL based" );
1383 if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1384 return;
1387 // preserve graphicsstate
1388 Push();
1389 vcl::Region aClipRegion( GetClipRegion() );
1390 SetClipRegion();
1392 GDIMetaFile* pOldMtf = GetConnectMetaFile();
1393 GDIMetaFile aMtf;
1394 SetConnectMetaFile( &aMtf );
1396 // put a push action to metafile
1397 Push();
1398 // copy graphics state to metafile
1399 vcl::Font aCopyFont = GetFont();
1400 if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY )
1402 aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * mnDPIY / nOldDPIY );
1403 aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * mnDPIX / nOldDPIX );
1405 SetFont( aCopyFont );
1406 SetTextColor( GetTextColor() );
1407 if( IsLineColor() )
1408 SetLineColor( GetLineColor() );
1409 else
1410 SetLineColor();
1411 if( IsFillColor() )
1412 SetFillColor( GetFillColor() );
1413 else
1414 SetFillColor();
1415 if( IsTextLineColor() )
1416 SetTextLineColor( GetTextLineColor() );
1417 else
1418 SetTextLineColor();
1419 if( IsOverlineColor() )
1420 SetOverlineColor( GetOverlineColor() );
1421 else
1422 SetOverlineColor();
1423 if( IsTextFillColor() )
1424 SetTextFillColor( GetTextFillColor() );
1425 else
1426 SetTextFillColor();
1427 SetTextAlign( GetTextAlign() );
1428 SetRasterOp( GetRasterOp() );
1429 if( IsRefPoint() )
1430 SetRefPoint( GetRefPoint() );
1431 else
1432 SetRefPoint();
1433 SetLayoutMode( GetLayoutMode() );
1434 SetDigitLanguage( GetDigitLanguage() );
1436 Rectangle aPaintRect;
1437 if(bNeedsScaling)
1439 aPaintRect = Rectangle( Point( 0, 0 ),
1440 Size(GetOutputSizePixel().Width() * fScaleX, GetOutputSizePixel().Height() * fScaleY) );
1442 else
1444 aPaintRect = Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
1446 aClipRegion.Intersect( aPaintRect );
1447 SetClipRegion( aClipRegion );
1449 // do the actual paint
1451 // background
1452 if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1454 Erase(*this);
1455 if(bNeedsScaling)
1456 aMtf.Scale(fScaleX, fScaleY);
1458 // foreground
1459 Paint(*this, aPaintRect);
1460 // put a pop action to metafile
1461 Pop();
1463 SetConnectMetaFile( pOldMtf );
1464 EnableOutput( bOutput );
1465 mpWindowImpl->mbReallyVisible = bRVisible;
1467 // paint metafile to VDev
1468 VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1469 DeviceFormat::DEFAULT,
1470 DeviceFormat::DEFAULT);
1472 if(bNeedsScaling)
1473 pMaskedDevice->SetMapMode( GetMapMode() );
1474 pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() );
1475 pMaskedDevice->EnableRTL( IsRTLEnabled() );
1476 aMtf.WindStart();
1477 aMtf.Play( pMaskedDevice );
1478 BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), aPaintRect.GetSize() ) );
1479 i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx );
1480 // get rid of virtual device now so they don't pile up during recursive calls
1481 pMaskedDevice.disposeAndClear();
1483 for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1485 if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1487 long nDeltaX = pChild->mnOutOffX - mnOutOffX;
1489 if( pOutDev->HasMirroredGraphics() )
1490 nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth;
1491 long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1492 Point aPos( i_rPos );
1493 Point aDelta( nDeltaX, nDeltaY );
1494 aPos += aDelta;
1495 pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1499 // restore graphics state
1500 Pop();
1502 EnableOutput( bOutput );
1503 mpWindowImpl->mbReallyVisible = bRVisible;
1504 mbDevOutput = bDevOutput;
1505 mnDPIX = nOldDPIX;
1506 mnDPIY = nOldDPIY;
1509 void Window::PaintToDevice( OutputDevice* pDev, const Point& rPos, const Size& /*rSize*/ )
1511 SAL_WARN_IF( pDev->HasMirroredGraphics(), "vcl", "PaintToDevice to mirroring graphics" );
1512 SAL_WARN_IF( pDev->IsRTLEnabled(), "vcl", "PaintToDevice to mirroring device" );
1514 vcl::Window* pRealParent = nullptr;
1515 if( ! mpWindowImpl->mbVisible )
1517 vcl::Window* pTempParent = ImplGetDefaultWindow();
1518 pTempParent->EnableChildTransparentMode();
1519 pRealParent = GetParent();
1520 SetParent( pTempParent );
1521 // trigger correct visibility flags for children
1522 Show();
1523 Hide();
1526 bool bVisible = mpWindowImpl->mbVisible;
1527 mpWindowImpl->mbVisible = true;
1529 if( mpWindowImpl->mpBorderWindow )
1530 mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1531 else
1532 ImplPaintToDevice( pDev, rPos );
1534 mpWindowImpl->mbVisible = bVisible;
1536 if( pRealParent )
1537 SetParent( pRealParent );
1540 void Window::Erase(vcl::RenderContext& rRenderContext)
1542 if (!IsDeviceOutputNecessary() || ImplIsRecordLayout())
1543 return;
1545 bool bNativeOK = false;
1547 ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1548 if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1550 Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1551 ControlState nState = ControlState::NONE;
1553 if (IsEnabled())
1554 nState |= ControlState::ENABLED;
1556 bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1557 nState, ImplControlValue(), OUString());
1560 if (mbBackground && !bNativeOK)
1562 RasterOp eRasterOp = GetRasterOp();
1563 if (eRasterOp != RasterOp::OverPaint)
1564 SetRasterOp(RasterOp::OverPaint);
1565 rRenderContext.DrawWallpaper(0, 0, mnOutWidth, mnOutHeight, maBackground);
1566 if (eRasterOp != RasterOp::OverPaint)
1567 rRenderContext.SetRasterOp(eRasterOp);
1570 if (mpAlphaVDev)
1571 mpAlphaVDev->Erase();
1574 void Window::ImplScroll( const Rectangle& rRect,
1575 long nHorzScroll, long nVertScroll, ScrollFlags nFlags )
1577 if ( !IsDeviceOutputNecessary() )
1578 return;
1580 nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll );
1581 nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll );
1583 if ( !nHorzScroll && !nVertScroll )
1584 return;
1586 if ( mpWindowImpl->mpCursor )
1587 mpWindowImpl->mpCursor->ImplSuspend();
1589 ScrollFlags nOrgFlags = nFlags;
1590 if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1592 if ( GetStyle() & WB_CLIPCHILDREN )
1593 nFlags |= ScrollFlags::NoChildren;
1594 else
1595 nFlags |= ScrollFlags::Children;
1598 vcl::Region aInvalidateRegion;
1599 bool bScrollChildren(nFlags & ScrollFlags::Children);
1601 if ( !mpWindowImpl->mpFirstChild )
1602 bScrollChildren = false;
1604 OutputDevice *pOutDev = GetOutDev();
1606 // --- RTL --- check if this window requires special action
1607 bool bReMirror = ( ImplIsAntiparallel() );
1609 Rectangle aRectMirror( rRect );
1610 if( bReMirror )
1612 // --- RTL --- make sure the invalidate region of this window is
1613 // computed in the same coordinate space as the one from the overlap windows
1614 pOutDev->ReMirror( aRectMirror );
1617 // adapt paint areas
1618 ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1620 ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1622 // --- RTL ---
1623 // if the scrolling on the device is performed in the opposite direction
1624 // then move the overlaps in that direction to compute the invalidate region
1625 // on the correct side, i.e., revert nHorzScroll
1626 if (!aInvalidateRegion.IsEmpty())
1628 aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1631 Rectangle aDestRect(aRectMirror);
1632 aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1633 vcl::Region aWinInvalidateRegion(aRectMirror);
1634 if (!SupportsDoubleBuffering())
1636 // There will be no CopyArea() call below, so invalidate the
1637 // whole visible area, not only the smaller one that was just
1638 // scrolled in.
1639 aWinInvalidateRegion.Exclude(aDestRect);
1642 aInvalidateRegion.Union(aWinInvalidateRegion);
1644 Point aPoint( mnOutOffX, mnOutOffY );
1645 vcl::Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) );
1646 if ( nFlags & ScrollFlags::Clip )
1647 aRegion.Intersect( rRect );
1648 if ( mpWindowImpl->mbWinRegion )
1649 aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1651 aRegion.Exclude( aInvalidateRegion );
1653 ImplClipBoundaries( aRegion, false, true );
1654 if ( !bScrollChildren )
1656 if ( nOrgFlags & ScrollFlags::NoChildren )
1657 ImplClipAllChildren( aRegion );
1658 else
1659 ImplClipChildren( aRegion );
1661 if ( mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1662 aRegion.Intersect( maRegion );
1663 if ( !aRegion.IsEmpty() )
1665 if ( mpWindowImpl->mpWinData )
1667 if ( mpWindowImpl->mbFocusVisible )
1668 ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) );
1669 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1670 InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags );
1672 #ifndef IOS
1673 // This seems completely unnecessary with tiled rendering, and
1674 // causes the "AquaSalGraphics::copyArea() for non-layered
1675 // graphics" message. Presumably we should bypass this on all
1676 // platforms when dealing with a "window" that uses tiled
1677 // rendering at the moment. Unclear how to figure that out,
1678 // though. Also unclear whether we actually could just not
1679 // create a "frame window", whatever that exactly is, in the
1680 // tiled rendering case, or at least for platforms where tiles
1681 // rendering is all there is.
1683 SalGraphics* pGraphics = ImplGetFrameGraphics();
1684 // The invalidation area contains the area what would be copied here,
1685 // so avoid copying in case of double buffering.
1686 if (pGraphics && !SupportsDoubleBuffering())
1688 if( bReMirror )
1690 // --- RTL --- frame coordinates require re-mirroring
1691 pOutDev->ReMirror( aRegion );
1694 pOutDev->SelectClipRegion( aRegion, pGraphics );
1695 pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1696 rRect.Left(), rRect.Top(),
1697 rRect.GetWidth(), rRect.GetHeight(),
1698 this );
1700 #endif
1701 if ( mpWindowImpl->mpWinData )
1703 if ( mpWindowImpl->mbFocusVisible )
1704 ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) );
1705 if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1706 InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags );
1710 if ( !aInvalidateRegion.IsEmpty() )
1712 // --- RTL --- the invalidate region for this windows is already computed in frame coordinates
1713 // so it has to be re-mirrored before calling the Paint-handler
1714 mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL;
1716 InvalidateFlags nPaintFlags = InvalidateFlags::Children;
1717 if ( !bScrollChildren )
1719 if ( nOrgFlags & ScrollFlags::NoChildren )
1720 ImplClipAllChildren( aInvalidateRegion );
1721 else
1722 ImplClipChildren( aInvalidateRegion );
1724 ImplInvalidateFrameRegion( &aInvalidateRegion, nPaintFlags );
1727 if ( bScrollChildren )
1729 vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1730 while ( pWindow )
1732 Point aPos = pWindow->GetPosPixel();
1733 aPos += Point( nHorzScroll, nVertScroll );
1734 pWindow->SetPosPixel( aPos );
1736 pWindow = pWindow->mpWindowImpl->mpNext;
1740 if ( nFlags & ScrollFlags::Update )
1741 Update();
1743 if ( mpWindowImpl->mpCursor )
1744 mpWindowImpl->mpCursor->ImplResume();
1747 } /* namespace vcl */
1750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */