Coverage Report

Created: 2025-11-16 09:57

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
99.7k
{
1146
99.7k
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1147
99.7k
        return;
1148
1149
0
    ImplInvalidate( nullptr, nFlags );
1150
0
    LogicInvalidate(nullptr);
1151
0
}
1152
1153
void Window::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags )
1154
14.7k
{
1155
14.7k
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1156
14.7k
        return;
1157
1158
0
    OutputDevice *pOutDev = GetOutDev();
1159
0
    tools::Rectangle aRect = pOutDev->ImplLogicToDevicePixel( rRect );
1160
0
    if ( !aRect.IsEmpty() )
1161
0
    {
1162
0
        vcl::Region aRegion( aRect );
1163
0
        ImplInvalidate( &aRegion, nFlags );
1164
0
        tools::Rectangle aLogicRectangle(rRect);
1165
0
        LogicInvalidate(&aLogicRectangle);
1166
0
    }
1167
0
}
1168
1169
void Window::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags )
1170
0
{
1171
0
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1172
0
        return;
1173
1174
0
    if ( rRegion.IsNull() )
1175
0
    {
1176
0
        ImplInvalidate( nullptr, nFlags );
1177
0
        LogicInvalidate(nullptr);
1178
0
    }
1179
0
    else
1180
0
    {
1181
0
        vcl::Region aRegion = GetOutDev()->ImplPixelToDevicePixel( LogicToPixel( rRegion ) );
1182
0
        if ( !aRegion.IsEmpty() )
1183
0
        {
1184
0
            ImplInvalidate( &aRegion, nFlags );
1185
0
            tools::Rectangle aLogicRectangle = rRegion.GetBoundRect();
1186
0
            LogicInvalidate(&aLogicRectangle);
1187
0
        }
1188
0
    }
1189
0
}
1190
1191
void Window::LogicInvalidate(const tools::Rectangle* pRectangle)
1192
0
{
1193
0
    if(pRectangle)
1194
0
    {
1195
0
        tools::Rectangle aRect = GetOutDev()->ImplLogicToDevicePixel( *pRectangle );
1196
0
        PixelInvalidate(&aRect);
1197
0
    }
1198
0
    else
1199
0
        PixelInvalidate(nullptr);
1200
0
}
1201
1202
bool Window::InvalidateByForeignEditView(EditView* )
1203
0
{
1204
0
    return false;
1205
0
}
1206
1207
void Window::PixelInvalidate(const tools::Rectangle* pRectangle)
1208
0
{
1209
0
    if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
1210
0
        return;
1211
1212
0
    Size aSize = GetSizePixel();
1213
0
    if (aSize.IsEmpty())
1214
0
        return;
1215
1216
0
    if (const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier())
1217
0
    {
1218
        // In case we are routing the window, notify the client
1219
0
        std::vector<vcl::LOKPayloadItem> aPayload;
1220
0
        tools::Rectangle aRect(Point(0, 0), aSize);
1221
0
        if (pRectangle)
1222
0
            aRect = *pRectangle;
1223
1224
0
        if (IsRTLEnabled() && GetOutDev() && !GetOutDev()->ImplIsAntiparallel())
1225
0
            GetOutDev()->ReMirror(aRect);
1226
1227
0
        aPayload.emplace_back("rectangle", aRect.toString());
1228
1229
0
        pNotifier->notifyWindow(GetLOKWindowId(), u"invalidate"_ustr, aPayload);
1230
0
    }
1231
0
    else if (GetParent() && GetParent()->IsFormControl())
1232
0
    {
1233
0
        const VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier();
1234
0
        if (pParent)
1235
0
            pParent->GetLOKNotifier()->notifyInvalidation(pRectangle);
1236
0
    }
1237
    // Added for dialog items. Pass invalidation to the parent window.
1238
0
    else if (VclPtr<vcl::Window> pParent = GetParentWithLOKNotifier())
1239
0
    {
1240
0
        const tools::Rectangle aRect(Point(GetOutOffXPixel(), GetOutOffYPixel()), GetSizePixel());
1241
0
        pParent->PixelInvalidate(&aRect);
1242
0
    }
1243
0
}
1244
1245
void Window::Validate()
1246
0
{
1247
0
    if ( !comphelper::LibreOfficeKit::isActive() && (!GetOutDev()->IsDeviceOutputNecessary() || !GetOutDev()->mnOutWidth || !GetOutDev()->mnOutHeight) )
1248
0
        return;
1249
1250
0
    ImplValidate();
1251
0
}
1252
1253
bool Window::HasPaintEvent() const
1254
0
{
1255
0
    if (!mpWindowImpl)
1256
0
        return false;
1257
1258
0
    if ( !mpWindowImpl->mbReallyVisible )
1259
0
        return false;
1260
1261
0
    if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1262
0
        return true;
1263
1264
0
    if ( mpWindowImpl->mnPaintFlags & ImplPaintFlags::Paint )
1265
0
        return true;
1266
1267
0
    if ( !ImplIsOverlapWindow() )
1268
0
    {
1269
0
        const vcl::Window* pTempWindow = this;
1270
0
        do
1271
0
        {
1272
0
            pTempWindow = pTempWindow->ImplGetParent();
1273
0
            if ( pTempWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::PaintChildren | ImplPaintFlags::PaintAllChildren) )
1274
0
                return true;
1275
0
        }
1276
0
        while ( !pTempWindow->ImplIsOverlapWindow() );
1277
0
    }
1278
1279
0
    return false;
1280
0
}
1281
1282
void Window::PaintImmediately()
1283
420
{
1284
420
    if (!mpWindowImpl)
1285
0
        return;
1286
1287
420
    if ( mpWindowImpl->mpBorderWindow )
1288
0
    {
1289
0
        mpWindowImpl->mpBorderWindow->PaintImmediately();
1290
0
        return;
1291
0
    }
1292
1293
420
    if ( !mpWindowImpl->mbReallyVisible )
1294
420
        return;
1295
1296
0
    bool bFlush = false;
1297
0
    if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame )
1298
0
    {
1299
0
        Point aPoint( 0, 0 );
1300
0
        vcl::Region aRegion( tools::Rectangle( aPoint, GetOutputSizePixel() ) );
1301
0
        ImplInvalidateOverlapFrameRegion( aRegion );
1302
0
        if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) )
1303
0
            bFlush = true;
1304
0
    }
1305
1306
    // First we should skip all windows which are Paint-Transparent
1307
0
    vcl::Window* pUpdateWindow = this;
1308
0
    vcl::Window* pWindow = pUpdateWindow;
1309
0
    while ( !pWindow->ImplIsOverlapWindow() )
1310
0
    {
1311
0
        if ( !pWindow->mpWindowImpl->mbPaintTransparent )
1312
0
        {
1313
0
            pUpdateWindow = pWindow;
1314
0
            break;
1315
0
        }
1316
0
        pWindow = pWindow->ImplGetParent();
1317
0
    }
1318
    // In order to limit drawing, an update only draws the window which
1319
    // has PAINTALLCHILDREN set
1320
0
    pWindow = pUpdateWindow;
1321
0
    do
1322
0
    {
1323
0
        if ( pWindow->mpWindowImpl->mnPaintFlags & ImplPaintFlags::PaintAllChildren )
1324
0
            pUpdateWindow = pWindow;
1325
0
        if ( pWindow->ImplIsOverlapWindow() )
1326
0
            break;
1327
0
        pWindow = pWindow->ImplGetParent();
1328
0
    }
1329
0
    while ( pWindow );
1330
1331
    // if there is something to paint, trigger a Paint
1332
0
    if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (ImplPaintFlags::Paint | ImplPaintFlags::PaintChildren) )
1333
0
    {
1334
0
        VclPtr<vcl::Window> xWindow(this);
1335
1336
        // trigger an update also for system windows on top of us,
1337
        // otherwise holes would remain
1338
0
        vcl::Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow();
1339
0
        if (pUpdateOverlapWindow->mpWindowImpl)
1340
0
            pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpFirstOverlap;
1341
0
        else
1342
0
            pUpdateOverlapWindow = nullptr;
1343
0
        while ( pUpdateOverlapWindow )
1344
0
        {
1345
0
             pUpdateOverlapWindow->PaintImmediately();
1346
0
             pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext;
1347
0
        }
1348
1349
0
        pUpdateWindow->ImplCallPaint(nullptr, pUpdateWindow->mpWindowImpl->mnPaintFlags);
1350
1351
0
        if (comphelper::LibreOfficeKit::isActive() && pUpdateWindow->GetParentDialog())
1352
0
            pUpdateWindow->LogicInvalidate(nullptr);
1353
1354
0
        if (xWindow->isDisposed())
1355
0
           return;
1356
1357
0
        bFlush = true;
1358
0
    }
1359
1360
0
    if ( bFlush )
1361
0
        GetOutDev()->Flush();
1362
0
}
1363
1364
void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos )
1365
0
{
1366
    // Special drawing when called through LOKit
1367
    // TODO: Move to its own method
1368
0
    if (comphelper::LibreOfficeKit::isActive())
1369
0
    {
1370
0
        VclPtrInstance<VirtualDevice> pDevice(*i_pTargetOutDev);
1371
0
        pDevice->EnableRTL(IsRTLEnabled());
1372
1373
0
        Size aSize(GetOutputSizePixel());
1374
0
        pDevice->SetOutputSizePixel(aSize);
1375
1376
0
        vcl::Font aCopyFont = GetFont();
1377
0
        pDevice->SetFont(aCopyFont);
1378
1379
0
        pDevice->SetTextColor(GetTextColor());
1380
0
        if (GetOutDev()->IsLineColor())
1381
0
            pDevice->SetLineColor(GetOutDev()->GetLineColor());
1382
0
        else
1383
0
            pDevice->SetLineColor();
1384
1385
0
        if (GetOutDev()->IsFillColor())
1386
0
            pDevice->SetFillColor(GetOutDev()->GetFillColor());
1387
0
        else
1388
0
            pDevice->SetFillColor();
1389
1390
0
        if (IsTextLineColor())
1391
0
            pDevice->SetTextLineColor(GetTextLineColor());
1392
0
        else
1393
0
            pDevice->SetTextLineColor();
1394
1395
0
        if (IsOverlineColor())
1396
0
            pDevice->SetOverlineColor(GetOverlineColor());
1397
0
        else
1398
0
            pDevice->SetOverlineColor();
1399
1400
0
        if (IsTextFillColor())
1401
0
            pDevice->SetTextFillColor(GetTextFillColor());
1402
0
        else
1403
0
            pDevice->SetTextFillColor();
1404
1405
0
        pDevice->SetTextAlign(GetTextAlign());
1406
0
        pDevice->SetRasterOp(GetOutDev()->GetRasterOp());
1407
1408
0
        tools::Rectangle aPaintRect(Point(), GetOutputSizePixel());
1409
1410
0
        vcl::Region aClipRegion(GetOutDev()->GetClipRegion());
1411
0
        pDevice->SetClipRegion();
1412
0
        aClipRegion.Intersect(aPaintRect);
1413
0
        pDevice->SetClipRegion(aClipRegion);
1414
1415
0
        if (!IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip))
1416
0
            Erase(*pDevice);
1417
1418
0
        pDevice->SetMapMode(GetMapMode());
1419
1420
0
        Paint(*pDevice, tools::Rectangle(Point(), GetOutputSizePixel()));
1421
1422
0
        i_pTargetOutDev->DrawOutDev(i_rPos, aSize, Point(), pDevice->PixelToLogic(aSize), *pDevice);
1423
1424
0
        bool bHasMirroredGraphics = pDevice->HasMirroredGraphics();
1425
1426
        // get rid of virtual device now so they don't pile up during recursive calls
1427
0
        pDevice.disposeAndClear();
1428
1429
1430
0
        for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1431
0
        {
1432
0
            if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1433
0
            {
1434
0
                tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1435
0
                if( bHasMirroredGraphics )
1436
0
                    nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1437
1438
0
                tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1439
1440
0
                Point aPos( i_rPos );
1441
0
                aPos += Point(nDeltaX, nDeltaY);
1442
1443
0
                pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1444
0
            }
1445
0
        }
1446
0
        return;
1447
0
    }
1448
1449
1450
0
    bool bRVisible = mpWindowImpl->mbReallyVisible;
1451
0
    mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible;
1452
0
    bool bDevOutput = GetOutDev()->mbDevOutput;
1453
0
    GetOutDev()->mbDevOutput = true;
1454
1455
0
    const OutputDevice *pOutDev = GetOutDev();
1456
0
    tools::Long nOldDPIX = pOutDev->GetDPIX();
1457
0
    tools::Long nOldDPIY = pOutDev->GetDPIY();
1458
0
    GetOutDev()->mnDPIX = i_pTargetOutDev->GetDPIX();
1459
0
    GetOutDev()->mnDPIY = i_pTargetOutDev->GetDPIY();
1460
0
    bool bOutput = GetOutDev()->IsOutputEnabled();
1461
0
    GetOutDev()->EnableOutput();
1462
1463
0
    SAL_WARN_IF( GetMapMode().GetMapUnit() != MapUnit::MapPixel, "vcl.window", "MapMode must be PIXEL based" );
1464
0
    if ( GetMapMode().GetMapUnit() != MapUnit::MapPixel )
1465
0
        return;
1466
1467
    // preserve graphicsstate
1468
0
    GetOutDev()->Push();
1469
0
    vcl::Region aClipRegion( GetOutDev()->GetClipRegion() );
1470
0
    GetOutDev()->SetClipRegion();
1471
1472
0
    GDIMetaFile* pOldMtf = GetOutDev()->GetConnectMetaFile();
1473
0
    GDIMetaFile aMtf;
1474
0
    GetOutDev()->SetConnectMetaFile( &aMtf );
1475
1476
    // put a push action to metafile
1477
0
    GetOutDev()->Push();
1478
    // copy graphics state to metafile
1479
0
    vcl::Font aCopyFont = GetFont();
1480
0
    if( nOldDPIX != GetOutDev()->mnDPIX || nOldDPIY != GetOutDev()->mnDPIY )
1481
0
    {
1482
0
        aCopyFont.SetFontHeight( aCopyFont.GetFontHeight() * GetOutDev()->mnDPIY / nOldDPIY );
1483
0
        aCopyFont.SetAverageFontWidth( aCopyFont.GetAverageFontWidth() * GetOutDev()->mnDPIX / nOldDPIX );
1484
0
    }
1485
0
    SetFont( aCopyFont );
1486
0
    SetTextColor( GetTextColor() );
1487
0
    if( GetOutDev()->IsLineColor() )
1488
0
        GetOutDev()->SetLineColor( GetOutDev()->GetLineColor() );
1489
0
    else
1490
0
        GetOutDev()->SetLineColor();
1491
0
    if( GetOutDev()->IsFillColor() )
1492
0
        GetOutDev()->SetFillColor( GetOutDev()->GetFillColor() );
1493
0
    else
1494
0
        GetOutDev()->SetFillColor();
1495
0
    if( IsTextLineColor() )
1496
0
        SetTextLineColor( GetTextLineColor() );
1497
0
    else
1498
0
        SetTextLineColor();
1499
0
    if( IsOverlineColor() )
1500
0
        SetOverlineColor( GetOverlineColor() );
1501
0
    else
1502
0
        SetOverlineColor();
1503
0
    if( IsTextFillColor() )
1504
0
        SetTextFillColor( GetTextFillColor() );
1505
0
    else
1506
0
        SetTextFillColor();
1507
0
    SetTextAlign( GetTextAlign() );
1508
0
    GetOutDev()->SetRasterOp( GetOutDev()->GetRasterOp() );
1509
0
    if( GetOutDev()->IsRefPoint() )
1510
0
        GetOutDev()->SetRefPoint( GetOutDev()->GetRefPoint() );
1511
0
    else
1512
0
        GetOutDev()->SetRefPoint();
1513
0
    GetOutDev()->SetLayoutMode( GetOutDev()->GetLayoutMode() );
1514
1515
0
    GetOutDev()->SetDigitLanguage( GetOutDev()->GetDigitLanguage() );
1516
0
    tools::Rectangle aPaintRect(Point(0, 0), GetOutputSizePixel());
1517
0
    aClipRegion.Intersect( aPaintRect );
1518
0
    GetOutDev()->SetClipRegion( aClipRegion );
1519
1520
    // do the actual paint
1521
1522
    // background
1523
0
    if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & ParentClipMode::NoClip ) )
1524
0
    {
1525
0
        Erase(*GetOutDev());
1526
0
    }
1527
    // foreground
1528
0
    Paint(*GetOutDev(), aPaintRect);
1529
    // put a pop action to metafile
1530
0
    GetOutDev()->Pop();
1531
1532
0
    GetOutDev()->SetConnectMetaFile( pOldMtf );
1533
0
    GetOutDev()->EnableOutput( bOutput );
1534
0
    mpWindowImpl->mbReallyVisible = bRVisible;
1535
1536
    // paint metafile to VDev
1537
0
    VclPtrInstance<VirtualDevice> pMaskedDevice(*i_pTargetOutDev,
1538
0
                                                DeviceFormat::WITH_ALPHA);
1539
1540
0
    pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel(), true, true );
1541
0
    pMaskedDevice->EnableRTL( IsRTLEnabled() );
1542
0
    aMtf.WindStart();
1543
0
    aMtf.Play(*pMaskedDevice);
1544
0
    Bitmap aBmpEx( pMaskedDevice->GetBitmap( Point( 0, 0 ), aPaintRect.GetSize() ) );
1545
0
    i_pTargetOutDev->DrawBitmap( i_rPos, aBmpEx );
1546
    // get rid of virtual device now so they don't pile up during recursive calls
1547
0
    pMaskedDevice.disposeAndClear();
1548
1549
0
    for( vcl::Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext )
1550
0
    {
1551
0
        if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() )
1552
0
        {
1553
0
            tools::Long nDeltaX = pChild->GetOutDev()->mnOutOffX - GetOutDev()->mnOutOffX;
1554
1555
0
            if( pOutDev->HasMirroredGraphics() )
1556
0
                nDeltaX = GetOutDev()->mnOutWidth - nDeltaX - pChild->GetOutDev()->mnOutWidth;
1557
0
            tools::Long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel();
1558
0
            Point aPos( i_rPos );
1559
            // tdf#165706 those delta values are in pixels, but aPos copied from
1560
            // i_rPos *may* be in logical coordinates if a MapMode is set at
1561
            // i_pTargetOutDev. To not mix values of different coordinate systems
1562
            // it *needs* to be converted (which does nothing if no MapMode)
1563
0
            Point aDelta( i_pTargetOutDev->PixelToLogic( Point( nDeltaX, nDeltaY )) );
1564
0
            aPos += aDelta;
1565
0
            pChild->ImplPaintToDevice( i_pTargetOutDev, aPos );
1566
0
        }
1567
0
    }
1568
1569
    // restore graphics state
1570
0
    GetOutDev()->Pop();
1571
1572
0
    GetOutDev()->EnableOutput( bOutput );
1573
0
    mpWindowImpl->mbReallyVisible = bRVisible;
1574
0
    GetOutDev()->mbDevOutput = bDevOutput;
1575
0
    GetOutDev()->mnDPIX = nOldDPIX;
1576
0
    GetOutDev()->mnDPIY = nOldDPIY;
1577
0
}
1578
1579
void Window::PaintToDevice(OutputDevice* pDev, const Point& rPos)
1580
0
{
1581
0
    if( !mpWindowImpl )
1582
0
        return;
1583
1584
0
    SAL_WARN_IF(  pDev->HasMirroredGraphics(), "vcl.window", "PaintToDevice to mirroring graphics" );
1585
0
    SAL_WARN_IF(  pDev->IsRTLEnabled(), "vcl.window", "PaintToDevice to mirroring device" );
1586
1587
0
    vcl::Window* pRealParent = nullptr;
1588
0
    if( ! mpWindowImpl->mbVisible )
1589
0
    {
1590
0
        vcl::Window* pTempParent = ImplGetDefaultWindow();
1591
0
        pTempParent->EnableChildTransparentMode();
1592
0
        pRealParent = GetParent();
1593
0
        SetParent( pTempParent );
1594
        // trigger correct visibility flags for children
1595
0
        Show();
1596
0
        Hide();
1597
0
    }
1598
1599
0
    bool bVisible = mpWindowImpl->mbVisible;
1600
0
    mpWindowImpl->mbVisible = true;
1601
1602
0
    if( mpWindowImpl->mpBorderWindow )
1603
0
        mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos );
1604
0
    else
1605
0
        ImplPaintToDevice( pDev, rPos );
1606
1607
0
    mpWindowImpl->mbVisible = bVisible;
1608
1609
0
    if( pRealParent )
1610
0
        SetParent( pRealParent );
1611
0
}
1612
1613
void Window::Erase(vcl::RenderContext& rRenderContext)
1614
0
{
1615
0
    if (!GetOutDev()->IsDeviceOutputNecessary() || GetOutDev()->ImplIsRecordLayout())
1616
0
        return;
1617
1618
0
    bool bNativeOK = false;
1619
1620
0
    ControlPart aCtrlPart = ImplGetWindowImpl()->mnNativeBackground;
1621
1622
0
    if (aCtrlPart == ControlPart::Entire && IsControlBackground())
1623
0
    {
1624
        // nothing to do here; background is drawn in corresponding drawNativeControl implementation
1625
0
        bNativeOK = true;
1626
0
    }
1627
0
    else if (aCtrlPart != ControlPart::NONE && ! IsControlBackground())
1628
0
    {
1629
0
        tools::Rectangle aCtrlRegion(Point(), GetOutputSizePixel());
1630
0
        ControlState nState = ControlState::NONE;
1631
1632
0
        if (IsEnabled())
1633
0
            nState |= ControlState::ENABLED;
1634
1635
0
        bNativeOK = rRenderContext.DrawNativeControl(ControlType::WindowBackground, aCtrlPart, aCtrlRegion,
1636
0
                                                     nState, ImplControlValue(), OUString());
1637
0
    }
1638
1639
0
    if (GetOutDev()->mbBackground && !bNativeOK)
1640
0
    {
1641
0
        RasterOp eRasterOp = GetOutDev()->GetRasterOp();
1642
0
        if (eRasterOp != RasterOp::OverPaint)
1643
0
            GetOutDev()->SetRasterOp(RasterOp::OverPaint);
1644
0
        rRenderContext.DrawWallpaper(0, 0, GetOutDev()->mnOutWidth, GetOutDev()->mnOutHeight, GetOutDev()->maBackground);
1645
0
        if (eRasterOp != RasterOp::OverPaint)
1646
0
            rRenderContext.SetRasterOp(eRasterOp);
1647
0
    }
1648
0
}
1649
1650
void Window::ImplScroll( const tools::Rectangle& rRect,
1651
                         tools::Long nHorzScroll, tools::Long nVertScroll, ScrollFlags nFlags )
1652
0
{
1653
0
    if ( !GetOutDev()->IsDeviceOutputNecessary() )
1654
0
        return;
1655
1656
0
    nHorzScroll = GetOutDev()->ImplLogicWidthToDevicePixel( nHorzScroll );
1657
0
    nVertScroll = GetOutDev()->ImplLogicHeightToDevicePixel( nVertScroll );
1658
1659
0
    if ( !nHorzScroll && !nVertScroll )
1660
0
        return;
1661
1662
0
    if ( mpWindowImpl->mpCursor )
1663
0
        mpWindowImpl->mpCursor->ImplSuspend();
1664
1665
0
    ScrollFlags nOrgFlags = nFlags;
1666
0
    if ( !(nFlags & (ScrollFlags::Children | ScrollFlags::NoChildren)) )
1667
0
    {
1668
0
        if ( GetStyle() & WB_CLIPCHILDREN )
1669
0
            nFlags |= ScrollFlags::NoChildren;
1670
0
        else
1671
0
            nFlags |= ScrollFlags::Children;
1672
0
    }
1673
1674
0
    vcl::Region  aInvalidateRegion;
1675
0
    bool    bScrollChildren(nFlags & ScrollFlags::Children);
1676
1677
0
    if ( !mpWindowImpl->mpFirstChild )
1678
0
        bScrollChildren = false;
1679
1680
0
    OutputDevice *pOutDev = GetOutDev();
1681
1682
    // RTL: check if this window requires special action
1683
0
    bool bReMirror = GetOutDev()->ImplIsAntiparallel();
1684
1685
0
    tools::Rectangle aRectMirror( rRect );
1686
0
    if( bReMirror )
1687
0
    {
1688
        //  make sure the invalidate region of this window is
1689
        // computed in the same coordinate space as the one from the overlap windows
1690
0
        pOutDev->ReMirror( aRectMirror );
1691
0
    }
1692
1693
    // adapt paint areas
1694
0
    ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChildren );
1695
1696
0
    ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChildren, false );
1697
1698
    // if the scrolling on the device is performed in the opposite direction
1699
    // then move the overlaps in that direction to compute the invalidate region
1700
    // on the correct side, i.e., revert nHorzScroll
1701
0
    if (!aInvalidateRegion.IsEmpty())
1702
0
    {
1703
0
        aInvalidateRegion.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1704
0
    }
1705
1706
0
    tools::Rectangle aDestRect(aRectMirror);
1707
0
    aDestRect.Move(bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll);
1708
0
    vcl::Region aWinInvalidateRegion(aRectMirror);
1709
0
    if (!SupportsDoubleBuffering())
1710
0
    {
1711
        // There will be no CopyArea() call below, so invalidate the
1712
        // whole visible area, not only the smaller one that was just
1713
        // scrolled in.
1714
0
        aWinInvalidateRegion.Exclude(aDestRect);
1715
0
    }
1716
1717
0
    aInvalidateRegion.Union(aWinInvalidateRegion);
1718
1719
0
    vcl::Region aRegion( GetOutputRectPixel() );
1720
0
    if ( nFlags & ScrollFlags::Clip )
1721
0
        aRegion.Intersect( rRect );
1722
0
    if ( mpWindowImpl->mbWinRegion )
1723
0
        aRegion.Intersect( GetOutDev()->ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) );
1724
1725
0
    aRegion.Exclude( aInvalidateRegion );
1726
1727
0
    ImplClipBoundaries( aRegion, false, true );
1728
0
    if ( !bScrollChildren )
1729
0
    {
1730
0
        if ( nOrgFlags & ScrollFlags::NoChildren )
1731
0
            ImplClipAllChildren( aRegion );
1732
0
        else
1733
0
            ImplClipChildren( aRegion );
1734
0
    }
1735
0
    if ( GetOutDev()->mbClipRegion && (nFlags & ScrollFlags::UseClipRegion) )
1736
0
        aRegion.Intersect( GetOutDev()->maRegion );
1737
0
    if ( !aRegion.IsEmpty() )
1738
0
    {
1739
0
        if ( mpWindowImpl->mpWinData )
1740
0
        {
1741
0
            if ( mpWindowImpl->mbFocusVisible )
1742
0
                ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1743
0
            if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1744
0
                InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1745
0
        }
1746
0
#ifndef IOS
1747
        // This seems completely unnecessary with tiled rendering, and
1748
        // causes the "AquaSalGraphics::copyArea() for non-layered
1749
        // graphics" message. Presumably we should bypass this on all
1750
        // platforms when dealing with a "window" that uses tiled
1751
        // rendering at the moment. Unclear how to figure that out,
1752
        // though. Also unclear whether we actually could just not
1753
        // create a "frame window", whatever that exactly is, in the
1754
        // tiled rendering case, or at least for platforms where tiles
1755
        // rendering is all there is.
1756
1757
0
        SalGraphics* pGraphics = ImplGetFrameGraphics();
1758
        // The invalidation area contains the area what would be copied here,
1759
        // so avoid copying in case of double buffering.
1760
0
        if (pGraphics && !SupportsDoubleBuffering())
1761
0
        {
1762
0
            if( bReMirror )
1763
0
            {
1764
0
                pOutDev->ReMirror( aRegion );
1765
0
            }
1766
1767
0
            pOutDev->SelectClipRegion( aRegion, pGraphics );
1768
0
            pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll,
1769
0
                                 rRect.Left(), rRect.Top(),
1770
0
                                 rRect.GetWidth(), rRect.GetHeight(),
1771
0
                                 *GetOutDev() );
1772
0
        }
1773
0
#endif
1774
0
        if ( mpWindowImpl->mpWinData )
1775
0
        {
1776
0
            if ( mpWindowImpl->mbFocusVisible )
1777
0
                ImplInvertFocus( *mpWindowImpl->mpWinData->mpFocusRect );
1778
0
            if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & ShowTrackFlags::TrackWindow) )
1779
0
                InvertTracking( *mpWindowImpl->mpWinData->mpTrackRect, mpWindowImpl->mpWinData->mnTrackFlags );
1780
0
        }
1781
0
    }
1782
1783
0
    if ( !aInvalidateRegion.IsEmpty() )
1784
0
    {
1785
        // RTL: the invalidate region for this windows is already computed in frame coordinates
1786
        // so it has to be re-mirrored before calling the Paint-handler
1787
0
        mpWindowImpl->mnPaintFlags |= ImplPaintFlags::CheckRtl;
1788
1789
0
        if ( !bScrollChildren )
1790
0
        {
1791
0
            if ( nOrgFlags & ScrollFlags::NoChildren )
1792
0
                ImplClipAllChildren( aInvalidateRegion );
1793
0
            else
1794
0
                ImplClipChildren( aInvalidateRegion );
1795
0
        }
1796
0
        ImplInvalidateFrameRegion( &aInvalidateRegion, InvalidateFlags::Children );
1797
0
    }
1798
1799
0
    if ( bScrollChildren )
1800
0
    {
1801
0
        vcl::Window* pWindow = mpWindowImpl->mpFirstChild;
1802
0
        while ( pWindow )
1803
0
        {
1804
0
            Point aPos = pWindow->GetPosPixel();
1805
0
            aPos += Point( nHorzScroll, nVertScroll );
1806
0
            pWindow->SetPosPixel( aPos );
1807
1808
0
            pWindow = pWindow->mpWindowImpl->mpNext;
1809
0
        }
1810
0
    }
1811
1812
0
    if ( nFlags & ScrollFlags::Update )
1813
0
        PaintImmediately();
1814
1815
0
    if ( mpWindowImpl->mpCursor )
1816
0
        mpWindowImpl->mpCursor->ImplResume();
1817
0
}
1818
1819
} /* namespace vcl */
1820
1821
1822
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */