Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/window/paint.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
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/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
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 .
18
 */
19
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>
27
28
#include <sal/types.h>
29
#include <sal/log.hxx>
30
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
40
41
// PaintBufferGuard
42
43
namespace vcl
44
{
45
PaintBufferGuard::PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
46
0
    : mpFrameData(pFrameData),
47
0
    m_pWindow(pWindow),
48
0
    mbBackground(false),
49
0
    mnOutOffX(0),
50
0
    mnOutOffY(0)
51
0
{
52
0
    if (!pFrameData->mpBuffer)
53
0
        return;
54
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
0
    mbBackground = pFrameData->mpBuffer->IsBackground();
60
0
    if (pWindow->IsBackground())
61
0
    {
62
0
        maBackground = pFrameData->mpBuffer->GetBackground();
63
0
        pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
64
0
    }
65
    //else
66
        //SAL_WARN("vcl.window", "the root of the double-buffering hierarchy should not have a transparent background");
67
68
0
    vcl::PushFlags nFlags = vcl::PushFlags::NONE;
69
0
    nFlags |= vcl::PushFlags::CLIPREGION;
70
0
    nFlags |= vcl::PushFlags::FILLCOLOR;
71
0
    nFlags |= vcl::PushFlags::FONT;
72
0
    nFlags |= vcl::PushFlags::LINECOLOR;
73
0
    nFlags |= vcl::PushFlags::MAPMODE;
74
0
    maSettings = pFrameData->mpBuffer->GetSettings();
75
0
    nFlags |= vcl::PushFlags::REFPOINT;
76
0
    nFlags |= vcl::PushFlags::TEXTCOLOR;
77
0
    nFlags |= vcl::PushFlags::TEXTLINECOLOR;
78
0
    nFlags |= vcl::PushFlags::OVERLINECOLOR;
79
0
    nFlags |= vcl::PushFlags::TEXTFILLCOLOR;
80
0
    nFlags |= vcl::PushFlags::TEXTALIGN;
81
0
    nFlags |= vcl::PushFlags::RASTEROP;
82
0
    nFlags |= vcl::PushFlags::TEXTLAYOUTMODE;
83
0
    nFlags |= vcl::PushFlags::TEXTLANGUAGE;
84
0
    pFrameData->mpBuffer->Push(nFlags);
85
0
    auto& rDev = *pWindow->GetOutDev();
86
0
    pFrameData->mpBuffer->SetClipRegion(rDev.GetClipRegion());
87
0
    pFrameData->mpBuffer->SetFillColor(rDev.GetFillColor());
88
0
    pFrameData->mpBuffer->SetFont(pWindow->GetFont());
89
0
    if (!rDev.HasAlpha() && rDev.GetLineColor() == COL_TRANSPARENT)
90
0
        pFrameData->mpBuffer->SetLineColor();
91
0
    else
92
0
        pFrameData->mpBuffer->SetLineColor(rDev.GetLineColor());
93
0
    pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
94
0
    pFrameData->mpBuffer->SetRefPoint(rDev.GetRefPoint());
95
0
    pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
96
0
    pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
97
0
    pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
98
0
    pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
99
0
    pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
100
0
    pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
101
0
    pFrameData->mpBuffer->SetRasterOp(rDev.GetRasterOp());
102
0
    pFrameData->mpBuffer->SetLayoutMode(rDev.GetLayoutMode());
103
0
    pFrameData->mpBuffer->SetDigitLanguage(rDev.GetDigitLanguage());
104
105
0
    mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
106
0
    mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
107
0
    pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
108
0
    pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
109
0
    pFrameData->mpBuffer->EnableRTL(pWindow->IsRTLEnabled());
110
0
}
111
112
PaintBufferGuard::~PaintBufferGuard()
113
0
{
114
0
    if (!mpFrameData->mpBuffer)
115
0
        return;
116
117
0
    if (!m_aPaintRect.IsEmpty())
118
0
    {
119
        // copy the buffer content to the actual window
120
        // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are
121
        // painting directly instead of using Invalidate()
122
        // [ie. everything you can see was painted directly to the
123
        // window either above or in eg. an event handler]
124
0
        if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT"))
125
0
        {
126
            // Make sure that the +1 value GetSize() adds to the size is in pixels.
127
0
            Size aPaintRectSize;
128
0
            if (m_pWindow->GetMapMode().GetMapUnit() == MapUnit::MapPixel)
129
0
            {
130
0
                aPaintRectSize = m_aPaintRect.GetSize();
131
0
            }
132
0
            else
133
0
            {
134
0
                tools::Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
135
0
                aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
136
0
            }
137
138
0
            m_pWindow->GetOutDev()->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer);
139
0
        }
140
0
    }
141
142
    // Restore buffer state.
143
0
    mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
144
0
    mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
145
146
0
    mpFrameData->mpBuffer->Pop();
147
0
    mpFrameData->mpBuffer->SetSettings(maSettings);
148
0
    if (mbBackground)
149
0
        mpFrameData->mpBuffer->SetBackground(maBackground);
150
0
    else
151
0
        mpFrameData->mpBuffer->SetBackground();
152
0
}
153
154
void PaintBufferGuard::SetPaintRect(const tools::Rectangle& rRectangle)
155
0
{
156
0
    m_aPaintRect = rRectangle;
157
0
}
158
159
vcl::RenderContext* PaintBufferGuard::GetRenderContext()
160
0
{
161
0
    if (mpFrameData->mpBuffer)
162
0
        return mpFrameData->mpBuffer;
163
0
    else
164
0
        return m_pWindow->GetOutDev();
165
0
}
166
}
167
168
class PaintHelper
169
{
170
private:
171
    VclPtr<vcl::Window> m_pWindow;
172
    std::unique_ptr<vcl::Region> m_pChildRegion;
173
    tools::Rectangle m_aSelectionRect;
174
    tools::Rectangle m_aPaintRect;
175
    vcl::Region m_aPaintRegion;
176
    ImplPaintFlags m_nPaintFlags;
177
    bool m_bPop : 1;
178
    bool m_bRestoreCursor : 1;
179
    bool m_bStartedBufferedPaint : 1; ///< This PaintHelper started a buffered paint, and should paint it on the screen when being destructed.
180
public:
181
    PaintHelper(vcl::Window* pWindow, ImplPaintFlags nPaintFlags);
182
    void SetPop()
183
0
    {
184
0
        m_bPop = true;
185
0
    }
186
    void SetPaintRect(const tools::Rectangle& rRect)
187
0
    {
188
0
        m_aPaintRect = rRect;
189
0
    }
190
    void SetSelectionRect(const tools::Rectangle& rRect)
191
0
    {
192
0
        m_aSelectionRect = rRect;
193
0
    }
194
    void SetRestoreCursor(bool bRestoreCursor)
195
0
    {
196
0
        m_bRestoreCursor = bRestoreCursor;
197
0
    }
198
    bool GetRestoreCursor() const
199
0
    {
200
0
        return m_bRestoreCursor;
201
0
    }
202
    ImplPaintFlags GetPaintFlags() const
203
0
    {
204
0
        return m_nPaintFlags;
205
0
    }
206
    vcl::Region& GetPaintRegion()
207
0
    {
208
0
        return m_aPaintRegion;
209
0
    }
210
    void DoPaint(const vcl::Region* pRegion);
211
212
    /// Start buffered paint: set it up to have the same settings as m_pWindow.
213
    void StartBufferedPaint();
214
215
    /// Paint the content of the buffer to the current m_pWindow.
216
    void PaintBuffer();
217
218
    ~PaintHelper();
219
};
220
221
PaintHelper::PaintHelper(vcl::Window *pWindow, ImplPaintFlags nPaintFlags)
222
0
    : m_pWindow(pWindow)
223
0
    , m_nPaintFlags(nPaintFlags)
224
0
    , m_bPop(false)
225
0
    , m_bRestoreCursor(false)
226
0
    , m_bStartedBufferedPaint(false)
227
0
{
228
0
}
229
230
void PaintHelper::StartBufferedPaint()
231
0
{
232
0
    ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
233
0
    assert(!pFrameData->mbInBufferedPaint);
234
235
0
    pFrameData->mbInBufferedPaint = true;
236
0
    pFrameData->maBufferedRect = tools::Rectangle();
237
0
    m_bStartedBufferedPaint = true;
238
0
}
239
240
void PaintHelper::PaintBuffer()
241
0
{
242
0
    ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
243
0
    assert(pFrameData->mbInBufferedPaint);
244
0
    assert(m_bStartedBufferedPaint);
245
246
0
    vcl::PaintBufferGuard aGuard(pFrameData, m_pWindow);
247
0
    aGuard.SetPaintRect(pFrameData->maBufferedRect);
248
0
}
249
250
void PaintHelper::DoPaint(const vcl::Region* pRegion)
251
0
{
252
0
    WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
253
254
0
    vcl::Region& rWinChildClipRegion = m_pWindow->ImplGetWinChildClipRegion();
255
0
    ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
256
0
    if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll || pFrameData->mbInBufferedPaint)
257
0
    {
258
0
        pWindowImpl->maInvalidateRegion = rWinChildClipRegion;
259
0
    }
260
0
    else
261
0
    {
262
0
        if (pRegion)
263
0
            pWindowImpl->maInvalidateRegion.Union( *pRegion );
264
265
0
        if (pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible)
266
            /* #98602# need to repaint all children within the
267
           * tracking rectangle, so the following invert
268
           * operation takes places without traces of the previous
269
           * one.
270
           */
271
0
           pWindowImpl->maInvalidateRegion.Union(*pWindowImpl->mpWinData->mpTrackRect);
272
273
0
        if (pWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren)
274
0
            m_pChildRegion.reset( new vcl::Region(pWindowImpl->maInvalidateRegion) );
275
0
        pWindowImpl->maInvalidateRegion.Intersect(rWinChildClipRegion);
276
0
    }
277
0
    pWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
278
0
    if (pWindowImpl->maInvalidateRegion.IsEmpty())
279
0
        return;
280
281
#if HAVE_FEATURE_OPENGL
282
    VCL_GL_INFO("PaintHelper::DoPaint on " <<
283
                typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "' begin");
284
#endif
285
    // double-buffering: setup the buffer if it does not exist
286
0
    if (!pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
287
0
        StartBufferedPaint();
288
289
    // double-buffering: if this window does not support double-buffering,
290
    // but we are in the middle of double-buffered paint, we might be
291
    // losing information
292
0
    if (pFrameData->mbInBufferedPaint && !m_pWindow->SupportsDoubleBuffering())
293
0
        SAL_WARN("vcl.window", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(*m_pWindow.get()).name());
294
295
0
    if (pFrameData->mbInBufferedPaint && m_pWindow->SupportsDoubleBuffering())
296
0
    {
297
        // double-buffering
298
0
        vcl::PaintBufferGuard g(pFrameData, m_pWindow);
299
0
        m_pWindow->ApplySettings(*pFrameData->mpBuffer);
300
301
0
        m_pWindow->PushPaintHelper(this, *pFrameData->mpBuffer);
302
0
        m_pWindow->Paint(*pFrameData->mpBuffer, m_aPaintRect);
303
0
        pFrameData->maBufferedRect.Union(m_aPaintRect);
304
0
    }
305
0
    else
306
0
    {
307
        // direct painting
308
0
        Wallpaper aBackground = m_pWindow->GetBackground();
309
0
        m_pWindow->ApplySettings(*m_pWindow->GetOutDev());
310
        // Restore bitmap background if it was lost.
311
0
        if (aBackground.IsBitmap() && !m_pWindow->GetBackground().IsBitmap())
312
0
        {
313
0
            m_pWindow->SetBackground(aBackground);
314
0
        }
315
0
        m_pWindow->PushPaintHelper(this, *m_pWindow->GetOutDev());
316
0
        m_pWindow->Paint(*m_pWindow->GetOutDev(), m_aPaintRect);
317
0
    }
318
#if HAVE_FEATURE_OPENGL
319
    VCL_GL_INFO("PaintHelper::DoPaint end on " <<
320
                typeid( *m_pWindow ).name() << " '" << m_pWindow->GetText() << "'");
321
#endif
322
0
}
323
324
namespace vcl
325
{
326
327
void RenderTools::DrawSelectionBackground(vcl::RenderContext& rRenderContext, vcl::Window const & rWindow,
328
                                          const tools::Rectangle& rRect, sal_uInt16 nHighlight,
329
                                          bool bChecked, bool bDrawBorder, bool bDrawExtBorderOnly,
330
                                          Color* pSelectionTextColor, tools::Long nCornerRadius, Color const * pPaintColor)
331
0
{
332
0
    if (rRect.IsEmpty())
333
0
        return;
334
335
0
    bool bRoundEdges = nCornerRadius > 0;
336
337
0
    const StyleSettings& rStyles = rRenderContext.GetSettings().GetStyleSettings();
338
339
    // colors used for item highlighting
340
0
    Color aSelectionBorderColor(pPaintColor ? *pPaintColor : rStyles.GetHighlightColor());
341
0
    Color aSelectionFillColor(aSelectionBorderColor);
342
343
0
    bool bDark = rStyles.GetFaceColor().IsDark();
344
0
    bool bBright = ( rStyles.GetFaceColor() == COL_WHITE );
345
346
0
    int c1 = aSelectionBorderColor.GetLuminance();
347
0
    int c2 = rWindow.GetBackgroundColor().GetLuminance();
348
349
0
    if (!bDark && !bBright && std::abs(c2 - c1) < (pPaintColor ? 40 : 75))
350
0
    {
351
        // contrast too low
352
0
        sal_uInt16 h, s, b;
353
0
        aSelectionFillColor.RGBtoHSB( h, s, b );
354
0
        if( b > 50 )    b -= 40;
355
0
        else            b += 40;
356
0
        aSelectionFillColor = Color::HSBtoRGB( h, s, b );
357
0
        aSelectionBorderColor = aSelectionFillColor;
358
0
    }
359
360
0
    if (bRoundEdges)
361
0
    {
362
0
        if (aSelectionBorderColor.IsDark())
363
0
            aSelectionBorderColor.IncreaseLuminance(128);
364
0
        else
365
0
            aSelectionBorderColor.DecreaseLuminance(128);
366
0
    }
367
368
0
    tools::Rectangle aRect(rRect);
369
0
    if (bDrawExtBorderOnly)
370
0
    {
371
0
        aRect.AdjustLeft( -1 );
372
0
        aRect.AdjustTop( -1 );
373
0
        aRect.AdjustRight(1 );
374
0
        aRect.AdjustBottom(1 );
375
0
    }
376
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
377
378
0
    if (bDrawBorder)
379
0
        rRenderContext.SetLineColor(bDark ? COL_WHITE : (bBright ? COL_BLACK : aSelectionBorderColor));
380
0
    else
381
0
        rRenderContext.SetLineColor();
382
383
0
    sal_uInt16 nPercent = 0;
384
0
    if (!nHighlight)
385
0
    {
386
0
        if (bDark)
387
0
            aSelectionFillColor = COL_BLACK;
388
0
        else
389
0
            nPercent = 80;  // just checked (light)
390
0
    }
391
0
    else
392
0
    {
393
0
        if (bChecked && nHighlight == 2)
394
0
        {
395
0
            if (bDark)
396
0
                aSelectionFillColor = COL_LIGHTGRAY;
397
0
            else if (bBright)
398
0
            {
399
0
                aSelectionFillColor = COL_BLACK;
400
0
                rRenderContext.SetLineColor(COL_BLACK);
401
0
                nPercent = 0;
402
0
            }
403
0
            else
404
0
                nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark )
405
0
        }
406
0
        else if (bChecked || nHighlight == 1)
407
0
        {
408
0
            if (bDark)
409
0
                aSelectionFillColor = COL_GRAY;
410
0
            else if (bBright)
411
0
            {
412
0
                aSelectionFillColor = COL_BLACK;
413
0
                rRenderContext.SetLineColor(COL_BLACK);
414
0
                nPercent = 0;
415
0
            }
416
0
            else
417
0
                nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark )
418
0
        }
419
0
        else
420
0
        {
421
0
            if (bDark)
422
0
                aSelectionFillColor = COL_LIGHTGRAY;
423
0
            else if (bBright)
424
0
            {
425
0
                aSelectionFillColor = COL_BLACK;
426
0
                rRenderContext.SetLineColor(COL_BLACK);
427
0
                if (nHighlight == 3)
428
0
                    nPercent = 80;
429
0
                else
430
0
                    nPercent = 0;
431
0
            }
432
0
            else
433
0
                nPercent = 70; // selected ( dark )
434
0
        }
435
0
    }
436
437
0
    if (bDark && bDrawExtBorderOnly)
438
0
    {
439
0
        rRenderContext.SetFillColor();
440
0
        if (pSelectionTextColor)
441
0
            *pSelectionTextColor = rStyles.GetHighlightTextColor();
442
0
    }
443
0
    else
444
0
    {
445
0
        rRenderContext.SetFillColor(aSelectionFillColor);
446
0
        if (pSelectionTextColor)
447
0
        {
448
0
            Color aTextColor = rWindow.IsControlBackground() ? rWindow.GetControlForeground() : rStyles.GetButtonTextColor();
449
0
            Color aHLTextColor = rStyles.GetHighlightTextColor();
450
0
            int nTextDiff = std::abs(aSelectionFillColor.GetLuminance() - aTextColor.GetLuminance());
451
0
            int nHLDiff = std::abs(aSelectionFillColor.GetLuminance() - aHLTextColor.GetLuminance());
452
0
            *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor;
453
0
        }
454
0
    }
455
456
0
    if (bDark)
457
0
    {
458
0
        rRenderContext.DrawRect(aRect);
459
0
    }
460
0
    else
461
0
    {
462
0
        if (bRoundEdges)
463
0
        {
464
0
            tools::Polygon aPoly(aRect, nCornerRadius, nCornerRadius);
465
0
            tools::PolyPolygon aPolyPoly(aPoly);
466
0
            rRenderContext.DrawTransparent(aPolyPoly, nPercent);
467
0
        }
468
0
        else
469
0
        {
470
0
            tools::Polygon aPoly(aRect);
471
0
            tools::PolyPolygon aPolyPoly(aPoly);
472
0
            rRenderContext.DrawTransparent(aPolyPoly, nPercent);
473
0
        }
474
0
    }
475
0
}
476
477
void Window::PushPaintHelper(PaintHelper *pHelper, vcl::RenderContext& rRenderContext)
478
0
{
479
0
    pHelper->SetPop();
480
481
0
    if ( mpWindowImpl->mpCursor )
482
0
        pHelper->SetRestoreCursor(mpWindowImpl->mpCursor->ImplSuspend());
483
484
0
    GetOutDev()->mbInitClipRegion = true;
485
0
    mpWindowImpl->mbInPaint = true;
486
487
    // restore Paint-Region
488
0
    vcl::Region &rPaintRegion = pHelper->GetPaintRegion();
489
0
    rPaintRegion = mpWindowImpl->maInvalidateRegion;
490
0
    tools::Rectangle aPaintRect = rPaintRegion.GetBoundRect();
491
492
    // RTL: re-mirror paint rect and region at this window
493
0
    if (GetOutDev()->ImplIsAntiparallel())
494
0
    {
495
0
        rRenderContext.ReMirror(aPaintRect);
496
0
        rRenderContext.ReMirror(rPaintRegion);
497
0
    }
498
0
    aPaintRect = GetOutDev()->ImplDevicePixelToLogic(aPaintRect);
499
0
    mpWindowImpl->mpPaintRegion = &rPaintRegion;
500
0
    mpWindowImpl->maInvalidateRegion.SetEmpty();
501
502
0
    if ((pHelper->GetPaintFlags() & ImplPaintFlags::Erase) && rRenderContext.IsBackground())
503
0
    {
504
0
        if (rRenderContext.IsClipRegion())
505
0
        {
506
0
            vcl::Region aOldRegion = rRenderContext.GetClipRegion();
507
0
            rRenderContext.SetClipRegion();
508
0
            Erase(rRenderContext);
509
0
            rRenderContext.SetClipRegion(aOldRegion);
510
0
        }
511
0
        else
512
0
            Erase(rRenderContext);
513
0
    }
514
515
    // #98943# trigger drawing of toolbox selection after all children are painted
516
0
    if (mpWindowImpl->mbDrawSelectionBackground)
517
0
        pHelper->SetSelectionRect(aPaintRect);
518
0
    pHelper->SetPaintRect(aPaintRect);
519
0
}
520
521
void Window::PopPaintHelper(PaintHelper const *pHelper)
522
0
{
523
0
    if (mpWindowImpl->mpWinData)
524
0
    {
525
0
        if (mpWindowImpl->mbFocusVisible)
526
0
            ImplInvertFocus(*mpWindowImpl->mpWinData->mpFocusRect);
527
0
    }
528
0
    mpWindowImpl->mbInPaint = false;
529
0
    GetOutDev()->mbInitClipRegion = true;
530
0
    mpWindowImpl->mpPaintRegion = nullptr;
531
0
    if (mpWindowImpl->mpCursor)
532
0
        mpWindowImpl->mpCursor->ImplResume(pHelper->GetRestoreCursor());
533
0
}
534
535
} /* namespace vcl */
536
537
PaintHelper::~PaintHelper()
538
0
{
539
0
    WindowImpl* pWindowImpl = m_pWindow->ImplGetWindowImpl();
540
0
    if (m_bPop)
541
0
    {
542
0
        m_pWindow->PopPaintHelper(this);
543
0
    }
544
545
0
    ImplFrameData* pFrameData = m_pWindow->mpWindowImpl->mpFrameData;
546
0
    if ( m_nPaintFlags & (ImplPaintFlags::PaintAllChildren | ImplPaintFlags::PaintChildren) )
547
0
    {
548
        // Paint from the bottom child window and frontward.
549
0
        vcl::Window* pTempWindow = pWindowImpl->mpLastChild;
550
0
        while (pTempWindow)
551
0
        {
552
0
            if (pTempWindow->mpWindowImpl->mbVisible)
553
0
                pTempWindow->ImplCallPaint(m_pChildRegion.get(), m_nPaintFlags);
554
0
            pTempWindow = pTempWindow->mpWindowImpl->mpPrev;
555
0
        }
556
0
    }
557
558
0
    if ( pWindowImpl->mpWinData && pWindowImpl->mbTrackVisible && (pWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
559
        /* #98602# need to invert the tracking rect AFTER
560
        * the children have painted
561
        */
562
0
        m_pWindow->InvertTracking( *pWindowImpl->mpWinData->mpTrackRect, pWindowImpl->mpWinData->mnTrackFlags );
563
564
    // double-buffering: paint in case we created the buffer, the children are
565
    // already painted inside
566
0
    if (m_bStartedBufferedPaint && pFrameData->mbInBufferedPaint)
567
0
    {
568
0
        PaintBuffer();
569
0
        pFrameData->mbInBufferedPaint = false;
570
0
        pFrameData->maBufferedRect = tools::Rectangle();
571
0
    }
572
573
    // #98943# draw toolbox selection
574
0
    if( !m_aSelectionRect.IsEmpty() )
575
0
        m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true );
576
0
}
577
578
namespace vcl {
579
580
void Window::ImplCallPaint(const vcl::Region* pRegion, ImplPaintFlags nPaintFlags)
581
0
{
582
    // call PrePaint. PrePaint may add to the invalidate region as well as
583
    // other parameters used below.
584
0
    PrePaint(*GetOutDev());
585
586
0
    mpWindowImpl->mbPaintFrame = false;
587
588
0
    if (nPaintFlags & ImplPaintFlags::PaintAllChildren)
589
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint | ImplPaintFlags::PaintAllChildren | (nPaintFlags & ImplPaintFlags::PaintAll);
590
0
    if (nPaintFlags & ImplPaintFlags::PaintChildren)
591
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren;
592
0
    if (nPaintFlags & ImplPaintFlags::Erase)
593
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
594
0
    if (nPaintFlags & ImplPaintFlags::CheckRtl)
595
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
596
0
    if (!mpWindowImpl->mpFirstChild)
597
0
        mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAllChildren;
598
599
    // If tiled rendering is used, windows are only invalidated, never painted to.
600
0
    if (mpWindowImpl->mbPaintDisabled || comphelper::LibreOfficeKit::isActive())
601
0
    {
602
0
        if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll)
603
0
            Invalidate(InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
604
0
        else if ( pRegion )
605
0
            Invalidate(*pRegion, InvalidateFlags::NoChildren | InvalidateFlags::NoErase | InvalidateFlags::NoTransparent | InvalidateFlags::NoClipChildren);
606
607
        // call PostPaint before returning
608
0
        PostPaint(*GetOutDev());
609
610
0
        return;
611
0
    }
612
613
0
    nPaintFlags = mpWindowImpl->mnPaintFlags & ~ImplPaintFlags::Paint;
614
615
0
    PaintHelper aHelper(this, nPaintFlags);
616
617
0
    if (mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint)
618
0
        aHelper.DoPaint(pRegion);
619
0
    else
620
0
        mpWindowImpl->mnPaintFlags = ImplPaintFlags::NONE;
621
622
    // call PostPaint
623
0
    PostPaint(*GetOutDev());
624
0
}
625
626
void Window::ImplCallOverlapPaint()
627
0
{
628
0
    if (!mpWindowImpl)
629
0
        return;
630
631
    // emit overlapping windows first
632
0
    vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
633
0
    while ( pTempWindow )
634
0
    {
635
0
        if ( pTempWindow->mpWindowImpl->mbReallyVisible )
636
0
            pTempWindow->ImplCallOverlapPaint();
637
0
        pTempWindow = pTempWindow->mpWindowImpl->mpNext;
638
0
    }
639
640
    // only then ourself
641
0
    if ( mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
642
0
    {
643
        // RTL: notify ImplCallPaint to check for re-mirroring
644
        // because we were called from the Sal layer
645
0
        ImplCallPaint(nullptr, mpWindowImpl->mnPaintFlags /*| ImplPaintFlags::CheckRtl */);
646
0
    }
647
0
}
648
649
IMPL_LINK_NOARG(Window, ImplHandlePaintHdl, Timer *, void)
650
0
{
651
0
    comphelper::ProfileZone aZone("VCL idle re-paint");
652
653
    // save paint events until layout is done
654
0
    if (IsSystemWindow() && static_cast<const SystemWindow*>(this)->hasPendingLayout())
655
0
    {
656
0
        mpWindowImpl->mpFrameData->maPaintIdle.Start();
657
0
        return;
658
0
    }
659
660
    // save paint events until resizing or initial sizing done
661
0
    if (mpWindowImpl->mbFrame &&
662
0
        mpWindowImpl->mpFrameData->maResizeIdle.IsActive())
663
0
    {
664
0
        mpWindowImpl->mpFrameData->maPaintIdle.Start();
665
0
    }
666
0
    else if ( mpWindowImpl->mbReallyVisible )
667
0
    {
668
0
        ImplCallOverlapPaint();
669
0
        if (comphelper::LibreOfficeKit::isActive() &&
670
0
            mpWindowImpl->mpFrameData->maPaintIdle.IsActive())
671
0
            mpWindowImpl->mpFrameData->maPaintIdle.Stop();
672
0
    }
673
0
}
674
675
IMPL_LINK_NOARG(Window, ImplHandleResizeTimerHdl, Timer *, void)
676
0
{
677
0
    comphelper::ProfileZone aZone("VCL idle resize");
678
679
0
    if( mpWindowImpl->mbReallyVisible )
680
0
    {
681
0
        ImplCallResize();
682
0
        if( mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
683
0
        {
684
0
            mpWindowImpl->mpFrameData->maPaintIdle.Stop();
685
0
            mpWindowImpl->mpFrameData->maPaintIdle.Invoke( nullptr );
686
0
        }
687
0
    }
688
0
}
689
690
void Window::ImplInvalidateFrameRegion( const vcl::Region* pRegion, InvalidateFlags nFlags )
691
0
{
692
    // set PAINTCHILDREN for all parent windows till the first OverlapWindow
693
0
    if ( !ImplIsOverlapWindow() )
694
0
    {
695
0
        vcl::Window* pTempWindow = this;
696
0
        ImplPaintFlags nTranspPaint = IsPaintTransparent() ? ImplPaintFlags::Paint : ImplPaintFlags::NONE;
697
0
        do
698
0
        {
699
0
            pTempWindow = pTempWindow->ImplGetParent();
700
0
            if ( pTempWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren )
701
0
                break;
702
0
            pTempWindow->mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintChildren | nTranspPaint;
703
0
            if( ! pTempWindow->IsPaintTransparent() )
704
0
                nTranspPaint = ImplPaintFlags::NONE;
705
0
        }
706
0
        while ( !pTempWindow->ImplIsOverlapWindow() );
707
0
    }
708
709
    // set Paint-Flags
710
0
    mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Paint;
711
0
    if ( nFlags & InvalidateFlags::Children )
712
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAllChildren;
713
0
    if ( !(nFlags & InvalidateFlags::NoErase) )
714
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::Erase;
715
716
0
    if ( !pRegion )
717
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::PaintAll;
718
0
    else if ( !(mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll) )
719
0
    {
720
        // if not everything has to be redrawn, add the region to it
721
0
        mpWindowImpl->maInvalidateRegion.Union( *pRegion );
722
0
    }
723
724
    // Handle transparent windows correctly: invalidate must be done on the first opaque parent
725
0
    if( ((IsPaintTransparent() && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
726
0
            && ImplGetParent() )
727
0
    {
728
0
        vcl::Window *pParent = ImplGetParent();
729
0
        while( pParent && pParent->IsPaintTransparent() )
730
0
            pParent = pParent->ImplGetParent();
731
0
        if( pParent )
732
0
        {
733
0
            vcl::Region *pChildRegion;
734
0
            if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
735
                // invalidate the whole child window region in the parent
736
0
                pChildRegion = &ImplGetWinChildClipRegion();
737
0
            else
738
                // invalidate the same region in the parent that has to be repainted in the child
739
0
                pChildRegion = &mpWindowImpl->maInvalidateRegion;
740
741
0
            nFlags |= InvalidateFlags::Children;  // paint should also be done on all children
742
0
            nFlags &= ~InvalidateFlags::NoErase;  // parent should paint and erase to create proper background
743
0
            pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags );
744
0
        }
745
0
    }
746
747
0
    if ( !mpWindowImpl->mpFrameData->maPaintIdle.IsActive() )
748
0
        mpWindowImpl->mpFrameData->maPaintIdle.Start();
749
0
}
750
751
void Window::ImplInvalidateOverlapFrameRegion( const vcl::Region& rRegion )
752
0
{
753
0
    vcl::Region aRegion = rRegion;
754
755
0
    ImplClipBoundaries( aRegion, true, true );
756
0
    if ( !aRegion.IsEmpty() )
757
0
        ImplInvalidateFrameRegion( &aRegion, InvalidateFlags::Children );
758
759
    // now we invalidate the overlapping windows
760
0
    vcl::Window* pTempWindow = mpWindowImpl->mpFirstOverlap;
761
0
    while ( pTempWindow )
762
0
    {
763
0
        if ( pTempWindow->IsVisible() )
764
0
            pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion );
765
766
0
        pTempWindow = pTempWindow->mpWindowImpl->mpNext;
767
0
    }
768
0
}
769
770
void Window::ImplInvalidateParentFrameRegion( const vcl::Region& rRegion )
771
0
{
772
0
    if ( mpWindowImpl->mbOverlapWin )
773
0
        mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion );
774
0
    else
775
0
    {
776
0
        if( ImplGetParent() )
777
0
            ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, InvalidateFlags::Children );
778
0
    }
779
0
}
780
781
void Window::ImplInvalidate( const vcl::Region* pRegion, InvalidateFlags nFlags )
782
0
{
783
    // check what has to be redrawn
784
0
    bool bInvalidateAll = !pRegion;
785
786
    // take Transparent-Invalidate into account
787
0
    vcl::Window* pOpaqueWindow = this;
788
0
    if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & InvalidateFlags::NoTransparent)) || (nFlags & InvalidateFlags::Transparent) )
789
0
    {
790
0
        vcl::Window* pTempWindow = pOpaqueWindow->ImplGetParent();
791
0
        while ( pTempWindow )
792
0
        {
793
0
            if ( !pTempWindow->IsPaintTransparent() )
794
0
            {
795
0
                pOpaqueWindow = pTempWindow;
796
0
                nFlags |= InvalidateFlags::Children;
797
0
                bInvalidateAll = false;
798
0
                break;
799
0
            }
800
801
0
            if ( pTempWindow->ImplIsOverlapWindow() )
802
0
                break;
803
804
0
            pTempWindow = pTempWindow->ImplGetParent();
805
0
        }
806
0
    }
807
808
    // assemble region
809
0
    InvalidateFlags nOrgFlags = nFlags;
810
0
    if ( !(nFlags & (InvalidateFlags::Children | InvalidateFlags::NoChildren)) )
811
0
    {
812
0
        if ( GetStyle() & WB_CLIPCHILDREN )
813
0
            nFlags |= InvalidateFlags::NoChildren;
814
0
        else
815
0
            nFlags |= InvalidateFlags::Children;
816
0
    }
817
0
    if ( (nFlags & InvalidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
818
0
        bInvalidateAll = false;
819
0
    if ( bInvalidateAll )
820
0
        ImplInvalidateFrameRegion( nullptr, nFlags );
821
0
    else
822
0
    {
823
0
        vcl::Region      aRegion( GetOutputRectPixel() );
824
0
        if ( pRegion )
825
0
        {
826
            // RTL: remirror region before intersecting it
827
0
            if ( GetOutDev()->ImplIsAntiparallel() )
828
0
            {
829
0
                const OutputDevice *pOutDev = GetOutDev();
830
831
0
                vcl::Region aRgn( *pRegion );
832
0
                pOutDev->ReMirror( aRgn );
833
0
                aRegion.Intersect( aRgn );
834
0
            }
835
0
            else
836
0
                aRegion.Intersect( *pRegion );
837
0
        }
838
0
        ImplClipBoundaries( aRegion, true, true );
839
0
        if ( nFlags & InvalidateFlags::NoChildren )
840
0
        {
841
0
            nFlags &= ~InvalidateFlags::Children;
842
0
            if ( !(nFlags & InvalidateFlags::NoClipChildren) )
843
0
            {
844
0
                if ( nOrgFlags & InvalidateFlags::NoChildren )
845
0
                    ImplClipAllChildren( aRegion );
846
0
                else
847
0
                {
848
0
                    if ( ImplClipChildren( aRegion ) )
849
0
                        nFlags |= InvalidateFlags::Children;
850
0
                }
851
0
            }
852
0
        }
853
0
        if ( !aRegion.IsEmpty() )
854
0
            ImplInvalidateFrameRegion( &aRegion, nFlags );  // transparency is handled here, pOpaqueWindow not required
855
0
    }
856
857
0
    if ( nFlags & InvalidateFlags::Update )
858
0
        pOpaqueWindow->PaintImmediately();        // start painting at the opaque parent
859
0
}
860
861
void Window::ImplMoveInvalidateRegion( const tools::Rectangle& rRect,
862
                                       tools::Long nHorzScroll, tools::Long nVertScroll,
863
                                       bool bChildren )
864
0
{
865
0
    if ( (mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintAll)) == ImplPaintFlags::Paint )
866
0
    {
867
0
        vcl::Region aTempRegion = mpWindowImpl->maInvalidateRegion;
868
0
        aTempRegion.Intersect( rRect );
869
0
        aTempRegion.Move( nHorzScroll, nVertScroll );
870
0
        mpWindowImpl->maInvalidateRegion.Union( aTempRegion );
871
0
    }
872
873
0
    if ( bChildren && (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintChildren) )
874
0
    {
875
0
        vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
876
0
        while ( pWindow )
877
0
        {
878
0
            pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, true );
879
0
            pWindow = pWindow->mpWindowImpl->mpNext;
880
0
        }
881
0
    }
882
0
}
883
884
void Window::ImplMoveAllInvalidateRegions( const tools::Rectangle& rRect,
885
                                           tools::Long nHorzScroll, tools::Long nVertScroll,
886
                                           bool bChildren )
887
0
{
888
    // also shift Paint-Region when paints need processing
889
0
    ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChildren );
890
    // Paint-Region should be shifted, as drawn by the parents
891
0
    if ( ImplIsOverlapWindow() )
892
0
        return;
893
894
0
    vcl::Region  aPaintAllRegion;
895
0
    vcl::Window* pPaintAllWindow = this;
896
0
    do
897
0
    {
898
0
        pPaintAllWindow = pPaintAllWindow->ImplGetParent();
899
0
        if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
900
0
        {
901
0
            if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
902
0
            {
903
0
                aPaintAllRegion.SetEmpty();
904
0
                break;
905
0
            }
906
0
            else
907
0
                aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion );
908
0
        }
909
0
    }
910
0
    while ( !pPaintAllWindow->ImplIsOverlapWindow() );
911
0
    if ( !aPaintAllRegion.IsEmpty() )
912
0
    {
913
0
        aPaintAllRegion.Move( nHorzScroll, nVertScroll );
914
0
        InvalidateFlags nPaintFlags = InvalidateFlags::NONE;
915
0
        if ( bChildren )
916
0
            nPaintFlags |= InvalidateFlags::Children;
917
0
        ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags );
918
0
    }
919
0
}
920
921
void Window::ImplValidateFrameRegion( const vcl::Region* pRegion, ValidateFlags nFlags )
922
0
{
923
0
    if ( !pRegion )
924
0
        mpWindowImpl->maInvalidateRegion.SetEmpty();
925
0
    else
926
0
    {
927
        // when all child windows have to be drawn we need to invalidate them before doing so
928
0
        if ( (mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren) && mpWindowImpl->mpFirstChild )
929
0
        {
930
0
            vcl::Region aChildRegion = mpWindowImpl->maInvalidateRegion;
931
0
            if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
932
0
            {
933
0
                aChildRegion = GetOutputRectPixel();
934
0
            }
935
0
            vcl::Window* pChild = mpWindowImpl->mpFirstChild;
936
0
            while ( pChild )
937
0
            {
938
0
                pChild->Invalidate( aChildRegion, InvalidateFlags::Children | InvalidateFlags::NoTransparent );
939
0
                pChild = pChild->mpWindowImpl->mpNext;
940
0
            }
941
0
        }
942
0
        if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAll )
943
0
        {
944
0
            mpWindowImpl->maInvalidateRegion = GetOutputRectPixel();
945
0
        }
946
0
        mpWindowImpl->maInvalidateRegion.Exclude( *pRegion );
947
0
    }
948
0
    mpWindowImpl->mnPaintFlags &= ~ImplPaintFlags::PaintAll;
949
950
0
    if ( nFlags & ValidateFlags::Children )
951
0
    {
952
0
        vcl::Window* pChild = mpWindowImpl->mpFirstChild;
953
0
        while ( pChild )
954
0
        {
955
0
            pChild->ImplValidateFrameRegion( pRegion, nFlags );
956
0
            pChild = pChild->mpWindowImpl->mpNext;
957
0
        }
958
0
    }
959
0
}
960
961
void Window::ImplValidate()
962
0
{
963
    // assemble region
964
0
    bool    bValidateAll = true;
965
0
    ValidateFlags nFlags = ValidateFlags::NONE;
966
0
    if ( GetStyle() & WB_CLIPCHILDREN )
967
0
        nFlags |= ValidateFlags::NoChildren;
968
0
    else
969
0
        nFlags |= ValidateFlags::Children;
970
0
    if ( (nFlags & ValidateFlags::NoChildren) && mpWindowImpl->mpFirstChild )
971
0
        bValidateAll = false;
972
0
    if ( bValidateAll )
973
0
        ImplValidateFrameRegion( nullptr, nFlags );
974
0
    else
975
0
    {
976
0
        vcl::Region      aRegion( GetOutputRectPixel() );
977
0
        ImplClipBoundaries( aRegion, true, true );
978
0
        if ( nFlags & ValidateFlags::NoChildren )
979
0
        {
980
0
            nFlags &= ~ValidateFlags::Children;
981
0
            if ( ImplClipChildren( aRegion ) )
982
0
                nFlags |= ValidateFlags::Children;
983
0
        }
984
0
        if ( !aRegion.IsEmpty() )
985
0
            ImplValidateFrameRegion( &aRegion, nFlags );
986
0
    }
987
0
}
988
989
void Window::ImplUpdateAll()
990
0
{
991
0
    if ( !mpWindowImpl || !mpWindowImpl->mbReallyVisible )
992
0
        return;
993
994
0
    bool bFlush = false;
995
0
    if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
996
0
    {
997
0
        Point aPoint( 0, 0 );
998
0
        vcl::Region aRegion( tools::Rectangle( aPoint, GetOutputSizePixel() ) );
999
0
        ImplInvalidateOverlapFrameRegion( aRegion );
1000
0
        if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1001
0
            bFlush = true;
1002
0
    }
1003
1004
    // an update changes the OverlapWindow, such that for later paints
1005
    // not too much has to be drawn, if ALLCHILDREN etc. is set
1006
0
    vcl::Window* pWindow = ImplGetFirstOverlapWindow();
1007
0
    pWindow->ImplCallOverlapPaint();
1008
1009
0
    if ( bFlush )
1010
0
        GetOutDev()->Flush();
1011
0
}
1012
1013
void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/)
1014
0
{
1015
0
}
1016
1017
void Window::PostPaint(vcl::RenderContext& /*rRenderContext*/)
1018
0
{
1019
0
}
1020
1021
void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect)
1022
0
{
1023
0
    CallEventListeners(VclEventId::WindowPaint, const_cast<tools::Rectangle *>(&rRect));
1024
0
}
1025
1026
void Window::SetPaintTransparent( bool bTransparent )
1027
0
{
1028
    // transparency is not useful for frames as the background would have to be provided by a different frame
1029
0
    if( bTransparent && mpWindowImpl->mbFrame )
1030
0
        return;
1031
1032
0
    if ( mpWindowImpl->mpBorderWindow )
1033
0
        mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent );
1034
1035
0
    mpWindowImpl->mbPaintTransparent = bTransparent;
1036
0
}
1037
1038
void Window::SetWindowRegionPixel()
1039
0
{
1040
1041
0
    if ( mpWindowImpl->mpBorderWindow )
1042
0
        mpWindowImpl->mpBorderWindow->SetWindowRegionPixel();
1043
0
    else if( mpWindowImpl->mbFrame )
1044
0
    {
1045
0
        mpWindowImpl->maWinRegion = vcl::Region(true);
1046
0
        mpWindowImpl->mbWinRegion = false;
1047
0
        mpWindowImpl->mpFrame->ResetClipRegion();
1048
0
    }
1049
0
    else
1050
0
    {
1051
0
        if ( mpWindowImpl->mbWinRegion )
1052
0
        {
1053
0
            mpWindowImpl->maWinRegion = vcl::Region(true);
1054
0
            mpWindowImpl->mbWinRegion = false;
1055
0
            ImplSetClipFlag();
1056
1057
0
            if ( IsReallyVisible() )
1058
0
            {
1059
0
                vcl::Region      aRegion( GetOutputRectPixel() );
1060
0
                ImplInvalidateParentFrameRegion( aRegion );
1061
0
            }
1062
0
        }
1063
0
    }
1064
0
}
1065
1066
void Window::SetWindowRegionPixel( const vcl::Region& rRegion )
1067
0
{
1068
1069
0
    if ( mpWindowImpl->mpBorderWindow )
1070
0
        mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion );
1071
0
    else if( mpWindowImpl->mbFrame )
1072
0
    {
1073
0
        if( !rRegion.IsNull() )
1074
0
        {
1075
0
            mpWindowImpl->maWinRegion = rRegion;
1076
0
            mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty();
1077
1078
0
            if( mpWindowImpl->mbWinRegion )
1079
0
            {
1080
                // set/update ClipRegion
1081
0
                RectangleVector aRectangles;
1082
0
                mpWindowImpl->maWinRegion.GetRegionRectangles(aRectangles);
1083
0
                mpWindowImpl->mpFrame->BeginSetClipRegion(aRectangles.size());
1084
1085
0
                for (auto const& rectangle : aRectangles)
1086
0
                {
1087
0
                    mpWindowImpl->mpFrame->UnionClipRegion(
1088
0
                        rectangle.Left(),
1089
0
                        rectangle.Top(),
1090
0
                        rectangle.GetWidth(),       // orig nWidth was ((R - L) + 1), same as GetWidth does
1091
0
                        rectangle.GetHeight());     // same for height
1092
0
                }
1093
1094
0
                mpWindowImpl->mpFrame->EndSetClipRegion();
1095
0
            }
1096
0
            else
1097
0
                SetWindowRegionPixel();
1098
0
        }
1099
0
        else
1100
0
            SetWindowRegionPixel();
1101
0
    }
1102
0
    else
1103
0
    {
1104
0
        if ( rRegion.IsNull() )
1105
0
        {
1106
0
            if ( mpWindowImpl->mbWinRegion )
1107
0
            {
1108
0
                mpWindowImpl->maWinRegion = vcl::Region(true);
1109
0
                mpWindowImpl->mbWinRegion = false;
1110
0
                ImplSetClipFlag();
1111
0
            }
1112
0
        }
1113
0
        else
1114
0
        {
1115
0
            mpWindowImpl->maWinRegion = rRegion;
1116
0
            mpWindowImpl->mbWinRegion = true;
1117
0
            ImplSetClipFlag();
1118
0
        }
1119
1120
0
        if ( IsReallyVisible() )
1121
0
        {
1122
0
            vcl::Region      aRegion( GetOutputRectPixel() );
1123
0
            ImplInvalidateParentFrameRegion( aRegion );
1124
0
        }
1125
0
    }
1126
0
}
1127
1128
vcl::Region Window::GetPaintRegion() const
1129
0
{
1130
1131
0
    if ( mpWindowImpl->mpPaintRegion )
1132
0
    {
1133
0
        vcl::Region aRegion = *mpWindowImpl->mpPaintRegion;
1134
0
        aRegion.Move( -GetOutDev()->mnOutOffX, -GetOutDev()->mnOutOffY );
1135
0
        return PixelToLogic( aRegion );
1136
0
    }
1137
0
    else
1138
0
    {
1139
0
        vcl::Region aPaintRegion(true);
1140
0
        return aPaintRegion;
1141
0
    }
1142
0
}
1143
1144
void Window::Invalidate( InvalidateFlags nFlags )
1145
113k
{
1146
113k
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1147
113k
        return;
1148
1149
0
    if (!mpWindowImpl)
1150
0
    {
1151
        // ImplInvalidate() would dereference mpWindowImpl unconditionally.
1152
0
        return;
1153
0
    }
1154
1155
0
    ImplInvalidate( nullptr, nFlags );
1156
0
    LogicInvalidate(nullptr);
1157
0
}
1158
1159
void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1160
18.4k
{
1161
18.4k
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1162
18.4k
        return;
1163
1164
0
    OutputDevice *pOutDev = GetOutDev();
1165
0
    tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1166
0
    if ( !aRect.IsEmpty() )
1167
0
    {
1168
0
        vcl::Region aRegion( aRect );
1169
0
        ImplInvalidate( &aRegion, nFlags );
1170
0
        tools::Rectangle aLogicRectangle(rRect);
1171
0
        LogicInvalidate(&aLogicRectangle);
1172
0
    }
1173
0
}
1174
1175
void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1176
0
{
1177
0
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1178
0
        return;
1179
1180
0
    if ( rRegion.IsNull() )
1181
0
    {
1182
0
        ImplInvalidate( nullptr, nFlags );
1183
0
        LogicInvalidate(nullptr);
1184
0
    }
1185
0
    else
1186
0
    {
1187
0
        vcl::Region aRegion = GetOutDev()->ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1188
0
        if ( !aRegion.IsEmpty() )
1189
0
        {
1190
0
            ImplInvalidate( &aRegion, nFlags );
1191
0
            tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1192
0
            LogicInvalidate(&aLogicRectangle);
1193
0
        }
1194
0
    }
1195
0
}
1196
1197
void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1198
0
{
1199
0
    if(pRectangle)
1200
0
    {
1201
0
        tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1202
0
        PixelInvalidate(&aRect);
1203
0
    }
1204
0
    else
1205
0
        PixelInvalidate(nullptr);
1206
0
}
1207
1208
bool Window::InvalidateByForeignEditView(EditView* )
1209
0
{
1210
0
    return false;
1211
0
}
1212
1213
void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1214
0
{
1215
0
    if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1216
0
        return;
1217
1218
0
    Size aSize = GetSizePixel();
1219
0
    if (aSize.IsEmpty())
1220
0
        return;
1221
1222
0
    if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1223
0
    {
1224
        // In case we are routing the window, notify the client
1225
0
        std::vector<vcl::LOKPayloadItem> aPayload;
1226
0
        tools::Rectangle aRect(Point(0, 0), aSize);
1227
0
        if (pRectangle)
1228
0
            aRect = *pRectangle;
1229
1230
0
        if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
1231
0
            GetOutDev()->ReMirror(aRect);
1232
1233
0
        aPayload.emplace_back("rectangle", aRect.toString());
1234
1235
0
        pNotifier->notifyWindow(GetLOKWindowId(), u"invalidate"_ustr, aPayload);
1236
0
    }
1237
0
    else if (GetParent() && GetParent()->IsFormControl())
1238
0
    {
1239
0
        const VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
1240
0
        if (pParent)
1241
0
            pParent->GetLOKNotifier()->notifyInvalidation(pRectangle);
1242
0
    }
1243
    // Added for dialog items. Pass invalidation to the parent window.
1244
0
    else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1245
0
    {
1246
0
        const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1247
0
        pParent->PixelInvalidate(&aRect);
1248
0
    }
1249
0
}
1250
1251
void Window::Validate()
1252
0
{
1253
0
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1254
0
        return;
1255
1256
0
    ImplValidate();
1257
0
}
1258
1259
bool Window::HasPaintEvent() const
1260
0
{
1261
0
    if (!mpWindowImpl)
1262
0
        return false;
1263
1264
0
    if ( !mpWindowImpl->mbReallyVisible )
1265
0
        return false;
1266
1267
0
    if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1268
0
        return true;
1269
1270
0
    if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1271
0
        return true;
1272
1273
0
    if ( !ImplIsOverlapWindow() )
1274
0
    {
1275
0
        const vcl::Window* pTempWindow = this;
1276
0
        do
1277
0
        {
1278
0
            pTempWindow = pTempWindow->ImplGetParent();
1279
0
            if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1280
0
                return true;
1281
0
        }
1282
0
        while ( !pTempWindow->ImplIsOverlapWindow() );
1283
0
    }
1284
1285
0
    return false;
1286
0
}
1287
1288
void Window::PaintImmediately()
1289
498
{
1290
498
    if (!mpWindowImpl)
1291
0
        return;
1292
1293
498
    if ( mpWindowImpl->mpBorderWindow )
1294
0
    {
1295
0
        mpWindowImpl->mpBorderWindow->PaintImmediately();
1296
0
        return;
1297
0
    }
1298
1299
498
    if ( !mpWindowImpl->mbReallyVisible )
1300
498
        return;
1301
1302
0
    bool bFlush = false;
1303
0
    if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1304
0
    {
1305
0
        Point aPoint( 0, 0 );
1306
0
        vcl::Region aRegion( tools::Rectangle( aPoint, GetOutputSizePixel() ) );
1307
0
        ImplInvalidateOverlapFrameRegion( aRegion );
1308
0
        if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1309
0
            bFlush = true;
1310
0
    }
1311
1312
    // First we should skip all windows which are Paint-Transparent
1313
0
    vcl::Window* pUpdateWindow = this;
1314
0
    vcl::Window* pWindow = pUpdateWindow;
1315
0
    while ( !pWindow->ImplIsOverlapWindow() )
1316
0
    {
1317
0
        if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1318
0
        {
1319
0
            pUpdateWindow = pWindow;
1320
0
            break;
1321
0
        }
1322
0
        pWindow = pWindow->ImplGetParent();
1323
0
    }
1324
    // In order to limit drawing, an update only draws the window which
1325
    // has PAINTALLCHILDREN set
1326
0
    pWindow = pUpdateWindow;
1327
0
    do
1328
0
    {
1329
0
        if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
1330
0
            pUpdateWindow = pWindow;
1331
0
        if ( pWindow->ImplIsOverlapWindow() )
1332
0
            break;
1333
0
        pWindow = pWindow->ImplGetParent();
1334
0
    }
1335
0
    while ( pWindow );
1336
1337
    // if there is something to paint, trigger a Paint
1338
0
    if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
1339
0
    {
1340
0
        VclPtr<vcl::Window> xWindow(this);
1341
1342
        // trigger an update also for system windows on top of us,
1343
        // otherwise holes would remain
1344
0
        vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow();
1345
0
        if (pUpdateOverlapWindow->mpWindowImpl)
1346
0
            pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpFirstOverlap;
1347
0
        else
1348
0
            pUpdateOverlapWindow = nullptr;
1349
0
        while ( pUpdateOverlapWindow )
1350
0
        {
1351
0
             pUpdateOverlapWindow->PaintImmediately();
1352
0
             pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1353
0
        }
1354
1355
0
        pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1356
1357
0
        if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1358
0
            pUpdateWindow->LogicInvalidate(nullptr);
1359
1360
0
        if (xWindow->isDisposed())
1361
0
           return;
1362
1363
0
        bFlush = true;
1364
0
    }
1365
1366
0
    if ( bFlush )
1367
0
        GetOutDev()->Flush();
1368
0
}
1369
1370
void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1371
0
{
1372
    // Special drawing when called through LOKit
1373
    // TODO: Move to its own method
1374
0
    if (comphelper::LibreOfficeKit::isActive())
1375
0
    {
1376
0
        VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1377
0
        pDevice->EnableRTL(IsRTLEnabled());
1378
1379
0
        Size aSize(GetOutputSizePixel());
1380
0
        pDevice->SetOutputSizePixel(aSize);
1381
1382
0
        vcl::Font aCopyFont = GetFont();
1383
0
        pDevice->SetFont(aCopyFont);
1384
1385
0
        pDevice->SetTextColor(GetTextColor());
1386
0
        if (GetOutDev()->IsLineColor())
1387
0
            pDevice->SetLineColor(GetOutDev()->GetLineColor());
1388
0
        else
1389
0
            pDevice->SetLineColor();
1390
1391
0
        if (GetOutDev()->IsFillColor())
1392
0
            pDevice->SetFillColor(GetOutDev()->GetFillColor());
1393
0
        else
1394
0
            pDevice->SetFillColor();
1395
1396
0
        if (IsTextLineColor())
1397
0
            pDevice->SetTextLineColor(GetTextLineColor());
1398
0
        else
1399
0
            pDevice->SetTextLineColor();
1400
1401
0
        if (IsOverlineColor())
1402
0
            pDevice->SetOverlineColor(GetOverlineColor());
1403
0
        else
1404
0
            pDevice->SetOverlineColor();
1405
1406
0
        if (IsTextFillColor())
1407
0
            pDevice->SetTextFillColor(GetTextFillColor());
1408
0
        else
1409
0
            pDevice->SetTextFillColor();
1410
1411
0
        pDevice->SetTextAlign(GetTextAlign());
1412
0
        pDevice->SetRasterOp(GetOutDev()->GetRasterOp());
1413
1414
0
        tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1415
1416
0
        vcl::Region aClipRegion(GetOutDev()->GetClipRegion());
1417
0
        pDevice->SetClipRegion();
1418
0
        aClipRegion.Intersect(aPaintRect);
1419
0
        pDevice->SetClipRegion(aClipRegion);
1420
1421
0
        if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1422
0
            Erase(*pDevice);
1423
1424
0
        pDevice->SetMapMode(GetMapMode());
1425
1426
0
        Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1427
1428
0
        i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1429
1430
0
        bool bHasMirroredGraphics = pDevice->HasMirroredGraphics();
1431
1432
        // get rid of virtual device now so they don't pile up during recursive calls
1433
0
        pDevice.disposeAndClear();
1434
1435
1436
0
        for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1437
0
        {
1438
0
            if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1439
0
            {
1440
0
                tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1441
0
                if( bHasMirroredGraphics )
1442
0
                    nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1443
1444
0
                tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1445
1446
0
                Point aPos( i_rPos );
1447
0
                aPos += Point(nDeltaX, nDeltaY);
1448
1449
0
                pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1450
0
            }
1451
0
        }
1452
0
        return;
1453
0
    }
1454
1455
1456
0
    bool bRVisible = mpWindowImpl->mbReallyVisible;
1457
0
    mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1458
0
    bool bDevOutput = GetOutDev()->mbDevOutput;
1459
0
    GetOutDev()->mbDevOutput = true;
1460
1461
0
    const OutputDevice *pOutDev = GetOutDev();
1462
0
    tools::Long nOldDPIX = pOutDev->GetDPIX();
1463
0
    tools::Long nOldDPIY = pOutDev->GetDPIY();
1464
0
    GetOutDev()->mnDPIX = i_pTargetOutDev->GetDPIX();
1465
0
    GetOutDev()->mnDPIY = i_pTargetOutDev->GetDPIY();
1466
0
    bool bOutput = GetOutDev()->IsOutputEnabled();
1467
0
    GetOutDev()->EnableOutput();
1468
1469
0
    SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1470
0
    if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1471
0
        return;
1472
1473
    // preserve graphicsstate
1474
0
    GetOutDev()->Push();
1475
0
    vcl::Region aClipRegion( GetOutDev()->GetClipRegion() );
1476
0
    GetOutDev()->SetClipRegion();
1477
1478
0
    GDIMetaFile* pOldMtf = GetOutDev()->GetConnectMetaFile();
1479
0
    GDIMetaFile aMtf;
1480
0
    GetOutDev()->SetConnectMetaFile( &aMtf );
1481
1482
    // put a push action to metafile
1483
0
    GetOutDev()->Push();
1484
    // copy graphics state to metafile
1485
0
    vcl::Font aCopyFont = GetFont();
1486
0
    if( nOldDPIX != GetOutDev()->mnDPIX || nOldDPIY != GetOutDev()->mnDPIY )
1487
0
    {
1488
0
        aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * GetOutDev()->mnDPIY / nOldDPIY );
1489
0
        aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * GetOutDev()->mnDPIX / nOldDPIX );
1490
0
    }
1491
0
    SetFont( aCopyFont );
1492
0
    SetTextColor( GetTextColor() );
1493
0
    if( GetOutDev()->IsLineColor() )
1494
0
        GetOutDev()->SetLineColor( GetOutDev()->GetLineColor() );
1495
0
    else
1496
0
        GetOutDev()->SetLineColor();
1497
0
    if( GetOutDev()->IsFillColor() )
1498
0
        GetOutDev()->SetFillColor( GetOutDev()->GetFillColor() );
1499
0
    else
1500
0
        GetOutDev()->SetFillColor();
1501
0
    if( IsTextLineColor() )
1502
0
        SetTextLineColor( GetTextLineColor() );
1503
0
    else
1504
0
        SetTextLineColor();
1505
0
    if( IsOverlineColor() )
1506
0
        SetOverlineColor( GetOverlineColor() );
1507
0
    else
1508
0
        SetOverlineColor();
1509
0
    if( IsTextFillColor() )
1510
0
        SetTextFillColor( GetTextFillColor() );
1511
0
    else
1512
0
        SetTextFillColor();
1513
0
    SetTextAlign( GetTextAlign() );
1514
0
    GetOutDev()->SetRasterOp( GetOutDev()->GetRasterOp() );
1515
0
    if( GetOutDev()->IsRefPoint() )
1516
0
        GetOutDev()->SetRefPoint( GetOutDev()->GetRefPoint() );
1517
0
    else
1518
0
        GetOutDev()->SetRefPoint();
1519
0
    GetOutDev()->SetLayoutMode( GetOutDev()->GetLayoutMode() );
1520
1521
0
    GetOutDev()->SetDigitLanguage( GetOutDev()->GetDigitLanguage() );
1522
0
    tools::Rectangle aPaintRect(Point(0, 0), GetOutputSizePixel());
1523
0
    aClipRegion.Intersect( aPaintRect );
1524
0
    GetOutDev()->SetClipRegion( aClipRegion );
1525
1526
    // do the actual paint
1527
1528
    // background
1529
0
    if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1530
0
    {
1531
0
        Erase(*GetOutDev());
1532
0
    }
1533
    // foreground
1534
0
    Paint(*GetOutDev(), aPaintRect);
1535
    // put a pop action to metafile
1536
0
    GetOutDev()->Pop();
1537
1538
0
    GetOutDev()->SetConnectMetaFile( pOldMtf );
1539
0
    GetOutDev()->EnableOutput( bOutput );
1540
0
    mpWindowImpl->mbReallyVisible = bRVisible;
1541
1542
    // paint metafile to VDev
1543
0
    VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1544
0
                                                DeviceFormat::WITH_ALPHA);
1545
1546
0
    pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel(), true, true );
1547
0
    pMaskedDevice->EnableRTL( IsRTLEnabled() );
1548
0
    aMtf.WindStart();
1549
0
    aMtf.Play(*pMaskedDevice);
1550
0
    Bitmap aBmpEx( pMaskedDevice->GetBitmap( Point( 0, 0 ), aPaintRect.GetSize() ) );
1551
0
    i_pTargetOutDev->DrawBitmap( i_rPos, aBmpEx );
1552
    // get rid of virtual device now so they don't pile up during recursive calls
1553
0
    pMaskedDevice.disposeAndClear();
1554
1555
0
    for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1556
0
    {
1557
0
        if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1558
0
        {
1559
0
            tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1560
1561
0
            if( pOutDev->HasMirroredGraphics() )
1562
0
                nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1563
0
            tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1564
0
            Point aPos( i_rPos );
1565
            // tdf#165706 those delta values are in pixels, but aPos copied from
1566
            // i_rPos *may* be in logical coordinates if a MapMode is set at
1567
            // i_pTargetOutDev. To not mix values of different coordinate systems
1568
            // it *needs* to be converted (which does nothing if no MapMode)
1569
0
            Point aDelta( i_pTargetOutDev->PixelToLogic( Point( nDeltaX, nDeltaY )) );
1570
0
            aPos += aDelta;
1571
0
            pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1572
0
        }
1573
0
    }
1574
1575
    // restore graphics state
1576
0
    GetOutDev()->Pop();
1577
1578
0
    GetOutDev()->EnableOutput( bOutput );
1579
0
    mpWindowImpl->mbReallyVisible = bRVisible;
1580
0
    GetOutDev()->mbDevOutput = bDevOutput;
1581
0
    GetOutDev()->mnDPIX = nOldDPIX;
1582
0
    GetOutDev()->mnDPIY = nOldDPIY;
1583
0
}
1584
1585
void Window::PaintToDevice(OutputDevice* pDev, const Point& rPos)
1586
0
{
1587
0
    if( !mpWindowImpl )
1588
0
        return;
1589
1590
0
    SAL_WARN_IF(  pDev->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1591
0
    SAL_WARN_IF(  pDev->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1592
1593
0
    vcl::Window* pRealParent = nullptr;
1594
0
    if( ! mpWindowImpl->mbVisible )
1595
0
    {
1596
0
        vcl::Window* pTempParent = ImplGetDefaultWindow();
1597
0
        pTempParent->EnableChildTransparentMode();
1598
0
        pRealParent = GetParent();
1599
0
        SetParent( pTempParent );
1600
        // trigger correct visibility flags for children
1601
0
        Show();
1602
0
        Hide();
1603
0
    }
1604
1605
0
    bool bVisible = mpWindowImpl->mbVisible;
1606
0
    mpWindowImpl->mbVisible = true;
1607
1608
0
    if( mpWindowImpl->mpBorderWindow )
1609
0
        mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1610
0
    else
1611
0
        ImplPaintToDevice( pDev, rPos );
1612
1613
0
    mpWindowImpl->mbVisible = bVisible;
1614
1615
0
    if( pRealParent )
1616
0
        SetParent( pRealParent );
1617
0
}
1618
1619
void Window::Erase(vcl::RenderContext& rRenderContext)
1620
0
{
1621
0
    if (!GetOutDev()->IsDeviceOutputNecessary() || GetOutDev()->ImplIsRecordLayout())
1622
0
        return;
1623
1624
0
    bool bNativeOK = false;
1625
1626
0
    ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1627
1628
0
    if (aCtrlPart == ControlPart::Entire && IsControlBackground())
1629
0
    {
1630
        // nothing to do here; background is drawn in corresponding drawNativeControl implementation
1631
0
        bNativeOK = true;
1632
0
    }
1633
0
    else if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1634
0
    {
1635
0
        tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1636
0
        ControlState nState = ControlState::NONE;
1637
1638
0
        if (IsEnabled())
1639
0
            nState |= ControlState::ENABLED;
1640
1641
0
        bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1642
0
                                                     nState, ImplControlValue(), OUString());
1643
0
    }
1644
1645
0
    if (GetOutDev()->mbBackground && !bNativeOK)
1646
0
    {
1647
0
        RasterOp eRasterOp = GetOutDev()->GetRasterOp();
1648
0
        if (eRasterOp != RasterOp::OverPaint)
1649
0
            GetOutDev()->SetRasterOp(RasterOp::OverPaint);
1650
0
        rRenderContext.DrawWallpaper(0, 0, GetOutDev()->mnOutWidth, GetOutDev()->mnOutHeight, GetOutDev()->maBackground);
1651
0
        if (eRasterOp != RasterOp::OverPaint)
1652
0
            rRenderContext.SetRasterOp(eRasterOp);
1653
0
    }
1654
0
}
1655
1656
void Window::ImplScroll( const tools::Rectangle& rRect,
1657
                         tools::Long nHorzScroll, tools::Long nVertScroll, ScrollFlags nFlags )
1658
0
{
1659
0
    if ( !GetOutDev()->IsDeviceOutputNecessary() )
1660
0
        return;
1661
1662
0
    nHorzScroll = GetOutDev()->ImplLogicWidthToDevicePixel( nHorzScroll );
1663
0
    nVertScroll = GetOutDev()->ImplLogicHeightToDevicePixel( nVertScroll );
1664
1665
0
    if ( !nHorzScroll && !nVertScroll )
1666
0
        return;
1667
1668
0
    if ( mpWindowImpl->mpCursor )
1669
0
        mpWindowImpl->mpCursor->ImplSuspend();
1670
1671
0
    ScrollFlags nOrgFlags = nFlags;
1672
0
    if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1673
0
    {
1674
0
        if ( GetStyle() & WB_CLIPCHILDREN )
1675
0
            nFlags |= ScrollFlags::NoChildren;
1676
0
        else
1677
0
            nFlags |= ScrollFlags::Children;
1678
0
    }
1679
1680
0
    vcl::Region  aInvalidateRegion;
1681
0
    bool    bScrollChildren(nFlags & ScrollFlags::Children);
1682
1683
0
    if ( !mpWindowImpl->mpFirstChild )
1684
0
        bScrollChildren = false;
1685
1686
0
    OutputDevice *pOutDev = GetOutDev();
1687
1688
    // RTL: check if this window requires special action
1689
0
    bool bReMirror = GetOutDev()->ImplIsAntiparallel();
1690
1691
0
    tools::Rectangle aRectMirror( rRect );
1692
0
    if( bReMirror )
1693
0
    {
1694
        //  make sure the invalidate region of this window is
1695
        // computed in the same coordinate space as the one from the overlap windows
1696
0
        pOutDev->ReMirror( aRectMirror );
1697
0
    }
1698
1699
    // adapt paint areas
1700
0
    ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1701
1702
0
    ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1703
1704
    // if the scrolling on the device is performed in the opposite direction
1705
    // then move the overlaps in that direction to compute the invalidate region
1706
    // on the correct side, i.e., revert nHorzScroll
1707
0
    if (!aInvalidateRegion.IsEmpty())
1708
0
    {
1709
0
        aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1710
0
    }
1711
1712
0
    tools::Rectangle aDestRect(aRectMirror);
1713
0
    aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1714
0
    vcl::Region aWinInvalidateRegion(aRectMirror);
1715
0
    if (!SupportsDoubleBuffering())
1716
0
    {
1717
        // There will be no CopyArea() call below, so invalidate the
1718
        // whole visible area, not only the smaller one that was just
1719
        // scrolled in.
1720
0
        aWinInvalidateRegion.Exclude(aDestRect);
1721
0
    }
1722
1723
0
    aInvalidateRegion.Union(aWinInvalidateRegion);
1724
1725
0
    vcl::Region aRegion( GetOutputRectPixel() );
1726
0
    if ( nFlags & ScrollFlags::Clip )
1727
0
        aRegion.Intersect( rRect );
1728
0
    if ( mpWindowImpl->mbWinRegion )
1729
0
        aRegion.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1730
1731
0
    aRegion.Exclude( aInvalidateRegion );
1732
1733
0
    ImplClipBoundaries( aRegion, false, true );
1734
0
    if ( !bScrollChildren )
1735
0
    {
1736
0
        if ( nOrgFlags & ScrollFlags::NoChildren )
1737
0
            ImplClipAllChildren( aRegion );
1738
0
        else
1739
0
            ImplClipChildren( aRegion );
1740
0
    }
1741
0
    if ( GetOutDev()->mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1742
0
        aRegion.Intersect( GetOutDev()->maRegion );
1743
0
    if ( !aRegion.IsEmpty() )
1744
0
    {
1745
0
        if ( mpWindowImpl->mpWinData )
1746
0
        {
1747
0
            if ( mpWindowImpl->mbFocusVisible )
1748
0
                ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1749
0
            if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1750
0
                InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1751
0
        }
1752
0
#ifndef IOS
1753
        // This seems completely unnecessary with tiled rendering, and
1754
        // causes the "AquaSalGraphics::copyArea() for non-layered
1755
        // graphics" message. Presumably we should bypass this on all
1756
        // platforms when dealing with a "window" that uses tiled
1757
        // rendering at the moment. Unclear how to figure that out,
1758
        // though. Also unclear whether we actually could just not
1759
        // create a "frame window", whatever that exactly is, in the
1760
        // tiled rendering case, or at least for platforms where tiles
1761
        // rendering is all there is.
1762
1763
0
        SalGraphics* pGraphics = ImplGetFrameGraphics();
1764
        // The invalidation area contains the area what would be copied here,
1765
        // so avoid copying in case of double buffering.
1766
0
        if (pGraphics && !SupportsDoubleBuffering())
1767
0
        {
1768
0
            if( bReMirror )
1769
0
            {
1770
0
                pOutDev->ReMirror( aRegion );
1771
0
            }
1772
1773
0
            pOutDev->SelectClipRegion( aRegion, pGraphics );
1774
0
            pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1775
0
                                 rRect.Left(), rRect.Top(),
1776
0
                                 rRect.GetWidth(), rRect.GetHeight(),
1777
0
                                 *GetOutDev() );
1778
0
        }
1779
0
#endif
1780
0
        if ( mpWindowImpl->mpWinData )
1781
0
        {
1782
0
            if ( mpWindowImpl->mbFocusVisible )
1783
0
                ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1784
0
            if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1785
0
                InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1786
0
        }
1787
0
    }
1788
1789
0
    if ( !aInvalidateRegion.IsEmpty() )
1790
0
    {
1791
        // RTL: the invalidate region for this windows is already computed in frame coordinates
1792
        // so it has to be re-mirrored before calling the Paint-handler
1793
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
1794
1795
0
        if ( !bScrollChildren )
1796
0
        {
1797
0
            if ( nOrgFlags & ScrollFlags::NoChildren )
1798
0
                ImplClipAllChildren( aInvalidateRegion );
1799
0
            else
1800
0
                ImplClipChildren( aInvalidateRegion );
1801
0
        }
1802
0
        ImplInvalidateFrameRegion( &aInvalidateRegion, InvalidateFlags::Children );
1803
0
    }
1804
1805
0
    if ( bScrollChildren )
1806
0
    {
1807
0
        vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1808
0
        while ( pWindow )
1809
0
        {
1810
0
            Point aPos = pWindow->GetPosPixel();
1811
0
            aPos += Point( nHorzScroll, nVertScroll );
1812
0
            pWindow->SetPosPixel( aPos );
1813
1814
0
            pWindow = pWindow->mpWindowImpl->mpNext;
1815
0
        }
1816
0
    }
1817
1818
0
    if ( nFlags & ScrollFlags::Update )
1819
0
        PaintImmediately();
1820
1821
0
    if ( mpWindowImpl->mpCursor )
1822
0
        mpWindowImpl->mpCursor->ImplResume();
1823
0
}
1824
1825
} /* namespace vcl */
1826
1827
1828
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */