Coverage Report

Created: 2026-02-26 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qregion.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#include "qregion.h"
6
#include "qpainterpath.h"
7
#include "qpolygon.h"
8
#include "qbuffer.h"
9
#include "qdatastream.h"
10
#include "qvariant.h"
11
#include "qvarlengtharray.h"
12
#include "qimage.h"
13
#include "qbitmap.h"
14
#include "qtransform.h"
15
16
#include <memory>
17
#include <private/qdebug_p.h>
18
19
#ifdef Q_OS_WIN
20
#  include <qt_windows.h>
21
#endif
22
23
QT_BEGIN_NAMESPACE
24
25
/*!
26
    \class QRegion
27
    \brief The QRegion class specifies a clip region for a painter.
28
29
    \inmodule QtGui
30
    \ingroup painting
31
    \ingroup shared
32
33
    QRegion is used with QPainter::setClipRegion() to limit the paint
34
    area to what needs to be painted. There is also a QWidget::repaint()
35
    function that takes a QRegion parameter. QRegion is the best tool for
36
    minimizing the amount of screen area to be updated by a repaint.
37
38
    This class is not suitable for constructing shapes for rendering, especially
39
    as outlines. Use QPainterPath to create paths and shapes for use with
40
    QPainter.
41
42
    QRegion is an \l{implicitly shared} class.
43
44
    \section1 Creating and Using Regions
45
46
    A region can be created from a rectangle, an ellipse, a polygon or
47
    a bitmap. Complex regions may be created by combining simple
48
    regions using united(), intersected(), subtracted(), or xored() (exclusive
49
    or). You can move a region using translate().
50
51
    You can test whether a region isEmpty() or if it
52
    contains() a QPoint or QRect. The bounding rectangle can be found
53
    with boundingRect().
54
55
    Iteration over the region (with begin(), end(), or
56
    ranged-for loops) gives a decomposition of the region into
57
    rectangles.
58
59
    Example of using complex regions:
60
    \snippet code/src_gui_painting_qregion.cpp 0
61
62
    \sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
63
*/
64
65
66
/*!
67
    \enum QRegion::RegionType
68
69
    Specifies the shape of the region to be created.
70
71
    \value Rectangle  the region covers the entire rectangle.
72
    \value Ellipse  the region is an ellipse inside the rectangle.
73
*/
74
75
/*!
76
    \fn void QRegion::translate(const QPoint &point)
77
78
    \overload
79
80
    Translates the region \a{point}\e{.x()} along the x axis and
81
    \a{point}\e{.y()} along the y axis, relative to the current
82
    position. Positive values move the region to the right and down.
83
84
    Translates to the given \a point.
85
*/
86
87
/*****************************************************************************
88
  QRegion member functions
89
 *****************************************************************************/
90
91
/*!
92
    \fn QRegion::QRegion()
93
94
    Constructs an empty region.
95
96
    \sa isEmpty()
97
*/
98
99
/*!
100
    \fn QRegion::QRegion(const QRect &r, RegionType t)
101
    \overload
102
103
    Create a region based on the rectangle \a r with region type \a t.
104
105
    If the rectangle is invalid a null region will be created.
106
107
    \sa QRegion::RegionType
108
*/
109
110
/*!
111
    \fn QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
112
113
    Constructs a polygon region from the point array \a a with the fill rule
114
    specified by \a fillRule.
115
116
    If \a fillRule is \l{Qt::WindingFill}, the polygon region is defined
117
    using the winding algorithm; if it is \l{Qt::OddEvenFill}, the odd-even fill
118
    algorithm is used.
119
120
    \warning This constructor can be used to create complex regions that will
121
    slow down painting when used.
122
*/
123
124
/*!
125
    \fn QRegion::QRegion(const QRegion &r)
126
127
    Constructs a new region which is equal to region \a r.
128
*/
129
130
/*!
131
    \fn QRegion::QRegion(QRegion &&other)
132
    \since 5.7
133
134
    Move-constructs a new region from region \a other.
135
    After the call, \a other is null.
136
137
    \sa isNull()
138
*/
139
140
/*!
141
    \fn QRegion::QRegion(const QBitmap &bm)
142
143
    Constructs a region from the bitmap \a bm.
144
145
    The resulting region consists of the pixels in bitmap \a bm that
146
    are Qt::color1, as if each pixel was a 1 by 1 rectangle.
147
148
    This constructor may create complex regions that will slow down
149
    painting when used. Note that drawing masked pixmaps can be done
150
    much faster using QPixmap::setMask().
151
*/
152
153
/*!
154
    Constructs a rectangular or elliptic region.
155
156
    If \a t is \c Rectangle, the region is the filled rectangle (\a x,
157
    \a y, \a w, \a h). If \a t is \c Ellipse, the region is the filled
158
    ellipse with center at (\a x + \a w / 2, \a y + \a h / 2) and size
159
    (\a w ,\a h).
160
*/
161
QRegion::QRegion(int x, int y, int w, int h, RegionType t)
162
0
{
163
0
    QRegion tmp(QRect(x, y, w, h), t);
164
0
    tmp.d->ref.ref();
165
0
    d = tmp.d;
166
0
}
167
168
/*!
169
    \fn QRegion::~QRegion()
170
    \internal
171
172
    Destroys the region.
173
*/
174
175
void QRegion::detach()
176
0
{
177
0
    if (d->ref.isShared())
178
0
        *this = copy();
179
0
}
180
181
// duplicates in qregion_win.cpp and qregion_wce.cpp
182
0
#define QRGN_SETRECT          1                // region stream commands
183
0
#define QRGN_SETELLIPSE       2                //  (these are internal)
184
0
#define QRGN_SETPTARRAY_ALT   3
185
0
#define QRGN_SETPTARRAY_WIND  4
186
0
#define QRGN_TRANSLATE        5
187
0
#define QRGN_OR               6
188
0
#define QRGN_AND              7
189
0
#define QRGN_SUB              8
190
0
#define QRGN_XOR              9
191
0
#define QRGN_RECTS            10
192
193
194
#ifndef QT_NO_DATASTREAM
195
196
/*
197
    Executes region commands in the internal buffer and rebuilds the
198
    original region.
199
200
    We do this when we read a region from the data stream.
201
202
    If \a ver is non-0, uses the format version \a ver on reading the
203
    byte array.
204
*/
205
void QRegion::exec(const QByteArray &buffer, int ver, QDataStream::ByteOrder byteOrder)
206
0
{
207
0
    QByteArray copy = buffer;
208
0
    QDataStream s(&copy, QIODevice::ReadOnly);
209
0
    if (ver)
210
0
        s.setVersion(ver);
211
0
    s.setByteOrder(byteOrder);
212
0
    QRegion rgn;
213
0
#ifndef QT_NO_DEBUG
214
0
    int test_cnt = 0;
215
0
#endif
216
0
    while (!s.atEnd()) {
217
0
        qint32 id;
218
0
        if (s.version() == 1) {
219
0
            int id_int;
220
0
            s >> id_int;
221
0
            id = id_int;
222
0
        } else {
223
0
            s >> id;
224
0
        }
225
0
#ifndef QT_NO_DEBUG
226
0
        if (test_cnt > 0 && id != QRGN_TRANSLATE)
227
0
            qWarning("QRegion::exec: Internal error");
228
0
        test_cnt++;
229
0
#endif
230
0
        if (id == QRGN_SETRECT || id == QRGN_SETELLIPSE) {
231
0
            QRect r;
232
0
            s >> r;
233
0
            rgn = QRegion(r, id == QRGN_SETRECT ? Rectangle : Ellipse);
234
0
        } else if (id == QRGN_SETPTARRAY_ALT || id == QRGN_SETPTARRAY_WIND) {
235
0
            QPolygon a;
236
0
            s >> a;
237
0
            rgn = QRegion(a, id == QRGN_SETPTARRAY_WIND ? Qt::WindingFill : Qt::OddEvenFill);
238
0
        } else if (id == QRGN_TRANSLATE) {
239
0
            QPoint p;
240
0
            s >> p;
241
0
            rgn.translate(p.x(), p.y());
242
0
        } else if (id >= QRGN_OR && id <= QRGN_XOR) {
243
0
            QByteArray bop1, bop2;
244
0
            QRegion r1, r2;
245
0
            s >> bop1;
246
0
            r1.exec(bop1);
247
0
            s >> bop2;
248
0
            r2.exec(bop2);
249
250
0
            switch (id) {
251
0
                case QRGN_OR:
252
0
                    rgn = r1.united(r2);
253
0
                    break;
254
0
                case QRGN_AND:
255
0
                    rgn = r1.intersected(r2);
256
0
                    break;
257
0
                case QRGN_SUB:
258
0
                    rgn = r1.subtracted(r2);
259
0
                    break;
260
0
                case QRGN_XOR:
261
0
                    rgn = r1.xored(r2);
262
0
                    break;
263
0
            }
264
0
        } else if (id == QRGN_RECTS) {
265
            // (This is the only form used in Qt 2.0)
266
0
            quint32 n;
267
0
            s >> n;
268
0
            QRect r;
269
0
            for (int i=0; i < static_cast<int>(n); i++) {
270
0
                s >> r;
271
0
                rgn = rgn.united(QRegion(r));
272
0
            }
273
0
        }
274
0
    }
275
0
    *this = rgn;
276
0
}
277
278
279
/*****************************************************************************
280
  QRegion stream functions
281
 *****************************************************************************/
282
283
/*!
284
    \fn QRegion &QRegion::operator=(const QRegion &r)
285
286
    Assigns \a r to this region and returns a reference to the region.
287
*/
288
289
/*!
290
    \fn QRegion &QRegion::operator=(QRegion &&other)
291
292
    Move-assigns \a other to this QRegion instance.
293
294
    \since 5.2
295
*/
296
297
/*!
298
    \fn void QRegion::swap(QRegion &other)
299
    \since 4.8
300
    \memberswap{region}
301
*/
302
303
/*!
304
    \relates QRegion
305
306
    Writes the region \a r to the stream \a s and returns a reference
307
    to the stream.
308
309
    \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
310
*/
311
312
QDataStream &operator<<(QDataStream &s, const QRegion &r)
313
0
{
314
0
    auto b = r.begin(), e = r.end();
315
0
    if (b == e) {
316
0
        s << static_cast<quint32>(0);
317
0
    } else {
318
0
        const auto size = e - b;
319
0
        if (s.version() == 1) {
320
0
            for (auto i = size - 1; i > 0; --i) {
321
0
                s << static_cast<quint32>(12 + i * 24);
322
0
                s << static_cast<int>(QRGN_OR);
323
0
            }
324
0
            for (auto it = b; it != e; ++it)
325
0
                s << static_cast<quint32>(4+8) << static_cast<int>(QRGN_SETRECT) << *it;
326
0
        } else {
327
0
            s << quint32(4 + 4 + 16 * size); // 16: storage size of QRect
328
0
            s << static_cast<qint32>(QRGN_RECTS);
329
0
            s << quint32(size);
330
0
            for (auto it = b; it != e; ++it)
331
0
                s << *it;
332
0
        }
333
0
    }
334
0
    return s;
335
0
}
336
337
/*!
338
    \relates QRegion
339
340
    Reads a region from the stream \a s into \a r and returns a
341
    reference to the stream.
342
343
    \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
344
*/
345
346
QDataStream &operator>>(QDataStream &s, QRegion &r)
347
0
{
348
0
    QByteArray b;
349
0
    s >> b;
350
0
    r.exec(b, s.version(), s.byteOrder());
351
0
    return s;
352
0
}
353
#endif //QT_NO_DATASTREAM
354
355
#ifndef QT_NO_DEBUG_STREAM
356
QDebug operator<<(QDebug s, const QRegion &r)
357
0
{
358
0
    QDebugStateSaver saver(s);
359
0
    s.nospace();
360
0
    s << "QRegion(";
361
0
    if (r.isNull()) {
362
0
        s << "null";
363
0
    } else if (r.isEmpty()) {
364
0
        s << "empty";
365
0
    } else {
366
0
        const int count = r.rectCount();
367
0
        if (count > 1)
368
0
            s << "size=" << count << ", bounds=(";
369
0
        QtDebugUtils::formatQRect(s, r.boundingRect());
370
0
        if (count > 1) {
371
0
            s << ") - [";
372
0
            bool first = true;
373
0
            for (const QRect &rect : r) {
374
0
                if (!first)
375
0
                    s << ", ";
376
0
                s << '(';
377
0
                QtDebugUtils::formatQRect(s, rect);
378
0
                s << ')';
379
0
                first = false;
380
0
            }
381
0
            s << ']';
382
0
        }
383
0
    }
384
0
    s << ')';
385
0
    return s;
386
0
}
387
#endif
388
389
390
// These are not inline - they can be implemented better on some platforms
391
//  (eg. Windows at least provides 3-variable operations).  For now, simple.
392
393
394
/*!
395
    Applies the united() function to this region and \a r. \c r1|r2 is
396
    equivalent to \c r1.united(r2).
397
398
    \sa united(), operator+()
399
*/
400
QRegion QRegion::operator|(const QRegion &r) const
401
0
    { return united(r); }
402
403
/*!
404
    Applies the united() function to this region and \a r. \c r1+r2 is
405
    equivalent to \c r1.united(r2).
406
407
    \sa united(), operator|()
408
*/
409
QRegion QRegion::operator+(const QRegion &r) const
410
0
    { return united(r); }
411
412
/*!
413
   \overload
414
   \since 4.4
415
 */
416
QRegion QRegion::operator+(const QRect &r) const
417
0
    { return united(r); }
418
419
/*!
420
    Applies the intersected() function to this region and \a r. \c r1&r2
421
    is equivalent to \c r1.intersected(r2).
422
423
    \sa intersected()
424
*/
425
QRegion QRegion::operator&(const QRegion &r) const
426
0
    { return intersected(r); }
427
428
/*!
429
   \overload
430
   \since 4.4
431
 */
432
QRegion QRegion::operator&(const QRect &r) const
433
0
{
434
0
    return intersected(r);
435
0
}
436
437
/*!
438
    Applies the subtracted() function to this region and \a r. \c r1-r2
439
    is equivalent to \c r1.subtracted(r2).
440
441
    \sa subtracted()
442
*/
443
QRegion QRegion::operator-(const QRegion &r) const
444
0
    { return subtracted(r); }
445
446
/*!
447
    Applies the xored() function to this region and \a r. \c r1^r2 is
448
    equivalent to \c r1.xored(r2).
449
450
    \sa xored()
451
*/
452
QRegion QRegion::operator^(const QRegion &r) const
453
0
    { return xored(r); }
454
455
/*!
456
    Applies the united() function to this region and \a r and assigns
457
    the result to this region. \c r1|=r2 is equivalent to \c
458
    {r1 = r1.united(r2)}.
459
460
    \sa united()
461
*/
462
QRegion& QRegion::operator|=(const QRegion &r)
463
0
    { return *this = *this | r; }
464
465
/*!
466
    \fn QRegion& QRegion::operator+=(const QRect &rect)
467
468
    Returns a region that is the union of this region with the specified \a rect.
469
470
    \sa united()
471
*/
472
/*!
473
    \fn QRegion& QRegion::operator+=(const QRegion &r)
474
475
    Applies the united() function to this region and \a r and assigns
476
    the result to this region. \c r1+=r2 is equivalent to \c
477
    {r1 = r1.united(r2)}.
478
479
    \sa intersected()
480
*/
481
482
/*!
483
  \fn QRegion& QRegion::operator&=(const QRegion &r)
484
485
  Applies the intersected() function to this region and \a r and
486
  assigns the result to this region. \c r1&=r2 is equivalent to \c
487
  r1 = r1.intersected(r2).
488
489
  \sa intersected()
490
*/
491
QRegion& QRegion::operator&=(const QRegion &r)
492
0
    { return *this = *this & r; }
493
494
/*!
495
   \overload
496
   \since 4.4
497
 */
498
#if defined (Q_OS_UNIX) || defined (Q_OS_WIN)
499
QRegion& QRegion::operator&=(const QRect &r)
500
0
{
501
0
    return *this = *this & r;
502
0
}
503
#else
504
QRegion& QRegion::operator&=(const QRect &r)
505
{
506
    return *this &= (QRegion(r));
507
}
508
#endif
509
510
/*!
511
  \fn QRegion& QRegion::operator-=(const QRegion &r)
512
513
  Applies the subtracted() function to this region and \a r and
514
  assigns the result to this region. \c r1-=r2 is equivalent to \c
515
  {r1 = r1.subtracted(r2)}.
516
517
  \sa subtracted()
518
*/
519
QRegion& QRegion::operator-=(const QRegion &r)
520
0
    { return *this = *this - r; }
521
522
/*!
523
    Applies the xored() function to this region and \a r and
524
    assigns the result to this region. \c r1^=r2 is equivalent to \c
525
    {r1 = r1.xored(r2)}.
526
527
    \sa xored()
528
*/
529
QRegion& QRegion::operator^=(const QRegion &r)
530
0
    { return *this = *this ^ r; }
531
532
/*!
533
    \fn bool QRegion::operator!=(const QRegion &other) const
534
535
    Returns \c true if this region is different from the \a other region;
536
    otherwise returns \c false.
537
*/
538
539
/*!
540
   Returns the region as a QVariant
541
*/
542
QRegion::operator QVariant() const
543
0
{
544
0
    return QVariant::fromValue(*this);
545
0
}
546
547
/*!
548
    \fn bool QRegion::operator==(const QRegion &r) const
549
550
    Returns \c true if the region is equal to \a r; otherwise returns
551
    false.
552
*/
553
554
/*!
555
    \fn void QRegion::translate(int dx, int dy)
556
557
    Translates (moves) the region \a dx along the X axis and \a dy
558
    along the Y axis.
559
*/
560
561
/*!
562
    \fn QRegion QRegion::translated(const QPoint &p) const
563
    \overload
564
    \since 4.1
565
566
    Returns a copy of the regtion that is translated \a{p}\e{.x()}
567
    along the x axis and \a{p}\e{.y()} along the y axis, relative to
568
    the current position.  Positive values move the rectangle to the
569
    right and down.
570
571
    \sa translate()
572
*/
573
574
/*!
575
    \since 4.1
576
577
    Returns a copy of the region that is translated \a dx along the
578
    x axis and \a dy along the y axis, relative to the current
579
    position. Positive values move the region to the right and
580
    down.
581
582
    \sa translate()
583
*/
584
585
QRegion
586
QRegion::translated(int dx, int dy) const
587
0
{
588
0
    QRegion ret(*this);
589
0
    ret.translate(dx, dy);
590
0
    return ret;
591
0
}
592
593
594
inline bool rect_intersects(const QRect &r1, const QRect &r2)
595
0
{
596
0
    return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
597
0
            r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
598
0
}
599
600
/*!
601
    \since 4.2
602
603
    Returns \c true if this region intersects with \a region, otherwise
604
    returns \c false.
605
*/
606
bool QRegion::intersects(const QRegion &region) const
607
0
{
608
0
    if (isEmpty() || region.isEmpty())
609
0
        return false;
610
611
0
    if (!rect_intersects(boundingRect(), region.boundingRect()))
612
0
        return false;
613
0
    if (rectCount() == 1 && region.rectCount() == 1)
614
0
        return true;
615
616
0
    for (const QRect &myRect : *this)
617
0
        for (const QRect &otherRect : region)
618
0
            if (rect_intersects(myRect, otherRect))
619
0
                return true;
620
0
    return false;
621
0
}
622
623
/*!
624
    \fn bool QRegion::intersects(const QRect &rect) const
625
    \since 4.2
626
627
    Returns \c true if this region intersects with \a rect, otherwise
628
    returns \c false.
629
*/
630
631
632
#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_QDOC)
633
/*
634
    \overload
635
    \since 4.4
636
*/
637
QRegion QRegion::intersect(const QRect &r) const
638
{
639
    return intersect(QRegion(r));
640
}
641
#endif
642
643
/*!
644
    \fn int QRegion::rectCount() const
645
    \since 4.6
646
647
    Returns the number of rectangles that this region is composed of.
648
    Same as \c{end() - begin()}.
649
*/
650
651
/*!
652
    \fn bool QRegion::isEmpty() const
653
654
    Returns \c true if the region is empty; otherwise returns \c false. An
655
    empty region is a region that contains no points.
656
657
    Example:
658
    \snippet code/src_gui_painting_qregion_unix.cpp 0
659
*/
660
661
/*!
662
    \fn bool QRegion::isNull() const
663
    \since 5.0
664
665
    Returns \c true if the region is empty; otherwise returns \c false. An
666
    empty region is a region that contains no points. This function is
667
    the same as isEmpty
668
669
    \sa isEmpty()
670
*/
671
672
/*!
673
    \fn bool QRegion::contains(const QPoint &p) const
674
675
    Returns \c true if the region contains the point \a p; otherwise
676
    returns \c false.
677
*/
678
679
/*!
680
    \fn bool QRegion::contains(const QRect &r) const
681
    \overload
682
683
    Returns \c true if the region overlaps the rectangle \a r; otherwise
684
    returns \c false.
685
*/
686
687
/*!
688
    \fn QRegion QRegion::united(const QRect &rect) const
689
    \since 4.4
690
691
    Returns a region which is the union of this region and the given \a rect.
692
693
    \sa intersected(), subtracted(), xored()
694
*/
695
696
/*!
697
    \fn QRegion QRegion::united(const QRegion &r) const
698
    \since 4.2
699
700
    Returns a region which is the union of this region and \a r.
701
702
    \image runion.png Region Union
703
704
    The figure shows the union of two elliptical regions.
705
706
    \sa intersected(), subtracted(), xored()
707
*/
708
709
/*!
710
    \fn QRegion QRegion::intersected(const QRect &rect) const
711
    \since 4.4
712
713
    Returns a region which is the intersection of this region and the given \a rect.
714
715
    \sa subtracted(), united(), xored()
716
*/
717
718
/*!
719
    \fn QRegion QRegion::intersected(const QRegion &r) const
720
    \since 4.2
721
722
    Returns a region which is the intersection of this region and \a r.
723
724
    \image rintersect.png Region Intersection
725
726
    The figure shows the intersection of two elliptical regions.
727
728
    \sa subtracted(), united(), xored()
729
*/
730
731
/*!
732
    \fn QRegion QRegion::subtracted(const QRegion &r) const
733
    \since 4.2
734
735
    Returns a region which is \a r subtracted from this region.
736
737
    \image rsubtract.png Region Subtraction
738
739
    The figure shows the result when the ellipse on the right is
740
    subtracted from the ellipse on the left (\c {left - right}).
741
742
    \sa intersected(), united(), xored()
743
*/
744
745
/*!
746
    \fn QRegion QRegion::xored(const QRegion &r) const
747
    \since 4.2
748
749
    Returns a region which is the exclusive or (XOR) of this region
750
    and \a r.
751
752
    \image rxor.png Region XORed
753
754
    The figure shows the exclusive or of two elliptical regions.
755
756
    \sa intersected(), united(), subtracted()
757
*/
758
759
/*!
760
    \fn QRect QRegion::boundingRect() const
761
762
    Returns the bounding rectangle of this region. An empty region
763
    gives a rectangle that is QRect::isNull().
764
*/
765
766
/*!
767
    \typedef QRegion::const_iterator
768
    \since 5.8
769
770
    An iterator over the non-overlapping rectangles that make up the
771
    region.
772
773
    The union of all the rectangles is equal to the original region.
774
775
    QRegion does not offer mutable iterators.
776
777
    \sa begin(), end()
778
*/
779
780
/*!
781
    \typedef QRegion::const_reverse_iterator
782
    \since 5.8
783
784
    A reverse iterator over the non-overlapping rectangles that make up the
785
    region.
786
787
    The union of all the rectangles is equal to the original region.
788
789
    QRegion does not offer mutable iterators.
790
791
    \sa rbegin(), rend()
792
*/
793
794
/*!
795
    \fn QRegion::begin() const
796
    \since 5.8
797
798
    Returns a const_iterator pointing to the beginning of the range of
799
    non-overlapping rectangles that make up the region.
800
801
    The union of all the rectangles is equal to the original region.
802
803
    \sa rbegin(), cbegin(), end()
804
*/
805
806
/*!
807
    \fn QRegion::cbegin() const
808
    \since 5.8
809
810
    Same as begin().
811
*/
812
813
/*!
814
    \fn QRegion::end() const
815
    \since 5.8
816
817
    Returns a const_iterator pointing to one past the end of
818
    non-overlapping rectangles that make up the region.
819
820
    The union of all the rectangles is equal to the original region.
821
822
    \sa rend(), cend(), begin()
823
*/
824
825
/*!
826
    \fn QRegion::cend() const
827
    \since 5.8
828
829
    Same as end().
830
*/
831
832
/*!
833
    \fn QRegion::rbegin() const
834
    \since 5.8
835
836
    Returns a const_reverse_iterator pointing to the beginning of the
837
    range of non-overlapping rectangles that make up the region.
838
839
    The union of all the rectangles is equal to the original region.
840
841
    \sa begin(), crbegin(), rend()
842
*/
843
844
/*!
845
    \fn QRegion::crbegin() const
846
    \since 5.8
847
848
    Same as rbegin().
849
*/
850
851
/*!
852
    \fn QRegion::rend() const
853
    \since 5.8
854
855
    Returns a const_reverse_iterator pointing to one past the end of
856
    the range of non-overlapping rectangles that make up the region.
857
858
    The union of all the rectangles is equal to the original region.
859
860
    \sa end(), crend(), rbegin()
861
*/
862
863
/*!
864
    \fn QRegion::crend() const
865
    \since 5.8
866
867
    Same as rend().
868
*/
869
870
/*!
871
    \fn void QRegion::setRects(const QRect *rects, int number)
872
    \overload
873
    \obsolete Use the QSpan overload instead.
874
*/
875
876
/*!
877
    \fn void QRegion::setRects(QSpan<const QRect> rects)
878
    \since 6.8
879
880
    Sets the region using the array of rectangles specified by \a rects.
881
    The rectangles \e must be optimally Y-X sorted and follow these restrictions:
882
883
    \list
884
    \li The rectangles must not intersect.
885
    \li All rectangles with a given top coordinate must have the same height.
886
    \li No two rectangles may abut horizontally (they should be combined
887
       into a single wider rectangle in that case).
888
    \li The rectangles must be sorted in ascending order, with Y as the major
889
       sort key and X as the minor sort key.
890
    \endlist
891
    \omit
892
    Only some platforms have these restrictions (Qt for Embedded Linux, X11 and \macos).
893
    \endomit
894
895
    \note For historical reasons, \c{rects.size()} must be less than \c{INT_MAX}
896
    (see rectCount()).
897
898
    \sa rects()
899
*/
900
901
namespace {
902
903
struct Segment
904
{
905
0
    Segment() {}
906
    Segment(const QPoint &p)
907
0
        : added(false)
908
0
        , point(p)
909
0
    {
910
0
    }
911
912
    int left() const
913
0
    {
914
0
        return qMin(point.x(), next->point.x());
915
0
    }
916
917
    int right() const
918
0
    {
919
0
        return qMax(point.x(), next->point.x());
920
0
    }
921
922
    bool overlaps(const Segment &other) const
923
0
    {
924
0
        return left() < other.right() && other.left() < right();
925
0
    }
926
927
    void connect(Segment &other)
928
0
    {
929
0
        next = &other;
930
0
        other.prev = this;
931
932
0
        horizontal = (point.y() == other.point.y());
933
0
    }
934
935
    void merge(Segment &other)
936
0
    {
937
0
        if (right() <= other.right()) {
938
0
            QPoint p = other.point;
939
0
            Segment *oprev = other.prev;
940
941
0
            other.point = point;
942
0
            other.prev = prev;
943
0
            prev->next = &other;
944
945
0
            point = p;
946
0
            prev = oprev;
947
0
            oprev->next = this;
948
0
        } else {
949
0
            Segment *onext = other.next;
950
0
            other.next = next;
951
0
            next->prev = &other;
952
953
0
            next = onext;
954
0
            next->prev = this;
955
0
        }
956
0
    }
957
958
    int horizontal : 1;
959
    int added : 1;
960
961
    QPoint point;
962
    Segment *prev;
963
    Segment *next;
964
};
965
966
void mergeSegments(Segment *a, int na, Segment *b, int nb)
967
0
{
968
0
    int i = 0;
969
0
    int j = 0;
970
971
0
    while (i != na && j != nb) {
972
0
        Segment &sa = a[i];
973
0
        Segment &sb = b[j];
974
0
        const int ra = sa.right();
975
0
        const int rb = sb.right();
976
0
        if (sa.overlaps(sb))
977
0
            sa.merge(sb);
978
0
        i += (rb >= ra);
979
0
        j += (ra >= rb);
980
0
    }
981
0
}
982
983
void addSegmentsToPath(Segment *segment, QPainterPath &path)
984
0
{
985
0
    Segment *current = segment;
986
0
    path.moveTo(current->point);
987
988
0
    current->added = true;
989
990
0
    Segment *last = current;
991
0
    current = current->next;
992
0
    while (current != segment) {
993
0
        if (current->horizontal != last->horizontal)
994
0
            path.lineTo(current->point);
995
0
        current->added = true;
996
0
        last = current;
997
0
        current = current->next;
998
0
    }
999
0
}
1000
1001
} // unnamed namespace
1002
1003
// the following is really a lie, because Segments cannot be relocated, as they
1004
// reference each other by address. For the same reason, they aren't even copyable,
1005
// but the code works with the compiler-generated (wrong) copy and move special
1006
// members, so use this as an optimization. The only container these are used in
1007
// (a QVarLengthArray in qt_regionToPath()) is resized once up-front, so doesn't
1008
// have a problem with this, but benefits from not having to run Segment ctors:
1009
Q_DECLARE_TYPEINFO(Segment, Q_PRIMITIVE_TYPE);
1010
1011
Q_GUI_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
1012
0
{
1013
0
    QPainterPath result;
1014
0
    if (region.rectCount() == 1) {
1015
0
        result.addRect(region.boundingRect());
1016
0
        return result;
1017
0
    }
1018
1019
0
    auto rect = region.begin();
1020
0
    const auto end = region.end();
1021
1022
0
    QVarLengthArray<Segment> segments;
1023
0
    segments.resize(4 * (end - rect));
1024
1025
0
    int lastRowSegmentCount = 0;
1026
0
    Segment *lastRowSegments = nullptr;
1027
1028
0
    int lastSegment = 0;
1029
0
    int lastY = 0;
1030
0
    while (rect != end) {
1031
0
        const int y = rect[0].y();
1032
0
        int count = 0;
1033
0
        while (&rect[count] != end && rect[count].y() == y)
1034
0
            ++count;
1035
1036
0
        for (int i = 0; i < count; ++i) {
1037
0
            int offset = lastSegment + i;
1038
0
            segments[offset] = Segment(rect[i].topLeft());
1039
0
            segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
1040
0
            segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
1041
0
            segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
1042
1043
0
            offset = lastSegment + i;
1044
0
            for (int j = 0; j < 4; ++j)
1045
0
                segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
1046
0
        }
1047
1048
0
        if (lastRowSegments && lastY == y)
1049
0
            mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
1050
1051
0
        lastRowSegments = &segments[lastSegment + 2 * count];
1052
0
        lastRowSegmentCount = count;
1053
0
        lastSegment += 4 * count;
1054
0
        lastY = y + rect[0].height();
1055
0
        rect += count;
1056
0
    }
1057
1058
0
    for (int i = 0; i < lastSegment; ++i) {
1059
0
        Segment *segment = &segments[i];
1060
0
        if (!segment->added)
1061
0
            addSegmentsToPath(segment, result);
1062
0
    }
1063
1064
0
    return result;
1065
0
}
1066
1067
//#define QT_REGION_DEBUG
1068
/*
1069
 *   clip region
1070
 */
1071
1072
struct QRegionPrivate {
1073
    int numRects;
1074
    int innerArea;
1075
    QList<QRect> rects;
1076
    QRect extents;
1077
    QRect innerRect;
1078
1079
0
    constexpr QRegionPrivate() : numRects(0), innerArea(-1) {}
1080
    inline QRegionPrivate(const QRect &r)
1081
0
        : numRects(1),
1082
0
          innerArea(r.width() * r.height()),
1083
0
          extents(r),
1084
0
          innerRect(r)
1085
0
    {
1086
0
    }
1087
1088
    void intersect(const QRect &r);
1089
1090
    /*
1091
     * Returns \c true if r is guaranteed to be fully contained in this region.
1092
     * A false return value does not guarantee the opposite.
1093
     */
1094
0
    inline bool contains(const QRegionPrivate &r) const {
1095
0
        return contains(r.extents);
1096
0
    }
1097
1098
0
    inline bool contains(const QRect &r2) const {
1099
0
        const QRect &r1 = innerRect;
1100
0
        return r2.left() >= r1.left() && r2.right() <= r1.right()
1101
0
            && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1102
0
    }
1103
1104
    /*
1105
     * Returns \c true if this region is guaranteed to be fully contained in r.
1106
     */
1107
0
    inline bool within(const QRect &r1) const {
1108
0
        const QRect &r2 = extents;
1109
0
        return r2.left() >= r1.left() && r2.right() <= r1.right()
1110
0
            && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1111
0
    }
1112
1113
0
    inline void updateInnerRect(const QRect &rect) {
1114
0
        const int area = rect.width() * rect.height();
1115
0
        if (area > innerArea) {
1116
0
            innerArea = area;
1117
0
            innerRect = rect;
1118
0
        }
1119
0
    }
1120
1121
0
    inline void vectorize() {
1122
0
        if (numRects == 1) {
1123
0
            if (!rects.size())
1124
0
                rects.resize(1);
1125
0
            rects[0] = extents;
1126
0
        }
1127
0
    }
1128
1129
    const QRect *begin() const noexcept
1130
0
    { return numRects == 1 ? &extents : rects.data(); } // avoid vectorize()
1131
1132
    const QRect *end() const noexcept
1133
0
    { return begin() + numRects; }
1134
1135
    inline void append(const QRect *r);
1136
    void append(const QRegionPrivate *r);
1137
    void prepend(const QRect *r);
1138
    void prepend(const QRegionPrivate *r);
1139
    inline bool canAppend(const QRect *r) const;
1140
    inline bool canAppend(const QRegionPrivate *r) const;
1141
    inline bool canPrepend(const QRect *r) const;
1142
    inline bool canPrepend(const QRegionPrivate *r) const;
1143
1144
    inline bool mergeFromRight(QRect *left, const QRect *right);
1145
    inline bool mergeFromLeft(QRect *left, const QRect *right);
1146
    inline bool mergeFromBelow(QRect *top, const QRect *bottom,
1147
                               const QRect *nextToTop,
1148
                               const QRect *nextToBottom);
1149
    inline bool mergeFromAbove(QRect *bottom, const QRect *top,
1150
                               const QRect *nextToBottom,
1151
                               const QRect *nextToTop);
1152
1153
#ifdef QT_REGION_DEBUG
1154
    void selfTest() const;
1155
#endif
1156
};
1157
1158
static inline bool isEmptyHelper(const QRegionPrivate *preg)
1159
0
{
1160
0
    return !preg || preg->numRects == 0;
1161
0
}
1162
1163
static inline bool canMergeFromRight(const QRect *left, const QRect *right)
1164
0
{
1165
0
    return (right->top() == left->top()
1166
0
            && right->bottom() == left->bottom()
1167
0
            && right->left() <= (left->right() + 1));
1168
0
}
1169
1170
static inline bool canMergeFromLeft(const QRect *right, const QRect *left)
1171
0
{
1172
0
    return canMergeFromRight(left, right);
1173
0
}
1174
1175
bool QRegionPrivate::mergeFromRight(QRect *left, const QRect *right)
1176
0
{
1177
0
    if (canMergeFromRight(left, right)) {
1178
0
        left->setRight(right->right());
1179
0
        updateInnerRect(*left);
1180
0
        return true;
1181
0
    }
1182
0
    return false;
1183
0
}
1184
1185
bool QRegionPrivate::mergeFromLeft(QRect *right, const QRect *left)
1186
0
{
1187
0
    if (canMergeFromLeft(right, left)) {
1188
0
        right->setLeft(left->left());
1189
0
        updateInnerRect(*right);
1190
0
        return true;
1191
0
    }
1192
0
    return false;
1193
0
}
1194
1195
static inline bool canMergeFromBelow(const QRect *top, const QRect *bottom,
1196
                                     const QRect *nextToTop,
1197
                                     const QRect *nextToBottom)
1198
0
{
1199
0
    if (nextToTop && nextToTop->y() == top->y())
1200
0
        return false;
1201
0
    if (nextToBottom && nextToBottom->y() == bottom->y())
1202
0
        return false;
1203
1204
0
    return ((top->bottom() >= (bottom->top() - 1))
1205
0
            && top->left() == bottom->left()
1206
0
            && top->right() == bottom->right());
1207
0
}
1208
1209
bool QRegionPrivate::mergeFromBelow(QRect *top, const QRect *bottom,
1210
                                    const QRect *nextToTop,
1211
                                    const QRect *nextToBottom)
1212
0
{
1213
0
    if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1214
0
        top->setBottom(bottom->bottom());
1215
0
        updateInnerRect(*top);
1216
0
        return true;
1217
0
    }
1218
0
    return false;
1219
0
}
1220
1221
bool QRegionPrivate::mergeFromAbove(QRect *bottom, const QRect *top,
1222
                                    const QRect *nextToBottom,
1223
                                    const QRect *nextToTop)
1224
0
{
1225
0
    if (canMergeFromBelow(top, bottom, nextToTop, nextToBottom)) {
1226
0
        bottom->setTop(top->top());
1227
0
        updateInnerRect(*bottom);
1228
0
        return true;
1229
0
    }
1230
0
    return false;
1231
0
}
1232
1233
static inline QRect qt_rect_intersect_normalized(const QRect &r1,
1234
                                                 const QRect &r2)
1235
0
{
1236
0
    QRect r;
1237
0
    r.setLeft(qMax(r1.left(), r2.left()));
1238
0
    r.setRight(qMin(r1.right(), r2.right()));
1239
0
    r.setTop(qMax(r1.top(), r2.top()));
1240
0
    r.setBottom(qMin(r1.bottom(), r2.bottom()));
1241
0
    return r;
1242
0
}
1243
1244
void QRegionPrivate::intersect(const QRect &rect)
1245
0
{
1246
0
    Q_ASSERT(extents.intersects(rect));
1247
0
    Q_ASSERT(numRects > 1);
1248
1249
#ifdef QT_REGION_DEBUG
1250
    selfTest();
1251
#endif
1252
1253
0
    const QRect r = rect.normalized();
1254
0
    extents = QRect();
1255
0
    innerRect = QRect();
1256
0
    innerArea = -1;
1257
1258
0
    QRect *dest = rects.data();
1259
0
    const QRect *src = dest;
1260
0
    int n = numRects;
1261
0
    numRects = 0;
1262
0
    while (n--) {
1263
0
        *dest = qt_rect_intersect_normalized(*src++, r);
1264
0
        if (dest->isEmpty())
1265
0
            continue;
1266
1267
0
        if (numRects == 0) {
1268
0
            extents = *dest;
1269
0
        } else {
1270
0
            extents.setLeft(qMin(extents.left(), dest->left()));
1271
            // hw: extents.top() will never change after initialization
1272
            //extents.setTop(qMin(extents.top(), dest->top()));
1273
0
            extents.setRight(qMax(extents.right(), dest->right()));
1274
0
            extents.setBottom(qMax(extents.bottom(), dest->bottom()));
1275
1276
0
            const QRect *nextToLast = (numRects > 1 ? dest - 2 : nullptr);
1277
1278
            // mergeFromBelow inlined and optimized
1279
0
            if (canMergeFromBelow(dest - 1, dest, nextToLast, nullptr)) {
1280
0
                if (!n || src->y() != dest->y() || src->left() > r.right()) {
1281
0
                    QRect *prev = dest - 1;
1282
0
                    prev->setBottom(dest->bottom());
1283
0
                    updateInnerRect(*prev);
1284
0
                    continue;
1285
0
                }
1286
0
            }
1287
0
        }
1288
0
        updateInnerRect(*dest);
1289
0
        ++dest;
1290
0
        ++numRects;
1291
0
    }
1292
#ifdef QT_REGION_DEBUG
1293
    selfTest();
1294
#endif
1295
0
}
1296
1297
void QRegionPrivate::append(const QRect *r)
1298
0
{
1299
0
    Q_ASSERT(!r->isEmpty());
1300
1301
0
    QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
1302
0
    if (mergeFromRight(myLast, r)) {
1303
0
        if (numRects > 1) {
1304
0
            const QRect *nextToTop = (numRects > 2 ? myLast - 2 : nullptr);
1305
0
            if (mergeFromBelow(myLast - 1, myLast, nextToTop, nullptr))
1306
0
                --numRects;
1307
0
        }
1308
0
    } else if (mergeFromBelow(myLast, r, (numRects > 1 ? myLast - 1 : nullptr), nullptr)) {
1309
        // nothing
1310
0
    } else {
1311
0
        vectorize();
1312
0
        ++numRects;
1313
0
        updateInnerRect(*r);
1314
0
        if (rects.size() < numRects)
1315
0
            rects.resize(numRects);
1316
0
        rects[numRects - 1] = *r;
1317
0
    }
1318
0
    extents.setCoords(qMin(extents.left(), r->left()),
1319
0
                      qMin(extents.top(), r->top()),
1320
0
                      qMax(extents.right(), r->right()),
1321
0
                      qMax(extents.bottom(), r->bottom()));
1322
1323
#ifdef QT_REGION_DEBUG
1324
    selfTest();
1325
#endif
1326
0
}
1327
1328
void QRegionPrivate::append(const QRegionPrivate *r)
1329
0
{
1330
0
    Q_ASSERT(!isEmptyHelper(r));
1331
1332
0
    if (r->numRects == 1) {
1333
0
        append(&r->extents);
1334
0
        return;
1335
0
    }
1336
1337
0
    vectorize();
1338
1339
0
    QRect *destRect = rects.data() + numRects;
1340
0
    const QRect *srcRect = r->rects.constData();
1341
0
    int numAppend = r->numRects;
1342
1343
    // try merging
1344
0
    {
1345
0
        const QRect *rFirst = srcRect;
1346
0
        QRect *myLast = destRect - 1;
1347
0
        const QRect *nextToLast = (numRects > 1 ? myLast - 1 : nullptr);
1348
0
        if (mergeFromRight(myLast, rFirst)) {
1349
0
            ++srcRect;
1350
0
            --numAppend;
1351
0
            const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 : nullptr);
1352
0
            if (mergeFromBelow(myLast, rFirst + 1, nextToLast, rNextToFirst)) {
1353
0
                ++srcRect;
1354
0
                --numAppend;
1355
0
            }
1356
0
            if (numRects  > 1) {
1357
0
                nextToLast = (numRects > 2 ? myLast - 2 : nullptr);
1358
0
                rNextToFirst = (numAppend > 0 ? srcRect : nullptr);
1359
0
                if (mergeFromBelow(myLast - 1, myLast, nextToLast, rNextToFirst)) {
1360
0
                    --destRect;
1361
0
                    --numRects;
1362
0
                }
1363
0
            }
1364
0
        } else if (mergeFromBelow(myLast, rFirst, nextToLast, rFirst + 1)) {
1365
0
            ++srcRect;
1366
0
            --numAppend;
1367
0
        }
1368
0
    }
1369
1370
    // append rectangles
1371
0
    if (numAppend > 0) {
1372
0
        const int newNumRects = numRects + numAppend;
1373
0
        if (newNumRects > rects.size()) {
1374
0
            rects.resize(newNumRects);
1375
0
            destRect = rects.data() + numRects;
1376
0
        }
1377
0
        memcpy(destRect, srcRect, numAppend * sizeof(QRect));
1378
1379
0
        numRects = newNumRects;
1380
0
    }
1381
1382
    // update inner rectangle
1383
0
    if (innerArea < r->innerArea) {
1384
0
        innerArea = r->innerArea;
1385
0
        innerRect = r->innerRect;
1386
0
    }
1387
1388
    // update extents
1389
0
    destRect = &extents;
1390
0
    srcRect = &r->extents;
1391
0
    extents.setCoords(qMin(destRect->left(), srcRect->left()),
1392
0
                      qMin(destRect->top(), srcRect->top()),
1393
0
                      qMax(destRect->right(), srcRect->right()),
1394
0
                      qMax(destRect->bottom(), srcRect->bottom()));
1395
1396
#ifdef QT_REGION_DEBUG
1397
    selfTest();
1398
#endif
1399
0
}
1400
1401
void QRegionPrivate::prepend(const QRegionPrivate *r)
1402
0
{
1403
0
    Q_ASSERT(!isEmptyHelper(r));
1404
1405
0
    if (r->numRects == 1) {
1406
0
        prepend(&r->extents);
1407
0
        return;
1408
0
    }
1409
1410
0
    vectorize();
1411
1412
0
    int numPrepend = r->numRects;
1413
0
    int numSkip = 0;
1414
1415
    // try merging
1416
0
    {
1417
0
        QRect *myFirst = rects.data();
1418
0
        const QRect *nextToFirst = (numRects > 1 ? myFirst + 1 : nullptr);
1419
0
        const QRect *rLast = r->rects.constData() + r->numRects - 1;
1420
0
        const QRect *rNextToLast = (r->numRects > 1 ? rLast - 1 : nullptr);
1421
0
        if (mergeFromLeft(myFirst, rLast)) {
1422
0
            --numPrepend;
1423
0
            --rLast;
1424
0
            rNextToLast = (numPrepend > 1 ? rLast - 1 : nullptr);
1425
0
            if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1426
0
                --numPrepend;
1427
0
                --rLast;
1428
0
            }
1429
0
            if (numRects  > 1) {
1430
0
                nextToFirst = (numRects > 2? myFirst + 2 : nullptr);
1431
0
                rNextToLast = (numPrepend > 0 ? rLast : nullptr);
1432
0
                if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, rNextToLast)) {
1433
0
                    --numRects;
1434
0
                    ++numSkip;
1435
0
                }
1436
0
            }
1437
0
        } else if (mergeFromAbove(myFirst, rLast, nextToFirst, rNextToLast)) {
1438
0
            --numPrepend;
1439
0
        }
1440
0
    }
1441
1442
0
    if (numPrepend > 0) {
1443
0
        const int newNumRects = numRects + numPrepend;
1444
0
        if (newNumRects > rects.size())
1445
0
            rects.resize(newNumRects);
1446
1447
        // move existing rectangles
1448
0
        memmove(rects.data() + numPrepend, rects.constData() + numSkip,
1449
0
                numRects * sizeof(QRect));
1450
1451
        // prepend new rectangles
1452
0
        memcpy(rects.data(), r->rects.constData(), numPrepend * sizeof(QRect));
1453
1454
0
        numRects = newNumRects;
1455
0
    }
1456
1457
    // update inner rectangle
1458
0
    if (innerArea < r->innerArea) {
1459
0
        innerArea = r->innerArea;
1460
0
        innerRect = r->innerRect;
1461
0
    }
1462
1463
    // update extents
1464
0
    extents.setCoords(qMin(extents.left(), r->extents.left()),
1465
0
                      qMin(extents.top(), r->extents.top()),
1466
0
                      qMax(extents.right(), r->extents.right()),
1467
0
                      qMax(extents.bottom(), r->extents.bottom()));
1468
1469
#ifdef QT_REGION_DEBUG
1470
    selfTest();
1471
#endif
1472
0
}
1473
1474
void QRegionPrivate::prepend(const QRect *r)
1475
0
{
1476
0
    Q_ASSERT(!r->isEmpty());
1477
1478
0
    QRect *myFirst = (numRects == 1 ? &extents : rects.data());
1479
0
    if (mergeFromLeft(myFirst, r)) {
1480
0
        if (numRects > 1) {
1481
0
            const QRect *nextToFirst = (numRects > 2 ? myFirst + 2 : nullptr);
1482
0
            if (mergeFromAbove(myFirst + 1, myFirst, nextToFirst, nullptr)) {
1483
0
                --numRects;
1484
0
                memmove(rects.data(), rects.constData() + 1,
1485
0
                        numRects * sizeof(QRect));
1486
0
            }
1487
0
        }
1488
0
    } else if (mergeFromAbove(myFirst, r, (numRects > 1 ? myFirst + 1 : nullptr), nullptr)) {
1489
        // nothing
1490
0
    } else {
1491
0
        vectorize();
1492
0
        ++numRects;
1493
0
        updateInnerRect(*r);
1494
0
        rects.prepend(*r);
1495
0
    }
1496
0
    extents.setCoords(qMin(extents.left(), r->left()),
1497
0
                      qMin(extents.top(), r->top()),
1498
0
                      qMax(extents.right(), r->right()),
1499
0
                      qMax(extents.bottom(), r->bottom()));
1500
1501
#ifdef QT_REGION_DEBUG
1502
    selfTest();
1503
#endif
1504
0
}
1505
1506
bool QRegionPrivate::canAppend(const QRect *r) const
1507
0
{
1508
0
    Q_ASSERT(!r->isEmpty());
1509
1510
0
    const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
1511
0
    if (r->top() > myLast->bottom())
1512
0
        return true;
1513
0
    if (r->top() == myLast->top()
1514
0
        && r->height() == myLast->height()
1515
0
        && r->left() > myLast->right())
1516
0
    {
1517
0
        return true;
1518
0
    }
1519
1520
0
    return false;
1521
0
}
1522
1523
bool QRegionPrivate::canAppend(const QRegionPrivate *r) const
1524
0
{
1525
0
    return canAppend(r->numRects == 1 ? &r->extents : r->rects.constData());
1526
0
}
1527
1528
bool QRegionPrivate::canPrepend(const QRect *r) const
1529
0
{
1530
0
    Q_ASSERT(!r->isEmpty());
1531
1532
0
    const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
1533
0
    if (r->bottom() < myFirst->top()) // not overlapping
1534
0
        return true;
1535
0
    if (r->top() == myFirst->top()
1536
0
        && r->height() == myFirst->height()
1537
0
        && r->right() < myFirst->left())
1538
0
    {
1539
0
        return true;
1540
0
    }
1541
1542
0
    return false;
1543
0
}
1544
1545
bool QRegionPrivate::canPrepend(const QRegionPrivate *r) const
1546
0
{
1547
0
    return canPrepend(r->numRects == 1 ? &r->extents : r->rects.constData() + r->numRects - 1);
1548
0
}
1549
1550
#ifdef QT_REGION_DEBUG
1551
void QRegionPrivate::selfTest() const
1552
{
1553
    if (numRects == 0) {
1554
        Q_ASSERT(extents.isEmpty());
1555
        Q_ASSERT(innerRect.isEmpty());
1556
        return;
1557
    }
1558
1559
    Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
1560
1561
    if (numRects == 1) {
1562
        Q_ASSERT(innerRect == extents);
1563
        Q_ASSERT(!innerRect.isEmpty());
1564
        return;
1565
    }
1566
1567
    for (int i = 0; i < numRects; ++i) {
1568
        const QRect r = rects.at(i);
1569
        if ((r.width() * r.height()) > innerArea)
1570
            qDebug() << "selfTest(): innerRect" << innerRect << '<' << r;
1571
    }
1572
1573
    QRect r = rects.first();
1574
    for (int i = 1; i < numRects; ++i) {
1575
        const QRect r2 = rects.at(i);
1576
        Q_ASSERT(!r2.isEmpty());
1577
        if (r2.y() == r.y()) {
1578
            Q_ASSERT(r.bottom() == r2.bottom());
1579
            Q_ASSERT(r.right() < (r2.left() + 1));
1580
        } else {
1581
            Q_ASSERT(r2.y() >= r.bottom());
1582
        }
1583
        r = r2;
1584
    }
1585
}
1586
#endif // QT_REGION_DEBUG
1587
1588
Q_CONSTINIT static QRegionPrivate qrp;
1589
Q_CONSTINIT const QRegion::QRegionData QRegion::shared_empty = {Q_REFCOUNT_INITIALIZE_STATIC, &qrp};
1590
1591
typedef void (*OverlapFunc)(QRegionPrivate &dest, const QRect *r1, const QRect *r1End,
1592
                            const QRect *r2, const QRect *r2End, int y1, int y2);
1593
typedef void (*NonOverlapFunc)(QRegionPrivate &dest, const QRect *r, const QRect *rEnd,
1594
                               int y1, int y2);
1595
1596
static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2);
1597
static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest);
1598
static void miRegionOp(QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2,
1599
                       OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
1600
                       NonOverlapFunc nonOverlap2Func);
1601
1602
0
#define RectangleOut 0
1603
#define RectangleIn 1
1604
#define RectanglePart 2
1605
0
#define EvenOddRule 0
1606
0
#define WindingRule 1
1607
1608
// START OF region.h extract
1609
/* $XConsortium: region.h,v 11.14 94/04/17 20:22:20 rws Exp $ */
1610
/************************************************************************
1611
1612
Copyright (c) 1987  X Consortium
1613
1614
Permission is hereby granted, free of charge, to any person obtaining a copy
1615
of this software and associated documentation files (the "Software"), to deal
1616
in the Software without restriction, including without limitation the rights
1617
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1618
copies of the Software, and to permit persons to whom the Software is
1619
furnished to do so, subject to the following conditions:
1620
1621
The above copyright notice and this permission notice shall be included in
1622
all copies or substantial portions of the Software.
1623
1624
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1625
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1626
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1627
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1628
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1629
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1630
1631
Except as contained in this notice, the name of the X Consortium shall not be
1632
used in advertising or otherwise to promote the sale, use or other dealings
1633
in this Software without prior written authorization from the X Consortium.
1634
1635
1636
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
1637
1638
                        All Rights Reserved
1639
1640
Permission to use, copy, modify, and distribute this software and its
1641
documentation for any purpose and without fee is hereby granted,
1642
provided that the above copyright notice appear in all copies and that
1643
both that copyright notice and this permission notice appear in
1644
supporting documentation, and that the name of Digital not be
1645
used in advertising or publicity pertaining to distribution of the
1646
software without specific, written prior permission.
1647
1648
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1649
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1650
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1651
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1652
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1653
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1654
SOFTWARE.
1655
1656
************************************************************************/
1657
1658
#ifndef _XREGION_H
1659
#define _XREGION_H
1660
1661
QT_BEGIN_INCLUDE_NAMESPACE
1662
#include <limits.h>
1663
QT_END_INCLUDE_NAMESPACE
1664
1665
/*  1 if two BOXes overlap.
1666
 *  0 if two BOXes do not overlap.
1667
 *  Remember, x2 and y2 are not in the region
1668
 */
1669
#define EXTENTCHECK(r1, r2) \
1670
0
        ((r1)->right() >= (r2)->left() && \
1671
0
         (r1)->left() <= (r2)->right() && \
1672
0
         (r1)->bottom() >= (r2)->top() && \
1673
0
         (r1)->top() <= (r2)->bottom())
1674
1675
/*
1676
 *  update region extents
1677
 */
1678
#define EXTENTS(r,idRect){\
1679
            if((r)->left() < (idRect)->extents.left())\
1680
              (idRect)->extents.setLeft((r)->left());\
1681
            if((r)->top() < (idRect)->extents.top())\
1682
              (idRect)->extents.setTop((r)->top());\
1683
            if((r)->right() > (idRect)->extents.right())\
1684
              (idRect)->extents.setRight((r)->right());\
1685
            if((r)->bottom() > (idRect)->extents.bottom())\
1686
              (idRect)->extents.setBottom((r)->bottom());\
1687
        }
1688
1689
/*
1690
 *   Check to see if there is enough memory in the present region.
1691
 */
1692
0
#define MEMCHECK(dest, rect, firstrect){\
1693
0
        if ((dest).numRects >= ((dest).rects.size()-1)){\
1694
0
          firstrect.resize(firstrect.size() * 2); \
1695
0
          (rect) = (firstrect).data() + (dest).numRects;\
1696
0
        }\
1697
0
      }
1698
1699
1700
/*
1701
 * number of points to buffer before sending them off
1702
 * to scanlines(): Must be an even number
1703
 */
1704
0
#define NUMPTSTOBUFFER 200
1705
1706
/*
1707
 * used to allocate buffers for points and link
1708
 * the buffers together
1709
 */
1710
typedef struct _POINTBLOCK {
1711
    char data[NUMPTSTOBUFFER * sizeof(QPoint)];
1712
    QPoint *pts;
1713
    struct _POINTBLOCK *next;
1714
} POINTBLOCK;
1715
1716
#endif
1717
// END OF region.h extract
1718
1719
// START OF Region.c extract
1720
/* $XConsortium: Region.c /main/30 1996/10/22 14:21:24 kaleb $ */
1721
/************************************************************************
1722
1723
Copyright (c) 1987, 1988  X Consortium
1724
1725
Permission is hereby granted, free of charge, to any person obtaining a copy
1726
of this software and associated documentation files (the "Software"), to deal
1727
in the Software without restriction, including without limitation the rights
1728
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1729
copies of the Software, and to permit persons to whom the Software is
1730
furnished to do so, subject to the following conditions:
1731
1732
The above copyright notice and this permission notice shall be included in
1733
all copies or substantial portions of the Software.
1734
1735
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1736
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1737
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1738
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1739
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1740
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1741
1742
Except as contained in this notice, the name of the X Consortium shall not be
1743
used in advertising or otherwise to promote the sale, use or other dealings
1744
in this Software without prior written authorization from the X Consortium.
1745
1746
1747
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
1748
1749
                        All Rights Reserved
1750
1751
Permission to use, copy, modify, and distribute this software and its
1752
documentation for any purpose and without fee is hereby granted,
1753
provided that the above copyright notice appear in all copies and that
1754
both that copyright notice and this permission notice appear in
1755
supporting documentation, and that the name of Digital not be
1756
used in advertising or publicity pertaining to distribution of the
1757
software without specific, written prior permission.
1758
1759
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1760
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1761
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1762
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1763
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1764
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1765
SOFTWARE.
1766
1767
************************************************************************/
1768
/*
1769
 * The functions in this file implement the Region abstraction, similar to one
1770
 * used in the X11 sample server. A Region is simply an area, as the name
1771
 * implies, and is implemented as a "y-x-banded" array of rectangles. To
1772
 * explain: Each Region is made up of a certain number of rectangles sorted
1773
 * by y coordinate first, and then by x coordinate.
1774
 *
1775
 * Furthermore, the rectangles are banded such that every rectangle with a
1776
 * given upper-left y coordinate (y1) will have the same lower-right y
1777
 * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
1778
 * will span the entire vertical distance of the band. This means that some
1779
 * areas that could be merged into a taller rectangle will be represented as
1780
 * several shorter rectangles to account for shorter rectangles to its left
1781
 * or right but within its "vertical scope".
1782
 *
1783
 * An added constraint on the rectangles is that they must cover as much
1784
 * horizontal area as possible. E.g. no two rectangles in a band are allowed
1785
 * to touch.
1786
 *
1787
 * Whenever possible, bands will be merged together to cover a greater vertical
1788
 * distance (and thus reduce the number of rectangles). Two bands can be merged
1789
 * only if the bottom of one touches the top of the other and they have
1790
 * rectangles in the same places (of the same width, of course). This maintains
1791
 * the y-x-banding that's so nice to have...
1792
 */
1793
/* $XFree86: xc/lib/X11/Region.c,v 1.1.1.2.2.2 1998/10/04 15:22:50 hohndel Exp $ */
1794
1795
static void UnionRectWithRegion(const QRect *rect, const QRegionPrivate *source,
1796
                                QRegionPrivate &dest)
1797
0
{
1798
0
    if (rect->isEmpty())
1799
0
        return;
1800
1801
0
    Q_ASSERT(EqualRegion(source, &dest));
1802
1803
0
    if (dest.numRects == 0) {
1804
0
        dest = QRegionPrivate(*rect);
1805
0
    } else if (dest.canAppend(rect)) {
1806
0
        dest.append(rect);
1807
0
    } else {
1808
0
        QRegionPrivate p(*rect);
1809
0
        UnionRegion(&p, source, dest);
1810
0
    }
1811
0
}
1812
1813
/*-
1814
 *-----------------------------------------------------------------------
1815
 * miSetExtents --
1816
 *      Reset the extents and innerRect of a region to what they should be.
1817
 *      Called by miSubtract and miIntersect b/c they can't figure it out
1818
 *      along the way or do so easily, as miUnion can.
1819
 *
1820
 * Results:
1821
 *      None.
1822
 *
1823
 * Side Effects:
1824
 *      The region's 'extents' and 'innerRect' structure is overwritten.
1825
 *
1826
 *-----------------------------------------------------------------------
1827
 */
1828
static void miSetExtents(QRegionPrivate &dest)
1829
0
{
1830
0
    const QRect *pBox,
1831
0
                         *pBoxEnd;
1832
0
    QRect *pExtents;
1833
1834
0
    dest.innerRect.setCoords(0, 0, -1, -1);
1835
0
    dest.innerArea = -1;
1836
0
    if (dest.numRects == 0) {
1837
0
        dest.extents.setCoords(0, 0, -1, -1);
1838
0
        return;
1839
0
    }
1840
1841
0
    pExtents = &dest.extents;
1842
0
    if (dest.rects.isEmpty())
1843
0
        pBox = &dest.extents;
1844
0
    else
1845
0
        pBox = dest.rects.constData();
1846
0
    pBoxEnd = pBox + dest.numRects - 1;
1847
1848
    /*
1849
     * Since pBox is the first rectangle in the region, it must have the
1850
     * smallest y1 and since pBoxEnd is the last rectangle in the region,
1851
     * it must have the largest y2, because of banding. Initialize x1 and
1852
     * x2 from  pBox and pBoxEnd, resp., as good things to initialize them
1853
     * to...
1854
     */
1855
0
    pExtents->setLeft(pBox->left());
1856
0
    pExtents->setTop(pBox->top());
1857
0
    pExtents->setRight(pBoxEnd->right());
1858
0
    pExtents->setBottom(pBoxEnd->bottom());
1859
1860
0
    Q_ASSERT(pExtents->top() <= pExtents->bottom());
1861
0
    while (pBox <= pBoxEnd) {
1862
0
        if (pBox->left() < pExtents->left())
1863
0
            pExtents->setLeft(pBox->left());
1864
0
        if (pBox->right() > pExtents->right())
1865
0
            pExtents->setRight(pBox->right());
1866
0
        dest.updateInnerRect(*pBox);
1867
0
        ++pBox;
1868
0
    }
1869
0
    Q_ASSERT(pExtents->left() <= pExtents->right());
1870
0
}
1871
1872
/* TranslateRegion(pRegion, x, y)
1873
   translates in place
1874
   added by raymond
1875
*/
1876
1877
static void OffsetRegion(QRegionPrivate &region, int x, int y)
1878
0
{
1879
0
    if (region.rects.size()) {
1880
0
        QRect *pbox = region.rects.data();
1881
0
        int nbox = region.numRects;
1882
1883
0
        while (nbox--) {
1884
0
            pbox->translate(x, y);
1885
0
            ++pbox;
1886
0
        }
1887
0
    }
1888
0
    region.extents.translate(x, y);
1889
0
    region.innerRect.translate(x, y);
1890
0
}
1891
1892
/*======================================================================
1893
 *          Region Intersection
1894
 *====================================================================*/
1895
/*-
1896
 *-----------------------------------------------------------------------
1897
 * miIntersectO --
1898
 *      Handle an overlapping band for miIntersect.
1899
 *
1900
 * Results:
1901
 *      None.
1902
 *
1903
 * Side Effects:
1904
 *      Rectangles may be added to the region.
1905
 *
1906
 *-----------------------------------------------------------------------
1907
 */
1908
static void miIntersectO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End,
1909
                         const QRect *r2, const QRect *r2End, int y1, int y2)
1910
0
{
1911
0
    int x1;
1912
0
    int x2;
1913
0
    QRect *pNextRect;
1914
1915
0
    pNextRect = dest.rects.data() + dest.numRects;
1916
1917
0
    while (r1 != r1End && r2 != r2End) {
1918
0
        x1 = qMax(r1->left(), r2->left());
1919
0
        x2 = qMin(r1->right(), r2->right());
1920
1921
        /*
1922
         * If there's any overlap between the two rectangles, add that
1923
         * overlap to the new region.
1924
         * There's no need to check for subsumption because the only way
1925
         * such a need could arise is if some region has two rectangles
1926
         * right next to each other. Since that should never happen...
1927
         */
1928
0
        if (x1 <= x2) {
1929
0
            Q_ASSERT(y1 <= y2);
1930
0
            MEMCHECK(dest, pNextRect, dest.rects)
1931
0
            pNextRect->setCoords(x1, y1, x2, y2);
1932
0
            ++dest.numRects;
1933
0
            ++pNextRect;
1934
0
        }
1935
1936
        /*
1937
         * Need to advance the pointers. Shift the one that extends
1938
         * to the right the least, since the other still has a chance to
1939
         * overlap with that region's next rectangle, if you see what I mean.
1940
         */
1941
0
        if (r1->right() < r2->right()) {
1942
0
            ++r1;
1943
0
        } else if (r2->right() < r1->right()) {
1944
0
            ++r2;
1945
0
        } else {
1946
0
            ++r1;
1947
0
            ++r2;
1948
0
        }
1949
0
    }
1950
0
}
1951
1952
/*======================================================================
1953
 *          Generic Region Operator
1954
 *====================================================================*/
1955
1956
/*-
1957
 *-----------------------------------------------------------------------
1958
 * miCoalesce --
1959
 *      Attempt to merge the boxes in the current band with those in the
1960
 *      previous one. Used only by miRegionOp.
1961
 *
1962
 * Results:
1963
 *      The new index for the previous band.
1964
 *
1965
 * Side Effects:
1966
 *      If coalescing takes place:
1967
 *          - rectangles in the previous band will have their y2 fields
1968
 *            altered.
1969
 *          - dest.numRects will be decreased.
1970
 *
1971
 *-----------------------------------------------------------------------
1972
 */
1973
static int miCoalesce(QRegionPrivate &dest, int prevStart, int curStart)
1974
0
{
1975
0
    QRect *pPrevBox;   /* Current box in previous band */
1976
0
    QRect *pCurBox;    /* Current box in current band */
1977
0
    QRect *pRegEnd;    /* End of region */
1978
0
    int curNumRects;    /* Number of rectangles in current band */
1979
0
    int prevNumRects;   /* Number of rectangles in previous band */
1980
0
    int bandY1;         /* Y1 coordinate for current band */
1981
0
    QRect *rData = dest.rects.data();
1982
1983
0
    pRegEnd = rData + dest.numRects;
1984
1985
0
    pPrevBox = rData + prevStart;
1986
0
    prevNumRects = curStart - prevStart;
1987
1988
    /*
1989
     * Figure out how many rectangles are in the current band. Have to do
1990
     * this because multiple bands could have been added in miRegionOp
1991
     * at the end when one region has been exhausted.
1992
     */
1993
0
    pCurBox = rData + curStart;
1994
0
    bandY1 = pCurBox->top();
1995
0
    for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
1996
0
        ++pCurBox;
1997
0
    }
1998
1999
0
    if (pCurBox != pRegEnd) {
2000
        /*
2001
         * If more than one band was added, we have to find the start
2002
         * of the last band added so the next coalescing job can start
2003
         * at the right place... (given when multiple bands are added,
2004
         * this may be pointless -- see above).
2005
         */
2006
0
        --pRegEnd;
2007
0
        while ((pRegEnd - 1)->top() == pRegEnd->top())
2008
0
            --pRegEnd;
2009
0
        curStart = pRegEnd - rData;
2010
0
        pRegEnd = rData + dest.numRects;
2011
0
    }
2012
2013
0
    if (curNumRects == prevNumRects && curNumRects != 0) {
2014
0
        pCurBox -= curNumRects;
2015
        /*
2016
         * The bands may only be coalesced if the bottom of the previous
2017
         * matches the top scanline of the current.
2018
         */
2019
0
        if (pPrevBox->bottom() == pCurBox->top() - 1) {
2020
            /*
2021
             * Make sure the bands have boxes in the same places. This
2022
             * assumes that boxes have been added in such a way that they
2023
             * cover the most area possible. I.e. two boxes in a band must
2024
             * have some horizontal space between them.
2025
             */
2026
0
            do {
2027
0
                if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
2028
                     // The bands don't line up so they can't be coalesced.
2029
0
                    return curStart;
2030
0
                }
2031
0
                ++pPrevBox;
2032
0
                ++pCurBox;
2033
0
                --prevNumRects;
2034
0
            } while (prevNumRects != 0);
2035
2036
0
            dest.numRects -= curNumRects;
2037
0
            pCurBox -= curNumRects;
2038
0
            pPrevBox -= curNumRects;
2039
2040
            /*
2041
             * The bands may be merged, so set the bottom y of each box
2042
             * in the previous band to that of the corresponding box in
2043
             * the current band.
2044
             */
2045
0
            do {
2046
0
                pPrevBox->setBottom(pCurBox->bottom());
2047
0
                dest.updateInnerRect(*pPrevBox);
2048
0
                ++pPrevBox;
2049
0
                ++pCurBox;
2050
0
                curNumRects -= 1;
2051
0
            } while (curNumRects != 0);
2052
2053
            /*
2054
             * If only one band was added to the region, we have to backup
2055
             * curStart to the start of the previous band.
2056
             *
2057
             * If more than one band was added to the region, copy the
2058
             * other bands down. The assumption here is that the other bands
2059
             * came from the same region as the current one and no further
2060
             * coalescing can be done on them since it's all been done
2061
             * already... curStart is already in the right place.
2062
             */
2063
0
            if (pCurBox == pRegEnd) {
2064
0
                curStart = prevStart;
2065
0
            } else {
2066
0
                do {
2067
0
                    *pPrevBox++ = *pCurBox++;
2068
0
                    dest.updateInnerRect(*pPrevBox);
2069
0
                } while (pCurBox != pRegEnd);
2070
0
            }
2071
0
        }
2072
0
    }
2073
0
    return curStart;
2074
0
}
2075
2076
/*-
2077
 *-----------------------------------------------------------------------
2078
 * miRegionOp --
2079
 *      Apply an operation to two regions. Called by miUnion, miInverse,
2080
 *      miSubtract, miIntersect...
2081
 *
2082
 * Results:
2083
 *      None.
2084
 *
2085
 * Side Effects:
2086
 *      The new region is overwritten.
2087
 *
2088
 * Notes:
2089
 *      The idea behind this function is to view the two regions as sets.
2090
 *      Together they cover a rectangle of area that this function divides
2091
 *      into horizontal bands where points are covered only by one region
2092
 *      or by both. For the first case, the nonOverlapFunc is called with
2093
 *      each the band and the band's upper and lower extents. For the
2094
 *      second, the overlapFunc is called to process the entire band. It
2095
 *      is responsible for clipping the rectangles in the band, though
2096
 *      this function provides the boundaries.
2097
 *      At the end of each band, the new region is coalesced, if possible,
2098
 *      to reduce the number of rectangles in the region.
2099
 *
2100
 *-----------------------------------------------------------------------
2101
 */
2102
static void miRegionOp(QRegionPrivate &dest,
2103
                       const QRegionPrivate *reg1, const QRegionPrivate *reg2,
2104
                       OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func,
2105
                       NonOverlapFunc nonOverlap2Func)
2106
0
{
2107
0
    const QRect *r1;         // Pointer into first region
2108
0
    const QRect *r2;         // Pointer into 2d region
2109
0
    const QRect *r1End;               // End of 1st region
2110
0
    const QRect *r2End;               // End of 2d region
2111
0
    int ybot;          // Bottom of intersection
2112
0
    int ytop;          // Top of intersection
2113
0
    int prevBand;               // Index of start of previous band in dest
2114
0
    int curBand;                // Index of start of current band in dest
2115
0
    const QRect *r1BandEnd;  // End of current band in r1
2116
0
    const QRect *r2BandEnd;  // End of current band in r2
2117
0
    int top;                    // Top of non-overlapping band
2118
0
    int bot;                    // Bottom of non-overlapping band
2119
2120
    /*
2121
     * Initialization:
2122
     *  set r1, r2, r1End and r2End appropriately, preserve the important
2123
     * parts of the destination region until the end in case it's one of
2124
     * the two source regions, then mark the "new" region empty, allocating
2125
     * another array of rectangles for it to use.
2126
     */
2127
0
    if (reg1->numRects == 1)
2128
0
        r1 = &reg1->extents;
2129
0
    else
2130
0
        r1 = reg1->rects.constData();
2131
0
    if (reg2->numRects == 1)
2132
0
        r2 = &reg2->extents;
2133
0
    else
2134
0
        r2 = reg2->rects.constData();
2135
2136
0
    r1End = r1 + reg1->numRects;
2137
0
    r2End = r2 + reg2->numRects;
2138
2139
0
    dest.vectorize();
2140
2141
    /*
2142
     * The following calls are going to detach dest.rects. Since dest might be
2143
     * aliasing *reg1 and/or *reg2, and we could have active iterators on
2144
     * reg1->rects and reg2->rects (if the regions have more than 1 rectangle),
2145
     * take a copy of dest.rects to keep those iteractors valid.
2146
     */
2147
0
    const QList<QRect> destRectsCopy = dest.rects;
2148
0
    Q_UNUSED(destRectsCopy);
2149
2150
0
    dest.numRects = 0;
2151
2152
    /*
2153
     * Allocate a reasonable number of rectangles for the new region. The idea
2154
     * is to allocate enough so the individual functions don't need to
2155
     * reallocate and copy the array, which is time consuming, yet we don't
2156
     * have to worry about using too much memory. I hope to be able to
2157
     * nuke the realloc() at the end of this function eventually.
2158
     */
2159
0
    dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2);
2160
2161
    /*
2162
     * Initialize ybot and ytop.
2163
     * In the upcoming loop, ybot and ytop serve different functions depending
2164
     * on whether the band being handled is an overlapping or non-overlapping
2165
     * band.
2166
     *  In the case of a non-overlapping band (only one of the regions
2167
     * has points in the band), ybot is the bottom of the most recent
2168
     * intersection and thus clips the top of the rectangles in that band.
2169
     * ytop is the top of the next intersection between the two regions and
2170
     * serves to clip the bottom of the rectangles in the current band.
2171
     *  For an overlapping band (where the two regions intersect), ytop clips
2172
     * the top of the rectangles of both regions and ybot clips the bottoms.
2173
     */
2174
0
    if (reg1->extents.top() < reg2->extents.top())
2175
0
        ybot = reg1->extents.top() - 1;
2176
0
    else
2177
0
        ybot = reg2->extents.top() - 1;
2178
2179
    /*
2180
     * prevBand serves to mark the start of the previous band so rectangles
2181
     * can be coalesced into larger rectangles. qv. miCoalesce, above.
2182
     * In the beginning, there is no previous band, so prevBand == curBand
2183
     * (curBand is set later on, of course, but the first band will always
2184
     * start at index 0). prevBand and curBand must be indices because of
2185
     * the possible expansion, and resultant moving, of the new region's
2186
     * array of rectangles.
2187
     */
2188
0
    prevBand = 0;
2189
2190
0
    do {
2191
0
        curBand = dest.numRects;
2192
2193
        /*
2194
         * This algorithm proceeds one source-band (as opposed to a
2195
         * destination band, which is determined by where the two regions
2196
         * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
2197
         * rectangle after the last one in the current band for their
2198
         * respective regions.
2199
         */
2200
0
        r1BandEnd = r1;
2201
0
        while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
2202
0
            ++r1BandEnd;
2203
2204
0
        r2BandEnd = r2;
2205
0
        while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
2206
0
            ++r2BandEnd;
2207
2208
        /*
2209
         * First handle the band that doesn't intersect, if any.
2210
         *
2211
         * Note that attention is restricted to one band in the
2212
         * non-intersecting region at once, so if a region has n
2213
         * bands between the current position and the next place it overlaps
2214
         * the other, this entire loop will be passed through n times.
2215
         */
2216
0
        if (r1->top() < r2->top()) {
2217
0
            top = qMax(r1->top(), ybot + 1);
2218
0
            bot = qMin(r1->bottom(), r2->top() - 1);
2219
2220
0
            if (nonOverlap1Func != nullptr && bot >= top)
2221
0
                (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
2222
0
            ytop = r2->top();
2223
0
        } else if (r2->top() < r1->top()) {
2224
0
            top = qMax(r2->top(), ybot + 1);
2225
0
            bot = qMin(r2->bottom(), r1->top() - 1);
2226
2227
0
            if (nonOverlap2Func != nullptr && bot >= top)
2228
0
                (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
2229
0
            ytop = r1->top();
2230
0
        } else {
2231
0
            ytop = r1->top();
2232
0
        }
2233
2234
        /*
2235
         * If any rectangles got added to the region, try and coalesce them
2236
         * with rectangles from the previous band. Note we could just do
2237
         * this test in miCoalesce, but some machines incur a not
2238
         * inconsiderable cost for function calls, so...
2239
         */
2240
0
        if (dest.numRects != curBand)
2241
0
            prevBand = miCoalesce(dest, prevBand, curBand);
2242
2243
        /*
2244
         * Now see if we've hit an intersecting band. The two bands only
2245
         * intersect if ybot >= ytop
2246
         */
2247
0
        ybot = qMin(r1->bottom(), r2->bottom());
2248
0
        curBand = dest.numRects;
2249
0
        if (ybot >= ytop)
2250
0
            (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
2251
2252
0
        if (dest.numRects != curBand)
2253
0
            prevBand = miCoalesce(dest, prevBand, curBand);
2254
2255
        /*
2256
         * If we've finished with a band (y2 == ybot) we skip forward
2257
         * in the region to the next band.
2258
         */
2259
0
        if (r1->bottom() == ybot)
2260
0
            r1 = r1BandEnd;
2261
0
        if (r2->bottom() == ybot)
2262
0
            r2 = r2BandEnd;
2263
0
    } while (r1 != r1End && r2 != r2End);
2264
2265
    /*
2266
     * Deal with whichever region still has rectangles left.
2267
     */
2268
0
    curBand = dest.numRects;
2269
0
    if (r1 != r1End) {
2270
0
        if (nonOverlap1Func != nullptr) {
2271
0
            do {
2272
0
                r1BandEnd = r1;
2273
0
                while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
2274
0
                    ++r1BandEnd;
2275
0
                (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
2276
0
                r1 = r1BandEnd;
2277
0
            } while (r1 != r1End);
2278
0
        }
2279
0
    } else if ((r2 != r2End) && (nonOverlap2Func != nullptr)) {
2280
0
        do {
2281
0
            r2BandEnd = r2;
2282
0
            while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
2283
0
                 ++r2BandEnd;
2284
0
            (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
2285
0
            r2 = r2BandEnd;
2286
0
        } while (r2 != r2End);
2287
0
    }
2288
2289
0
    if (dest.numRects != curBand)
2290
0
        (void)miCoalesce(dest, prevBand, curBand);
2291
2292
    /*
2293
     * A bit of cleanup. To keep regions from growing without bound,
2294
     * we shrink the array of rectangles to match the new number of
2295
     * rectangles in the region.
2296
     *
2297
     * Only do this stuff if the number of rectangles allocated is more than
2298
     * twice the number of rectangles in the region (a simple optimization).
2299
     */
2300
0
    if (qMax(4, dest.numRects) < (dest.rects.size() >> 1))
2301
0
        dest.rects.resize(dest.numRects);
2302
0
}
2303
2304
/*======================================================================
2305
 *          Region Union
2306
 *====================================================================*/
2307
2308
/*-
2309
 *-----------------------------------------------------------------------
2310
 * miUnionNonO --
2311
 *      Handle a non-overlapping band for the union operation. Just
2312
 *      Adds the rectangles into the region. Doesn't have to check for
2313
 *      subsumption or anything.
2314
 *
2315
 * Results:
2316
 *      None.
2317
 *
2318
 * Side Effects:
2319
 *      dest.numRects is incremented and the final rectangles overwritten
2320
 *      with the rectangles we're passed.
2321
 *
2322
 *-----------------------------------------------------------------------
2323
 */
2324
2325
static void miUnionNonO(QRegionPrivate &dest, const QRect *r, const QRect *rEnd,
2326
                        int y1, int y2)
2327
0
{
2328
0
    QRect *pNextRect;
2329
2330
0
    pNextRect = dest.rects.data() + dest.numRects;
2331
2332
0
    Q_ASSERT(y1 <= y2);
2333
2334
0
    while (r != rEnd) {
2335
0
        Q_ASSERT(r->left() <= r->right());
2336
0
        MEMCHECK(dest, pNextRect, dest.rects)
2337
0
        pNextRect->setCoords(r->left(), y1, r->right(), y2);
2338
0
        dest.numRects++;
2339
0
        ++pNextRect;
2340
0
        ++r;
2341
0
    }
2342
0
}
2343
2344
2345
/*-
2346
 *-----------------------------------------------------------------------
2347
 * miUnionO --
2348
 *      Handle an overlapping band for the union operation. Picks the
2349
 *      left-most rectangle each time and merges it into the region.
2350
 *
2351
 * Results:
2352
 *      None.
2353
 *
2354
 * Side Effects:
2355
 *      Rectangles are overwritten in dest.rects and dest.numRects will
2356
 *      be changed.
2357
 *
2358
 *-----------------------------------------------------------------------
2359
 */
2360
2361
static void miUnionO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End,
2362
                     const QRect *r2, const QRect *r2End, int y1, int y2)
2363
0
{
2364
0
    QRect *pNextRect;
2365
2366
0
    pNextRect = dest.rects.data() + dest.numRects;
2367
2368
0
#define MERGERECT(r)             \
2369
0
    if ((dest.numRects != 0) &&  \
2370
0
        (pNextRect[-1].top() == y1) &&  \
2371
0
        (pNextRect[-1].bottom() == y2) &&  \
2372
0
        (pNextRect[-1].right() >= r->left()-1)) { \
2373
0
        if (pNextRect[-1].right() < r->right()) { \
2374
0
            pNextRect[-1].setRight(r->right());  \
2375
0
            dest.updateInnerRect(pNextRect[-1]); \
2376
0
            Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \
2377
0
        }  \
2378
0
    } else { \
2379
0
        MEMCHECK(dest, pNextRect, dest.rects)  \
2380
0
        pNextRect->setCoords(r->left(), y1, r->right(), y2); \
2381
0
        dest.updateInnerRect(*pNextRect); \
2382
0
        dest.numRects++;  \
2383
0
        pNextRect++;  \
2384
0
    }  \
2385
0
    r++;
2386
2387
0
    Q_ASSERT(y1 <= y2);
2388
0
    while (r1 != r1End && r2 != r2End) {
2389
0
        if (r1->left() < r2->left()) {
2390
0
            MERGERECT(r1)
2391
0
        } else {
2392
0
            MERGERECT(r2)
2393
0
        }
2394
0
    }
2395
2396
0
    if (r1 != r1End) {
2397
0
        do {
2398
0
            MERGERECT(r1)
2399
0
        } while (r1 != r1End);
2400
0
    } else {
2401
0
        while (r2 != r2End) {
2402
0
            MERGERECT(r2)
2403
0
        }
2404
0
    }
2405
0
}
2406
2407
static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
2408
0
{
2409
0
    Q_ASSERT(!isEmptyHelper(reg1) && !isEmptyHelper(reg2));
2410
0
    Q_ASSERT(!reg1->contains(*reg2));
2411
0
    Q_ASSERT(!reg2->contains(*reg1));
2412
0
    Q_ASSERT(!EqualRegion(reg1, reg2));
2413
0
    Q_ASSERT(!reg1->canAppend(reg2));
2414
0
    Q_ASSERT(!reg2->canAppend(reg1));
2415
2416
0
    if (reg1->innerArea > reg2->innerArea) {
2417
0
        dest.innerArea = reg1->innerArea;
2418
0
        dest.innerRect = reg1->innerRect;
2419
0
    } else {
2420
0
        dest.innerArea = reg2->innerArea;
2421
0
        dest.innerRect = reg2->innerRect;
2422
0
    }
2423
0
    miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
2424
2425
0
    dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
2426
0
                           qMin(reg1->extents.top(), reg2->extents.top()),
2427
0
                           qMax(reg1->extents.right(), reg2->extents.right()),
2428
0
                           qMax(reg1->extents.bottom(), reg2->extents.bottom()));
2429
0
}
2430
2431
/*======================================================================
2432
 *        Region Subtraction
2433
 *====================================================================*/
2434
2435
/*-
2436
 *-----------------------------------------------------------------------
2437
 * miSubtractNonO --
2438
 *      Deal with non-overlapping band for subtraction. Any parts from
2439
 *      region 2 we discard. Anything from region 1 we add to the region.
2440
 *
2441
 * Results:
2442
 *      None.
2443
 *
2444
 * Side Effects:
2445
 *      dest may be affected.
2446
 *
2447
 *-----------------------------------------------------------------------
2448
 */
2449
2450
static void miSubtractNonO1(QRegionPrivate &dest, const QRect *r,
2451
                            const QRect *rEnd, int y1, int y2)
2452
0
{
2453
0
    QRect *pNextRect;
2454
2455
0
    pNextRect = dest.rects.data() + dest.numRects;
2456
2457
0
    Q_ASSERT(y1<=y2);
2458
2459
0
    while (r != rEnd) {
2460
0
        Q_ASSERT(r->left() <= r->right());
2461
0
        MEMCHECK(dest, pNextRect, dest.rects)
2462
0
        pNextRect->setCoords(r->left(), y1, r->right(), y2);
2463
0
        ++dest.numRects;
2464
0
        ++pNextRect;
2465
0
        ++r;
2466
0
    }
2467
0
}
2468
2469
/*-
2470
 *-----------------------------------------------------------------------
2471
 * miSubtractO --
2472
 *      Overlapping band subtraction. x1 is the left-most point not yet
2473
 *      checked.
2474
 *
2475
 * Results:
2476
 *      None.
2477
 *
2478
 * Side Effects:
2479
 *      dest may have rectangles added to it.
2480
 *
2481
 *-----------------------------------------------------------------------
2482
 */
2483
2484
static void miSubtractO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End,
2485
                        const QRect *r2, const QRect *r2End, int y1, int y2)
2486
0
{
2487
0
    QRect *pNextRect;
2488
0
    int x1;
2489
2490
0
    x1 = r1->left();
2491
2492
0
    Q_ASSERT(y1 <= y2);
2493
0
    pNextRect = dest.rects.data() + dest.numRects;
2494
2495
0
    while (r1 != r1End && r2 != r2End) {
2496
0
        if (r2->right() < x1) {
2497
            /*
2498
             * Subtrahend missed the boat: go to next subtrahend.
2499
             */
2500
0
            ++r2;
2501
0
        } else if (r2->left() <= x1) {
2502
            /*
2503
             * Subtrahend precedes minuend: nuke left edge of minuend.
2504
             */
2505
0
            x1 = r2->right() + 1;
2506
0
            if (x1 > r1->right()) {
2507
                /*
2508
                 * Minuend completely covered: advance to next minuend and
2509
                 * reset left fence to edge of new minuend.
2510
                 */
2511
0
                ++r1;
2512
0
                if (r1 != r1End)
2513
0
                    x1 = r1->left();
2514
0
            } else {
2515
                // Subtrahend now used up since it doesn't extend beyond minuend
2516
0
                ++r2;
2517
0
            }
2518
0
        } else if (r2->left() <= r1->right()) {
2519
            /*
2520
             * Left part of subtrahend covers part of minuend: add uncovered
2521
             * part of minuend to region and skip to next subtrahend.
2522
             */
2523
0
            Q_ASSERT(x1 < r2->left());
2524
0
            MEMCHECK(dest, pNextRect, dest.rects)
2525
0
            pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
2526
0
            ++dest.numRects;
2527
0
            ++pNextRect;
2528
2529
0
            x1 = r2->right() + 1;
2530
0
            if (x1 > r1->right()) {
2531
                /*
2532
                 * Minuend used up: advance to new...
2533
                 */
2534
0
                ++r1;
2535
0
                if (r1 != r1End)
2536
0
                    x1 = r1->left();
2537
0
            } else {
2538
                // Subtrahend used up
2539
0
                ++r2;
2540
0
            }
2541
0
        } else {
2542
            /*
2543
             * Minuend used up: add any remaining piece before advancing.
2544
             */
2545
0
            if (r1->right() >= x1) {
2546
0
                MEMCHECK(dest, pNextRect, dest.rects)
2547
0
                pNextRect->setCoords(x1, y1, r1->right(), y2);
2548
0
                ++dest.numRects;
2549
0
                ++pNextRect;
2550
0
            }
2551
0
            ++r1;
2552
0
            if (r1 != r1End)
2553
0
                x1 = r1->left();
2554
0
        }
2555
0
    }
2556
2557
    /*
2558
     * Add remaining minuend rectangles to region.
2559
     */
2560
0
    while (r1 != r1End) {
2561
0
        Q_ASSERT(x1 <= r1->right());
2562
0
        MEMCHECK(dest, pNextRect, dest.rects)
2563
0
        pNextRect->setCoords(x1, y1, r1->right(), y2);
2564
0
        ++dest.numRects;
2565
0
        ++pNextRect;
2566
2567
0
        ++r1;
2568
0
        if (r1 != r1End)
2569
0
            x1 = r1->left();
2570
0
    }
2571
0
}
2572
2573
/*-
2574
 *-----------------------------------------------------------------------
2575
 * miSubtract --
2576
 *      Subtract regS from regM and leave the result in regD.
2577
 *      S stands for subtrahend, M for minuend and D for difference.
2578
 *
2579
 * Side Effects:
2580
 *      regD is overwritten.
2581
 *
2582
 *-----------------------------------------------------------------------
2583
 */
2584
2585
static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS,
2586
                           QRegionPrivate &dest)
2587
0
{
2588
0
    Q_ASSERT(!isEmptyHelper(regM));
2589
0
    Q_ASSERT(!isEmptyHelper(regS));
2590
0
    Q_ASSERT(EXTENTCHECK(&regM->extents, &regS->extents));
2591
0
    Q_ASSERT(!regS->contains(*regM));
2592
0
    Q_ASSERT(!EqualRegion(regM, regS));
2593
2594
0
    miRegionOp(dest, regM, regS, miSubtractO, miSubtractNonO1, nullptr);
2595
2596
    /*
2597
     * Can't alter dest's extents before we call miRegionOp because
2598
     * it might be one of the source regions and miRegionOp depends
2599
     * on the extents of those regions being the unaltered. Besides, this
2600
     * way there's no checking against rectangles that will be nuked
2601
     * due to coalescing, so we have to examine fewer rectangles.
2602
     */
2603
0
    miSetExtents(dest);
2604
0
}
2605
2606
static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
2607
0
{
2608
0
    Q_ASSERT(!isEmptyHelper(sra) && !isEmptyHelper(srb));
2609
0
    Q_ASSERT(EXTENTCHECK(&sra->extents, &srb->extents));
2610
0
    Q_ASSERT(!EqualRegion(sra, srb));
2611
2612
0
    QRegionPrivate tra, trb;
2613
2614
0
    if (!srb->contains(*sra))
2615
0
        SubtractRegion(sra, srb, tra);
2616
0
    if (!sra->contains(*srb))
2617
0
        SubtractRegion(srb, sra, trb);
2618
2619
0
    Q_ASSERT(isEmptyHelper(&trb) || !tra.contains(trb));
2620
0
    Q_ASSERT(isEmptyHelper(&tra) || !trb.contains(tra));
2621
2622
0
    if (isEmptyHelper(&tra)) {
2623
0
        dest = trb;
2624
0
    } else if (isEmptyHelper(&trb)) {
2625
0
        dest = tra;
2626
0
    } else if (tra.canAppend(&trb)) {
2627
0
        dest = tra;
2628
0
        dest.append(&trb);
2629
0
    } else if (trb.canAppend(&tra)) {
2630
0
        dest = trb;
2631
0
        dest.append(&tra);
2632
0
    } else {
2633
0
        UnionRegion(&tra, &trb, dest);
2634
0
    }
2635
0
}
2636
2637
/*
2638
 *      Check to see if two regions are equal
2639
 */
2640
static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
2641
0
{
2642
0
    if (r1->numRects != r2->numRects) {
2643
0
        return false;
2644
0
    } else if (r1->numRects == 0) {
2645
0
        return true;
2646
0
    } else if (r1->extents != r2->extents) {
2647
0
        return false;
2648
0
    } else if (r1->numRects == 1 && r2->numRects == 1) {
2649
0
        return true; // equality tested in previous if-statement
2650
0
    } else {
2651
0
        const QRect *rr1 = (r1->numRects == 1) ? &r1->extents : r1->rects.constData();
2652
0
        const QRect *rr2 = (r2->numRects == 1) ? &r2->extents : r2->rects.constData();
2653
0
        for (int i = 0; i < r1->numRects; ++i, ++rr1, ++rr2) {
2654
0
            if (*rr1 != *rr2)
2655
0
                return false;
2656
0
        }
2657
0
    }
2658
2659
0
    return true;
2660
0
}
2661
2662
static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
2663
0
{
2664
0
    int i;
2665
2666
0
    if (isEmptyHelper(pRegion))
2667
0
        return false;
2668
0
    if (!pRegion->extents.contains(x, y))
2669
0
        return false;
2670
0
    if (pRegion->numRects == 1)
2671
0
        return pRegion->extents.contains(x, y);
2672
0
    if (pRegion->innerRect.contains(x, y))
2673
0
        return true;
2674
0
    for (i = 0; i < pRegion->numRects; ++i) {
2675
0
        if (pRegion->rects[i].contains(x, y))
2676
0
            return true;
2677
0
    }
2678
0
    return false;
2679
0
}
2680
2681
static bool RectInRegion(QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
2682
0
{
2683
0
    const QRect *pbox;
2684
0
    const QRect *pboxEnd;
2685
0
    QRect rect(rx, ry, rwidth, rheight);
2686
0
    QRect *prect = &rect;
2687
0
    int partIn, partOut;
2688
2689
0
    if (!region || region->numRects == 0 || !EXTENTCHECK(&region->extents, prect))
2690
0
        return RectangleOut;
2691
2692
0
    partOut = false;
2693
0
    partIn = false;
2694
2695
    /* can stop when both partOut and partIn are true, or we reach prect->y2 */
2696
0
    pbox = (region->numRects == 1) ? &region->extents : region->rects.constData();
2697
0
    pboxEnd = pbox + region->numRects;
2698
0
    for (; pbox < pboxEnd; ++pbox) {
2699
0
        if (pbox->bottom() < ry)
2700
0
           continue;
2701
2702
0
        if (pbox->top() > ry) {
2703
0
           partOut = true;
2704
0
           if (partIn || pbox->top() > prect->bottom())
2705
0
              break;
2706
0
           ry = pbox->top();
2707
0
        }
2708
2709
0
        if (pbox->right() < rx)
2710
0
           continue;            /* not far enough over yet */
2711
2712
0
        if (pbox->left() > rx) {
2713
0
           partOut = true;      /* missed part of rectangle to left */
2714
0
           if (partIn)
2715
0
              break;
2716
0
        }
2717
2718
0
        if (pbox->left() <= prect->right()) {
2719
0
            partIn = true;      /* definitely overlap */
2720
0
            if (partOut)
2721
0
               break;
2722
0
        }
2723
2724
0
        if (pbox->right() >= prect->right()) {
2725
0
           ry = pbox->bottom() + 1;     /* finished with this band */
2726
0
           if (ry > prect->bottom())
2727
0
              break;
2728
0
           rx = prect->left();  /* reset x out to left again */
2729
0
        } else {
2730
            /*
2731
             * Because boxes in a band are maximal width, if the first box
2732
             * to overlap the rectangle doesn't completely cover it in that
2733
             * band, the rectangle must be partially out, since some of it
2734
             * will be uncovered in that band. partIn will have been set true
2735
             * by now...
2736
             */
2737
0
            break;
2738
0
        }
2739
0
    }
2740
0
    return partIn;
2741
0
}
2742
// END OF Region.c extract
2743
// START OF poly.h extract
2744
/* $XConsortium: poly.h,v 1.4 94/04/17 20:22:19 rws Exp $ */
2745
/************************************************************************
2746
2747
Copyright (c) 1987  X Consortium
2748
2749
Permission is hereby granted, free of charge, to any person obtaining a copy
2750
of this software and associated documentation files (the "Software"), to deal
2751
in the Software without restriction, including without limitation the rights
2752
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2753
copies of the Software, and to permit persons to whom the Software is
2754
furnished to do so, subject to the following conditions:
2755
2756
The above copyright notice and this permission notice shall be included in
2757
all copies or substantial portions of the Software.
2758
2759
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2760
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2761
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2762
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2763
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2764
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2765
2766
Except as contained in this notice, the name of the X Consortium shall not be
2767
used in advertising or otherwise to promote the sale, use or other dealings
2768
in this Software without prior written authorization from the X Consortium.
2769
2770
2771
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2772
2773
                        All Rights Reserved
2774
2775
Permission to use, copy, modify, and distribute this software and its
2776
documentation for any purpose and without fee is hereby granted,
2777
provided that the above copyright notice appear in all copies and that
2778
both that copyright notice and this permission notice appear in
2779
supporting documentation, and that the name of Digital not be
2780
used in advertising or publicity pertaining to distribution of the
2781
software without specific, written prior permission.
2782
2783
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2784
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2785
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2786
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2787
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2788
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2789
SOFTWARE.
2790
2791
************************************************************************/
2792
2793
/*
2794
 *     This file contains a few macros to help track
2795
 *     the edge of a filled object.  The object is assumed
2796
 *     to be filled in scanline order, and thus the
2797
 *     algorithm used is an extension of Bresenham's line
2798
 *     drawing algorithm which assumes that y is always the
2799
 *     major axis.
2800
 *     Since these pieces of code are the same for any filled shape,
2801
 *     it is more convenient to gather the library in one
2802
 *     place, but since these pieces of code are also in
2803
 *     the inner loops of output primitives, procedure call
2804
 *     overhead is out of the question.
2805
 *     See the author for a derivation if needed.
2806
 */
2807
2808
2809
/*
2810
 *  In scan converting polygons, we want to choose those pixels
2811
 *  which are inside the polygon.  Thus, we add .5 to the starting
2812
 *  x coordinate for both left and right edges.  Now we choose the
2813
 *  first pixel which is inside the pgon for the left edge and the
2814
 *  first pixel which is outside the pgon for the right edge.
2815
 *  Draw the left pixel, but not the right.
2816
 *
2817
 *  How to add .5 to the starting x coordinate:
2818
 *      If the edge is moving to the right, then subtract dy from the
2819
 *  error term from the general form of the algorithm.
2820
 *      If the edge is moving to the left, then add dy to the error term.
2821
 *
2822
 *  The reason for the difference between edges moving to the left
2823
 *  and edges moving to the right is simple:  If an edge is moving
2824
 *  to the right, then we want the algorithm to flip immediately.
2825
 *  If it is moving to the left, then we don't want it to flip until
2826
 *  we traverse an entire pixel.
2827
 */
2828
0
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
2829
0
    int dx;      /* local storage */ \
2830
0
\
2831
0
    /* \
2832
0
     *  if the edge is horizontal, then it is ignored \
2833
0
     *  and assumed not to be processed.  Otherwise, do this stuff. \
2834
0
     */ \
2835
0
    if ((dy) != 0) { \
2836
0
        xStart = (x1); \
2837
0
        dx = (x2) - xStart; \
2838
0
        if (dx < 0) { \
2839
0
            m = dx / (dy); \
2840
0
            m1 = m - 1; \
2841
0
            incr1 = -2 * dx + 2 * (dy) * m1; \
2842
0
            incr2 = -2 * dx + 2 * (dy) * m; \
2843
0
            d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
2844
0
        } else { \
2845
0
            m = dx / (dy); \
2846
0
            m1 = m + 1; \
2847
0
            incr1 = 2 * dx - 2 * (dy) * m1; \
2848
0
            incr2 = 2 * dx - 2 * (dy) * m; \
2849
0
            d = -2 * m * (dy) + 2 * dx; \
2850
0
        } \
2851
0
    } \
2852
0
}
2853
2854
0
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
2855
0
    if (m1 > 0) { \
2856
0
        if (d > 0) { \
2857
0
            minval += m1; \
2858
0
            d += incr1; \
2859
0
        } \
2860
0
        else { \
2861
0
            minval += m; \
2862
0
            d += incr2; \
2863
0
        } \
2864
0
    } else {\
2865
0
        if (d >= 0) { \
2866
0
            minval += m1; \
2867
0
            d += incr1; \
2868
0
        } \
2869
0
        else { \
2870
0
            minval += m; \
2871
0
            d += incr2; \
2872
0
        } \
2873
0
    } \
2874
0
}
2875
2876
2877
/*
2878
 *     This structure contains all of the information needed
2879
 *     to run the bresenham algorithm.
2880
 *     The variables may be hardcoded into the declarations
2881
 *     instead of using this structure to make use of
2882
 *     register declarations.
2883
 */
2884
typedef struct {
2885
    int minor_axis;     /* minor axis        */
2886
    int d;              /* decision variable */
2887
    int m, m1;          /* slope and slope+1 */
2888
    int incr1, incr2;   /* error increments */
2889
} BRESINFO;
2890
2891
2892
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
2893
0
        BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
2894
0
                     bres.m, bres.m1, bres.incr1, bres.incr2)
2895
2896
#define BRESINCRPGONSTRUCT(bres) \
2897
0
        BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
2898
2899
2900
2901
/*
2902
 *     These are the data structures needed to scan
2903
 *     convert regions.  Two different scan conversion
2904
 *     methods are available -- the even-odd method, and
2905
 *     the winding number method.
2906
 *     The even-odd rule states that a point is inside
2907
 *     the polygon if a ray drawn from that point in any
2908
 *     direction will pass through an odd number of
2909
 *     path segments.
2910
 *     By the winding number rule, a point is decided
2911
 *     to be inside the polygon if a ray drawn from that
2912
 *     point in any direction passes through a different
2913
 *     number of clockwise and counter-clockwise path
2914
 *     segments.
2915
 *
2916
 *     These data structures are adapted somewhat from
2917
 *     the algorithm in (Foley/Van Dam) for scan converting
2918
 *     polygons.
2919
 *     The basic algorithm is to start at the top (smallest y)
2920
 *     of the polygon, stepping down to the bottom of
2921
 *     the polygon by incrementing the y coordinate.  We
2922
 *     keep a list of edges which the current scanline crosses,
2923
 *     sorted by x.  This list is called the Active Edge Table (AET)
2924
 *     As we change the y-coordinate, we update each entry in
2925
 *     in the active edge table to reflect the edges new xcoord.
2926
 *     This list must be sorted at each scanline in case
2927
 *     two edges intersect.
2928
 *     We also keep a data structure known as the Edge Table (ET),
2929
 *     which keeps track of all the edges which the current
2930
 *     scanline has not yet reached.  The ET is basically a
2931
 *     list of ScanLineList structures containing a list of
2932
 *     edges which are entered at a given scanline.  There is one
2933
 *     ScanLineList per scanline at which an edge is entered.
2934
 *     When we enter a new edge, we move it from the ET to the AET.
2935
 *
2936
 *     From the AET, we can implement the even-odd rule as in
2937
 *     (Foley/Van Dam).
2938
 *     The winding number rule is a little trickier.  We also
2939
 *     keep the EdgeTableEntries in the AET linked by the
2940
 *     nextWETE (winding EdgeTableEntry) link.  This allows
2941
 *     the edges to be linked just as before for updating
2942
 *     purposes, but only uses the edges linked by the nextWETE
2943
 *     link as edges representing spans of the polygon to
2944
 *     drawn (as with the even-odd rule).
2945
 */
2946
2947
/*
2948
 * for the winding number rule
2949
 */
2950
#define CLOCKWISE          1
2951
#define COUNTERCLOCKWISE  -1
2952
2953
typedef struct _EdgeTableEntry {
2954
     int ymax;             /* ycoord at which we exit this edge. */
2955
     int ClockWise;        /* flag for winding number rule       */
2956
     BRESINFO bres;        /* Bresenham info to run the edge     */
2957
     struct _EdgeTableEntry *next;       /* next in the list     */
2958
     struct _EdgeTableEntry *back;       /* for insertion sort   */
2959
     struct _EdgeTableEntry *nextWETE;   /* for winding num rule */
2960
} EdgeTableEntry;
2961
2962
2963
typedef struct _ScanLineList{
2964
     int scanline;              /* the scanline represented */
2965
     EdgeTableEntry *edgelist;  /* header node              */
2966
     struct _ScanLineList *next;  /* next in the list       */
2967
} ScanLineList;
2968
2969
2970
typedef struct {
2971
     int ymax;                 /* ymax for the polygon     */
2972
     int ymin;                 /* ymin for the polygon     */
2973
     ScanLineList scanlines;   /* header node              */
2974
} EdgeTable;
2975
2976
2977
/*
2978
 * Here is a struct to help with storage allocation
2979
 * so we can allocate a big chunk at a time, and then take
2980
 * pieces from this heap when we need to.
2981
 */
2982
0
#define SLLSPERBLOCK 25
2983
2984
typedef struct _ScanLineListBlock {
2985
     ScanLineList SLLs[SLLSPERBLOCK];
2986
     struct _ScanLineListBlock *next;
2987
} ScanLineListBlock;
2988
2989
2990
2991
/*
2992
 *
2993
 *     a few macros for the inner loops of the fill code where
2994
 *     performance considerations don't allow a procedure call.
2995
 *
2996
 *     Evaluate the given edge at the given scanline.
2997
 *     If the edge has expired, then we leave it and fix up
2998
 *     the active edge table; otherwise, we increment the
2999
 *     x value to be ready for the next scanline.
3000
 *     The winding number rule is in effect, so we must notify
3001
 *     the caller when the edge has been removed so he
3002
 *     can reorder the Winding Active Edge Table.
3003
 */
3004
0
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
3005
0
   if (pAET->ymax == y) {          /* leaving this edge */ \
3006
0
      pPrevAET->next = pAET->next; \
3007
0
      pAET = pPrevAET->next; \
3008
0
      fixWAET = 1; \
3009
0
      if (pAET) \
3010
0
         pAET->back = pPrevAET; \
3011
0
   } \
3012
0
   else { \
3013
0
      BRESINCRPGONSTRUCT(pAET->bres) \
3014
0
      pPrevAET = pAET; \
3015
0
      pAET = pAET->next; \
3016
0
   } \
3017
0
}
3018
3019
3020
/*
3021
 *     Evaluate the given edge at the given scanline.
3022
 *     If the edge has expired, then we leave it and fix up
3023
 *     the active edge table; otherwise, we increment the
3024
 *     x value to be ready for the next scanline.
3025
 *     The even-odd rule is in effect.
3026
 */
3027
0
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
3028
0
   if (pAET->ymax == y) {          /* leaving this edge */ \
3029
0
      pPrevAET->next = pAET->next; \
3030
0
      pAET = pPrevAET->next; \
3031
0
      if (pAET) \
3032
0
         pAET->back = pPrevAET; \
3033
0
   } \
3034
0
   else { \
3035
0
      BRESINCRPGONSTRUCT(pAET->bres) \
3036
0
      pPrevAET = pAET; \
3037
0
      pAET = pAET->next; \
3038
0
   } \
3039
0
}
3040
// END OF poly.h extract
3041
// START OF PolyReg.c extract
3042
/* $XConsortium: PolyReg.c,v 11.23 94/11/17 21:59:37 converse Exp $ */
3043
/************************************************************************
3044
3045
Copyright (c) 1987  X Consortium
3046
3047
Permission is hereby granted, free of charge, to any person obtaining a copy
3048
of this software and associated documentation files (the "Software"), to deal
3049
in the Software without restriction, including without limitation the rights
3050
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3051
copies of the Software, and to permit persons to whom the Software is
3052
furnished to do so, subject to the following conditions:
3053
3054
The above copyright notice and this permission notice shall be included in
3055
all copies or substantial portions of the Software.
3056
3057
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3058
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3059
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
3060
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
3061
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3062
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3063
3064
Except as contained in this notice, the name of the X Consortium shall not be
3065
used in advertising or otherwise to promote the sale, use or other dealings
3066
in this Software without prior written authorization from the X Consortium.
3067
3068
3069
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3070
3071
                        All Rights Reserved
3072
3073
Permission to use, copy, modify, and distribute this software and its
3074
documentation for any purpose and without fee is hereby granted,
3075
provided that the above copyright notice appear in all copies and that
3076
both that copyright notice and this permission notice appear in
3077
supporting documentation, and that the name of Digital not be
3078
used in advertising or publicity pertaining to distribution of the
3079
software without specific, written prior permission.
3080
3081
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3082
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3083
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
3084
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
3085
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
3086
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
3087
SOFTWARE.
3088
3089
************************************************************************/
3090
/* $XFree86: xc/lib/X11/PolyReg.c,v 1.1.1.2.8.2 1998/10/04 15:22:49 hohndel Exp $ */
3091
3092
0
#define LARGE_COORDINATE INT_MAX
3093
0
#define SMALL_COORDINATE INT_MIN
3094
3095
/*
3096
 *     InsertEdgeInET
3097
 *
3098
 *     Insert the given edge into the edge table.
3099
 *     First we must find the correct bucket in the
3100
 *     Edge table, then find the right slot in the
3101
 *     bucket.  Finally, we can insert it.
3102
 *
3103
 */
3104
static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline,
3105
                           ScanLineListBlock **SLLBlock, int *iSLLBlock)
3106
0
{
3107
0
    EdgeTableEntry *start, *prev;
3108
0
    ScanLineList *pSLL, *pPrevSLL;
3109
0
    ScanLineListBlock *tmpSLLBlock;
3110
3111
    /*
3112
     * find the right bucket to put the edge into
3113
     */
3114
0
    pPrevSLL = &ET->scanlines;
3115
0
    pSLL = pPrevSLL->next;
3116
0
    while (pSLL && (pSLL->scanline < scanline)) {
3117
0
        pPrevSLL = pSLL;
3118
0
        pSLL = pSLL->next;
3119
0
    }
3120
3121
    /*
3122
     * reassign pSLL (pointer to ScanLineList) if necessary
3123
     */
3124
0
    if ((!pSLL) || (pSLL->scanline > scanline)) {
3125
0
        if (*iSLLBlock > SLLSPERBLOCK-1)
3126
0
        {
3127
0
            tmpSLLBlock =
3128
0
                  (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock));
3129
0
            Q_CHECK_PTR(tmpSLLBlock);
3130
0
            (*SLLBlock)->next = tmpSLLBlock;
3131
0
            tmpSLLBlock->next = (ScanLineListBlock *)nullptr;
3132
0
            *SLLBlock = tmpSLLBlock;
3133
0
            *iSLLBlock = 0;
3134
0
        }
3135
0
        pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3136
3137
0
        pSLL->next = pPrevSLL->next;
3138
0
        pSLL->edgelist = (EdgeTableEntry *)nullptr;
3139
0
        pPrevSLL->next = pSLL;
3140
0
    }
3141
0
    pSLL->scanline = scanline;
3142
3143
    /*
3144
     * now insert the edge in the right bucket
3145
     */
3146
0
    prev = nullptr;
3147
0
    start = pSLL->edgelist;
3148
0
    while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3149
0
        prev = start;
3150
0
        start = start->next;
3151
0
    }
3152
0
    ETE->next = start;
3153
3154
0
    if (prev)
3155
0
        prev->next = ETE;
3156
0
    else
3157
0
        pSLL->edgelist = ETE;
3158
0
}
3159
3160
/*
3161
 *     CreateEdgeTable
3162
 *
3163
 *     This routine creates the edge table for
3164
 *     scan converting polygons.
3165
 *     The Edge Table (ET) looks like:
3166
 *
3167
 *    EdgeTable
3168
 *     --------
3169
 *    |  ymax  |        ScanLineLists
3170
 *    |scanline|-->------------>-------------->...
3171
 *     --------   |scanline|   |scanline|
3172
 *                |edgelist|   |edgelist|
3173
 *                ---------    ---------
3174
 *                    |             |
3175
 *                    |             |
3176
 *                    V             V
3177
 *              list of ETEs   list of ETEs
3178
 *
3179
 *     where ETE is an EdgeTableEntry data structure,
3180
 *     and there is one ScanLineList per scanline at
3181
 *     which an edge is initially entered.
3182
 *
3183
 */
3184
3185
static void CreateETandAET(int count, const QPoint *pts,
3186
                           EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs,
3187
                           ScanLineListBlock *pSLLBlock)
3188
0
{
3189
0
    const QPoint *top,
3190
0
                          *bottom,
3191
0
                          *PrevPt,
3192
0
                          *CurrPt;
3193
0
    int iSLLBlock = 0;
3194
0
    int dy;
3195
3196
0
    Q_ASSERT(count > 1);
3197
3198
    /*
3199
     *  initialize the Active Edge Table
3200
     */
3201
0
    AET->next = nullptr;
3202
0
    AET->back = nullptr;
3203
0
    AET->nextWETE = nullptr;
3204
0
    AET->bres.minor_axis = SMALL_COORDINATE;
3205
3206
    /*
3207
     *  initialize the Edge Table.
3208
     */
3209
0
    ET->scanlines.next = nullptr;
3210
0
    ET->ymax = SMALL_COORDINATE;
3211
0
    ET->ymin = LARGE_COORDINATE;
3212
0
    pSLLBlock->next = nullptr;
3213
3214
0
    PrevPt = &pts[count - 1];
3215
3216
    /*
3217
     *  for each vertex in the array of points.
3218
     *  In this loop we are dealing with two vertices at
3219
     *  a time -- these make up one edge of the polygon.
3220
     */
3221
0
    while (count--) {
3222
0
        CurrPt = pts++;
3223
3224
        /*
3225
         *  find out which point is above and which is below.
3226
         */
3227
0
        if (PrevPt->y() > CurrPt->y()) {
3228
0
            bottom = PrevPt;
3229
0
            top = CurrPt;
3230
0
            pETEs->ClockWise = 0;
3231
0
        } else {
3232
0
            bottom = CurrPt;
3233
0
            top = PrevPt;
3234
0
            pETEs->ClockWise = 1;
3235
0
        }
3236
3237
        /*
3238
         * don't add horizontal edges to the Edge table.
3239
         */
3240
0
        if (bottom->y() != top->y()) {
3241
0
            pETEs->ymax = bottom->y() - 1;  /* -1 so we don't get last scanline */
3242
3243
            /*
3244
             *  initialize integer edge algorithm
3245
             */
3246
0
            dy = bottom->y() - top->y();
3247
0
            BRESINITPGONSTRUCT(dy, top->x(), bottom->x(), pETEs->bres)
3248
3249
0
            InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3250
3251
0
            if (PrevPt->y() > ET->ymax)
3252
0
                ET->ymax = PrevPt->y();
3253
0
            if (PrevPt->y() < ET->ymin)
3254
0
                ET->ymin = PrevPt->y();
3255
0
            ++pETEs;
3256
0
        }
3257
3258
0
        PrevPt = CurrPt;
3259
0
    }
3260
0
}
3261
3262
/*
3263
 *     loadAET
3264
 *
3265
 *     This routine moves EdgeTableEntries from the
3266
 *     EdgeTable into the Active Edge Table,
3267
 *     leaving them sorted by smaller x coordinate.
3268
 *
3269
 */
3270
3271
static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
3272
0
{
3273
0
    EdgeTableEntry *pPrevAET;
3274
0
    EdgeTableEntry *tmp;
3275
3276
0
    pPrevAET = AET;
3277
0
    AET = AET->next;
3278
0
    while (ETEs) {
3279
0
        while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3280
0
            pPrevAET = AET;
3281
0
            AET = AET->next;
3282
0
        }
3283
0
        tmp = ETEs->next;
3284
0
        ETEs->next = AET;
3285
0
        if (AET)
3286
0
            AET->back = ETEs;
3287
0
        ETEs->back = pPrevAET;
3288
0
        pPrevAET->next = ETEs;
3289
0
        pPrevAET = ETEs;
3290
3291
0
        ETEs = tmp;
3292
0
    }
3293
0
}
3294
3295
/*
3296
 *     computeWAET
3297
 *
3298
 *     This routine links the AET by the
3299
 *     nextWETE (winding EdgeTableEntry) link for
3300
 *     use by the winding number rule.  The final
3301
 *     Active Edge Table (AET) might look something
3302
 *     like:
3303
 *
3304
 *     AET
3305
 *     ----------  ---------   ---------
3306
 *     |ymax    |  |ymax    |  |ymax    |
3307
 *     | ...    |  |...     |  |...     |
3308
 *     |next    |->|next    |->|next    |->...
3309
 *     |nextWETE|  |nextWETE|  |nextWETE|
3310
 *     ---------   ---------   ^--------
3311
 *         |                   |       |
3312
 *         V------------------->       V---> ...
3313
 *
3314
 */
3315
static void computeWAET(EdgeTableEntry *AET)
3316
0
{
3317
0
    EdgeTableEntry *pWETE;
3318
0
    int inside = 1;
3319
0
    int isInside = 0;
3320
3321
0
    AET->nextWETE = nullptr;
3322
0
    pWETE = AET;
3323
0
    AET = AET->next;
3324
0
    while (AET) {
3325
0
        if (AET->ClockWise)
3326
0
            ++isInside;
3327
0
        else
3328
0
            --isInside;
3329
3330
0
        if ((!inside && !isInside) || (inside && isInside)) {
3331
0
            pWETE->nextWETE = AET;
3332
0
            pWETE = AET;
3333
0
            inside = !inside;
3334
0
        }
3335
0
        AET = AET->next;
3336
0
    }
3337
0
    pWETE->nextWETE = nullptr;
3338
0
}
3339
3340
/*
3341
 *     InsertionSort
3342
 *
3343
 *     Just a simple insertion sort using
3344
 *     pointers and back pointers to sort the Active
3345
 *     Edge Table.
3346
 *
3347
 */
3348
3349
static int InsertionSort(EdgeTableEntry *AET)
3350
0
{
3351
0
    EdgeTableEntry *pETEchase;
3352
0
    EdgeTableEntry *pETEinsert;
3353
0
    EdgeTableEntry *pETEchaseBackTMP;
3354
0
    int changed = 0;
3355
3356
0
    AET = AET->next;
3357
0
    while (AET) {
3358
0
        pETEinsert = AET;
3359
0
        pETEchase = AET;
3360
0
        while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3361
0
            pETEchase = pETEchase->back;
3362
3363
0
        AET = AET->next;
3364
0
        if (pETEchase != pETEinsert) {
3365
0
            pETEchaseBackTMP = pETEchase->back;
3366
0
            pETEinsert->back->next = AET;
3367
0
            if (AET)
3368
0
                AET->back = pETEinsert->back;
3369
0
            pETEinsert->next = pETEchase;
3370
0
            pETEchase->back->next = pETEinsert;
3371
0
            pETEchase->back = pETEinsert;
3372
0
            pETEinsert->back = pETEchaseBackTMP;
3373
0
            changed = 1;
3374
0
        }
3375
0
    }
3376
0
    return changed;
3377
0
}
3378
3379
/*
3380
 *     Clean up our act.
3381
 */
3382
static void FreeStorage(ScanLineListBlock *pSLLBlock)
3383
0
{
3384
0
    ScanLineListBlock *tmpSLLBlock;
3385
3386
0
    while (pSLLBlock) {
3387
0
        tmpSLLBlock = pSLLBlock->next;
3388
0
        free(pSLLBlock);
3389
0
        pSLLBlock = tmpSLLBlock;
3390
0
    }
3391
0
}
3392
3393
struct QRegionSpan {
3394
0
    QRegionSpan() {}
3395
0
    QRegionSpan(int x1_, int x2_) : x1(x1_), x2(x2_) {}
3396
3397
    int x1;
3398
    int x2;
3399
0
    int width() const { return x2 - x1; }
3400
};
3401
3402
Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3403
3404
static inline void flushRow(const QRegionSpan *spans, int y, int numSpans, QRegionPrivate *reg, int *lastRow, int *extendTo, bool *needsExtend)
3405
0
{
3406
0
    QRect *regRects = reg->rects.data() + *lastRow;
3407
0
    bool canExtend = reg->rects.size() - *lastRow == numSpans
3408
0
        && !(*needsExtend && *extendTo + 1 != y)
3409
0
        && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
3410
3411
0
    for (int i = 0; i < numSpans && canExtend; ++i) {
3412
0
        if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3413
0
            canExtend = false;
3414
0
    }
3415
3416
0
    if (canExtend) {
3417
0
        *extendTo = y;
3418
0
        *needsExtend = true;
3419
0
    } else {
3420
0
        if (*needsExtend) {
3421
0
            for (int i = 0; i < reg->rects.size() - *lastRow; ++i)
3422
0
                regRects[i].setBottom(*extendTo);
3423
0
        }
3424
3425
0
        *lastRow = reg->rects.size();
3426
0
        reg->rects.reserve(*lastRow + numSpans);
3427
0
        for (int i = 0; i < numSpans; ++i)
3428
0
            reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
3429
3430
0
        if (spans[0].x1 < reg->extents.left())
3431
0
            reg->extents.setLeft(spans[0].x1);
3432
3433
0
        if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3434
0
            reg->extents.setRight(spans[numSpans-1].x2 - 1);
3435
3436
0
        *needsExtend = false;
3437
0
    }
3438
0
}
3439
3440
/*
3441
 *     Create an array of rectangles from a list of points.
3442
 *     If indeed these things (POINTS, RECTS) are the same,
3443
 *     then this proc is still needed, because it allocates
3444
 *     storage for the array, which was allocated on the
3445
 *     stack by the calling procedure.
3446
 *
3447
 */
3448
static void PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
3449
                       POINTBLOCK *FirstPtBlock, QRegionPrivate *reg)
3450
0
{
3451
0
    int lastRow = 0;
3452
0
    int extendTo = 0;
3453
0
    bool needsExtend = false;
3454
0
    QVarLengthArray<QRegionSpan> row;
3455
0
    qsizetype rowSize = 0;
3456
3457
0
    reg->extents.setLeft(INT_MAX);
3458
0
    reg->extents.setRight(INT_MIN);
3459
0
    reg->innerArea = -1;
3460
3461
0
    POINTBLOCK *CurPtBlock = FirstPtBlock;
3462
0
    for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3463
        /* the loop uses 2 points per iteration */
3464
0
        int i = NUMPTSTOBUFFER >> 1;
3465
0
        if (!numFullPtBlocks)
3466
0
            i = iCurPtBlock >> 1;
3467
0
        if(i) {
3468
0
            row.resize(qMax(row.size(), rowSize + i));
3469
0
            for (QPoint *pts = CurPtBlock->pts; i--; pts += 2) {
3470
0
                const int width = pts[1].x() - pts[0].x();
3471
0
                if (width) {
3472
0
                    if (rowSize && row[rowSize-1].x2 == pts[0].x())
3473
0
                        row[rowSize-1].x2 = pts[1].x();
3474
0
                    else
3475
0
                        row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3476
0
                }
3477
3478
0
                if (rowSize) {
3479
0
                    QPoint *next = i ? &pts[2] : (numFullPtBlocks && iCurPtBlock ? CurPtBlock->next->pts : nullptr);
3480
3481
0
                    if (!next || next->y() != pts[0].y()) {
3482
0
                        flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3483
0
                        rowSize = 0;
3484
0
                    }
3485
0
                }
3486
0
            }
3487
0
        }
3488
0
        CurPtBlock = CurPtBlock->next;
3489
0
    }
3490
3491
0
    if (needsExtend) {
3492
0
        for (int i = lastRow; i < reg->rects.size(); ++i)
3493
0
            reg->rects[i].setBottom(extendTo);
3494
0
    }
3495
3496
0
    reg->numRects = reg->rects.size();
3497
3498
0
    if (reg->numRects) {
3499
0
        reg->extents.setTop(reg->rects[0].top());
3500
0
        reg->extents.setBottom(reg->rects[lastRow].bottom());
3501
3502
0
        for (int i = 0; i < reg->rects.size(); ++i)
3503
0
            reg->updateInnerRect(reg->rects[i]);
3504
0
    } else {
3505
0
        reg->extents.setCoords(0, 0, 0, 0);
3506
0
    }
3507
0
}
3508
3509
/*
3510
 *     polytoregion
3511
 *
3512
 *     Scan converts a polygon by returning a run-length
3513
 *     encoding of the resultant bitmap -- the run-length
3514
 *     encoding is in the form of an array of rectangles.
3515
 *
3516
 *     Can return 0 in case of errors.
3517
 */
3518
static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule)
3519
    //Point     *Pts;                /* the pts                 */
3520
    //int       Count;                 /* number of pts           */
3521
    //int       rule;                        /* winding rule */
3522
0
{
3523
0
    QRegionPrivate *region;
3524
0
    EdgeTableEntry *pAET;   /* Active Edge Table       */
3525
0
    int y;                  /* current scanline        */
3526
0
    int iPts = 0;           /* number of pts in buffer */
3527
0
    EdgeTableEntry *pWETE;  /* Winding Edge Table Entry*/
3528
0
    ScanLineList *pSLL;     /* current scanLineList    */
3529
0
    QPoint *pts;             /* output buffer           */
3530
0
    EdgeTableEntry *pPrevAET;        /* ptr to previous AET     */
3531
0
    EdgeTable ET;                    /* header node for ET      */
3532
0
    EdgeTableEntry *AET;             /* header node for AET     */
3533
0
    EdgeTableEntry *pETEs;           /* EdgeTableEntries pool   */
3534
0
    ScanLineListBlock SLLBlock;      /* header for scanlinelist */
3535
0
    int fixWAET = false;
3536
0
    POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers    */
3537
0
    FirstPtBlock.pts = reinterpret_cast<QPoint *>(FirstPtBlock.data);
3538
0
    FirstPtBlock.next = nullptr;
3539
0
    POINTBLOCK *tmpPtBlock;
3540
0
    int numFullPtBlocks = 0;
3541
3542
0
    Q_ASSERT(Count > 1);
3543
3544
0
    region = new QRegionPrivate;
3545
3546
        /* special case a rectangle */
3547
0
    if (((Count == 4) ||
3548
0
         ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
3549
0
         && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
3550
0
               && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
3551
0
               && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
3552
0
               && (Pts[3].y() == Pts[0].y())))) {
3553
0
        int x = qMin(Pts[0].x(), Pts[2].x());
3554
0
        region->extents.setLeft(x);
3555
0
        int y = qMin(Pts[0].y(), Pts[2].y());
3556
0
        region->extents.setTop(y);
3557
0
        region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
3558
0
        region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
3559
0
        if ((region->extents.left() <= region->extents.right()) &&
3560
0
            (region->extents.top() <= region->extents.bottom())) {
3561
0
            region->numRects = 1;
3562
0
            region->innerRect = region->extents;
3563
0
            region->innerArea = region->innerRect.width() * region->innerRect.height();
3564
0
        }
3565
0
        return region;
3566
0
    }
3567
3568
0
    if (!(pETEs = static_cast<EdgeTableEntry *>(malloc(sizeof(EdgeTableEntry) * Count)))) {
3569
0
        delete region;
3570
0
        return nullptr;
3571
0
    }
3572
3573
0
    region->vectorize();
3574
3575
0
    AET = new EdgeTableEntry;
3576
0
    pts = FirstPtBlock.pts;
3577
0
    CreateETandAET(Count, Pts, &ET, AET, pETEs, &SLLBlock);
3578
3579
0
    pSLL = ET.scanlines.next;
3580
0
    curPtBlock = &FirstPtBlock;
3581
3582
    // sanity check that the region won't become too big...
3583
0
    if (ET.ymax - ET.ymin > 100000) {
3584
        // clean up region ptr
3585
0
#ifndef QT_NO_DEBUG
3586
0
        qWarning("QRegion: creating region from big polygon failed...!");
3587
0
#endif
3588
0
        delete AET;
3589
0
        delete region;
3590
0
        return nullptr;
3591
0
    }
3592
3593
3594
0
    QT_TRY {
3595
0
        if (rule == EvenOddRule) {
3596
            /*
3597
             *  for each scanline
3598
             */
3599
0
            for (y = ET.ymin; y < ET.ymax; ++y) {
3600
3601
                /*
3602
                 *  Add a new edge to the active edge table when we
3603
                 *  get to the next edge.
3604
                 */
3605
0
                if (pSLL && y == pSLL->scanline) {
3606
0
                    loadAET(AET, pSLL->edgelist);
3607
0
                    pSLL = pSLL->next;
3608
0
                }
3609
0
                pPrevAET = AET;
3610
0
                pAET = AET->next;
3611
3612
                /*
3613
                 *  for each active edge
3614
                 */
3615
0
                while (pAET) {
3616
0
                    pts->setX(pAET->bres.minor_axis);
3617
0
                    pts->setY(y);
3618
0
                    ++pts;
3619
0
                    ++iPts;
3620
3621
                    /*
3622
                     *  send out the buffer
3623
                     */
3624
0
                    if (iPts == NUMPTSTOBUFFER) {
3625
0
                        tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK));
3626
0
                        Q_CHECK_PTR(tmpPtBlock);
3627
0
                        tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3628
0
                        curPtBlock->next = tmpPtBlock;
3629
0
                        curPtBlock = tmpPtBlock;
3630
0
                        pts = curPtBlock->pts;
3631
0
                        ++numFullPtBlocks;
3632
0
                        iPts = 0;
3633
0
                    }
3634
0
                    EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
3635
0
                }
3636
0
                InsertionSort(AET);
3637
0
            }
3638
0
        } else {
3639
            /*
3640
             *  for each scanline
3641
             */
3642
0
            for (y = ET.ymin; y < ET.ymax; ++y) {
3643
                /*
3644
                 *  Add a new edge to the active edge table when we
3645
                 *  get to the next edge.
3646
                 */
3647
0
                if (pSLL && y == pSLL->scanline) {
3648
0
                    loadAET(AET, pSLL->edgelist);
3649
0
                    computeWAET(AET);
3650
0
                    pSLL = pSLL->next;
3651
0
                }
3652
0
                pPrevAET = AET;
3653
0
                pAET = AET->next;
3654
0
                pWETE = pAET;
3655
3656
                /*
3657
                 *  for each active edge
3658
                 */
3659
0
                while (pAET) {
3660
                    /*
3661
                     *  add to the buffer only those edges that
3662
                     *  are in the Winding active edge table.
3663
                     */
3664
0
                    if (pWETE == pAET) {
3665
0
                        pts->setX(pAET->bres.minor_axis);
3666
0
                        pts->setY(y);
3667
0
                        ++pts;
3668
0
                        ++iPts;
3669
3670
                        /*
3671
                         *  send out the buffer
3672
                         */
3673
0
                        if (iPts == NUMPTSTOBUFFER) {
3674
0
                            tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK)));
3675
0
                            tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data);
3676
0
                            curPtBlock->next = tmpPtBlock;
3677
0
                            curPtBlock = tmpPtBlock;
3678
0
                            pts = curPtBlock->pts;
3679
0
                            ++numFullPtBlocks;
3680
0
                            iPts = 0;
3681
0
                        }
3682
0
                        pWETE = pWETE->nextWETE;
3683
0
                    }
3684
0
                    EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
3685
0
                }
3686
3687
                /*
3688
                 *  recompute the winding active edge table if
3689
                 *  we just resorted or have exited an edge.
3690
                 */
3691
0
                if (InsertionSort(AET) || fixWAET) {
3692
0
                    computeWAET(AET);
3693
0
                    fixWAET = false;
3694
0
                }
3695
0
            }
3696
0
        }
3697
0
    } QT_CATCH(...) {
3698
0
        FreeStorage(SLLBlock.next);
3699
0
        PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3700
0
        for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3701
0
            tmpPtBlock = curPtBlock->next;
3702
0
            free(curPtBlock);
3703
0
            curPtBlock = tmpPtBlock;
3704
0
        }
3705
0
        free(pETEs);
3706
0
        return nullptr; // this function returns 0 in case of an error
3707
0
    }
3708
3709
0
    FreeStorage(SLLBlock.next);
3710
0
    PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3711
0
    for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3712
0
        tmpPtBlock = curPtBlock->next;
3713
0
        free(curPtBlock);
3714
0
        curPtBlock = tmpPtBlock;
3715
0
    }
3716
0
    delete AET;
3717
0
    free(pETEs);
3718
0
    return region;
3719
0
}
3720
// END OF PolyReg.c extract
3721
3722
QRegionPrivate *qt_bitmapToRegion(const QBitmap& bitmap)
3723
0
{
3724
0
    const QImage image = bitmap.toImage();
3725
3726
0
    QRegionPrivate *region = new QRegionPrivate;
3727
3728
0
    QRect xr;
3729
3730
0
#define AddSpan \
3731
0
        { \
3732
0
            xr.setCoords(prev1, y, x-1, y); \
3733
0
            UnionRectWithRegion(&xr, region, *region); \
3734
0
        }
3735
3736
0
    const uchar zero = 0;
3737
0
    bool little = image.format() == QImage::Format_MonoLSB;
3738
3739
0
    int x,
3740
0
        y;
3741
0
    for (y = 0; y < image.height(); ++y) {
3742
0
        const uchar *line = image.constScanLine(y);
3743
0
        int w = image.width();
3744
0
        uchar all = zero;
3745
0
        int prev1 = -1;
3746
0
        for (x = 0; x < w;) {
3747
0
            uchar byte = line[x / 8];
3748
0
            if (x > w - 8 || byte!=all) {
3749
0
                if (little) {
3750
0
                    for (int b = 8; b > 0 && x < w; --b) {
3751
0
                        if (!(byte & 0x01) == !all) {
3752
                            // More of the same
3753
0
                        } else {
3754
                            // A change.
3755
0
                            if (all!=zero) {
3756
0
                                AddSpan
3757
0
                                all = zero;
3758
0
                            } else {
3759
0
                                prev1 = x;
3760
0
                                all = ~zero;
3761
0
                            }
3762
0
                        }
3763
0
                        byte >>= 1;
3764
0
                        ++x;
3765
0
                    }
3766
0
                } else {
3767
0
                    for (int b = 8; b > 0 && x < w; --b) {
3768
0
                        if (!(byte & 0x80) == !all) {
3769
                            // More of the same
3770
0
                        } else {
3771
                            // A change.
3772
0
                            if (all != zero) {
3773
0
                                AddSpan
3774
0
                                all = zero;
3775
0
                            } else {
3776
0
                                prev1 = x;
3777
0
                                all = ~zero;
3778
0
                            }
3779
0
                        }
3780
0
                        byte <<= 1;
3781
0
                        ++x;
3782
0
                    }
3783
0
                }
3784
0
            } else {
3785
0
                x += 8;
3786
0
            }
3787
0
        }
3788
0
        if (all != zero) {
3789
0
            AddSpan
3790
0
        }
3791
0
    }
3792
0
#undef AddSpan
3793
3794
0
    return region;
3795
0
}
3796
3797
QRegion::QRegion()
3798
581k
    : d(const_cast<QRegionData*>(&shared_empty))
3799
581k
{
3800
581k
}
3801
3802
QRegion::QRegion(const QRect &r, RegionType t)
3803
0
{
3804
0
    if (r.isEmpty()) {
3805
0
        d = const_cast<QRegionData*>(&shared_empty);
3806
0
    } else {
3807
0
        d = new QRegionData;
3808
0
        if (t == Rectangle) {
3809
0
            d->qt_rgn = new QRegionPrivate(r);
3810
0
        } else if (t == Ellipse) {
3811
0
            QPainterPath path;
3812
0
            path.addEllipse(r.x(), r.y(), r.width(), r.height());
3813
0
            QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
3814
0
            d->qt_rgn = PolygonRegion(a.constData(), a.size(), EvenOddRule);
3815
0
        }
3816
0
    }
3817
0
}
3818
3819
QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
3820
0
{
3821
0
    if (a.size() > 2) {
3822
0
        QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
3823
0
                                               fillRule == Qt::WindingFill ? WindingRule : EvenOddRule);
3824
0
        if (qt_rgn) {
3825
0
            d =  new QRegionData;
3826
0
            d->qt_rgn = qt_rgn;
3827
0
        } else {
3828
0
            d = const_cast<QRegionData*>(&shared_empty);
3829
0
        }
3830
0
    } else {
3831
0
        d = const_cast<QRegionData*>(&shared_empty);
3832
0
    }
3833
0
}
3834
3835
QRegion::QRegion(const QRegion &r)
3836
42.0k
{
3837
42.0k
    d = r.d;
3838
42.0k
    d->ref.ref();
3839
42.0k
}
3840
3841
3842
QRegion::QRegion(const QBitmap &bm)
3843
0
{
3844
0
    if (bm.isNull()) {
3845
0
        d = const_cast<QRegionData*>(&shared_empty);
3846
0
    } else {
3847
0
        d = new QRegionData;
3848
0
        d->qt_rgn = qt_bitmapToRegion(bm);
3849
0
    }
3850
0
}
3851
3852
void QRegion::cleanUp(QRegion::QRegionData *x)
3853
0
{
3854
0
    delete x->qt_rgn;
3855
0
    delete x;
3856
0
}
3857
3858
QRegion::~QRegion()
3859
656k
{
3860
656k
    if (!d->ref.deref())
3861
0
        cleanUp(d);
3862
656k
}
3863
3864
3865
QRegion &QRegion::operator=(const QRegion &r)
3866
0
{
3867
0
    r.d->ref.ref();
3868
0
    if (!d->ref.deref())
3869
0
        cleanUp(d);
3870
0
    d = r.d;
3871
0
    return *this;
3872
0
}
3873
3874
3875
/*!
3876
    \internal
3877
*/
3878
QRegion QRegion::copy() const
3879
0
{
3880
0
    QRegion r;
3881
0
    auto x = std::make_unique<QRegionData>();
3882
0
    x->ref.initializeOwned();
3883
0
    if (d->qt_rgn)
3884
0
        x->qt_rgn = new QRegionPrivate(*d->qt_rgn);
3885
0
    else
3886
0
        x->qt_rgn = new QRegionPrivate;
3887
0
    if (!r.d->ref.deref())
3888
0
        cleanUp(r.d);
3889
0
    r.d = x.release();
3890
0
    return r;
3891
0
}
3892
3893
bool QRegion::isEmpty() const
3894
126k
{
3895
126k
    return d == &shared_empty || d->qt_rgn->numRects == 0;
3896
126k
}
3897
3898
bool QRegion::isNull() const
3899
0
{
3900
0
    return d == &shared_empty || d->qt_rgn->numRects == 0;
3901
0
}
3902
3903
bool QRegion::contains(const QPoint &p) const
3904
0
{
3905
0
    return PointInRegion(d->qt_rgn, p.x(), p.y());
3906
0
}
3907
3908
bool QRegion::contains(const QRect &r) const
3909
0
{
3910
0
    return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) != RectangleOut;
3911
0
}
3912
3913
3914
3915
void QRegion::translate(int dx, int dy)
3916
0
{
3917
0
    if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
3918
0
        return;
3919
3920
0
    detach();
3921
0
    OffsetRegion(*d->qt_rgn, dx, dy);
3922
0
}
3923
3924
QRegion QRegion::united(const QRegion &r) const
3925
0
{
3926
0
    if (isEmptyHelper(d->qt_rgn))
3927
0
        return r;
3928
0
    if (isEmptyHelper(r.d->qt_rgn))
3929
0
        return *this;
3930
0
    if (d == r.d)
3931
0
        return *this;
3932
3933
0
    if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3934
0
        return *this;
3935
0
    } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3936
0
        return r;
3937
0
    } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3938
0
        QRegion result(*this);
3939
0
        result.detach();
3940
0
        result.d->qt_rgn->append(r.d->qt_rgn);
3941
0
        return result;
3942
0
    } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3943
0
        QRegion result(*this);
3944
0
        result.detach();
3945
0
        result.d->qt_rgn->prepend(r.d->qt_rgn);
3946
0
        return result;
3947
0
    } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3948
0
        return *this;
3949
0
    } else {
3950
0
        QRegion result;
3951
0
        result.detach();
3952
0
        UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
3953
0
        return result;
3954
0
    }
3955
0
}
3956
3957
QRegion& QRegion::operator+=(const QRegion &r)
3958
0
{
3959
0
    if (isEmptyHelper(d->qt_rgn))
3960
0
        return *this = r;
3961
0
    if (isEmptyHelper(r.d->qt_rgn))
3962
0
        return *this;
3963
0
    if (d == r.d)
3964
0
        return *this;
3965
3966
0
    if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3967
0
        return *this;
3968
0
    } else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3969
0
        return *this = r;
3970
0
    } else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3971
0
        detach();
3972
0
        d->qt_rgn->append(r.d->qt_rgn);
3973
0
        return *this;
3974
0
    } else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3975
0
        detach();
3976
0
        d->qt_rgn->prepend(r.d->qt_rgn);
3977
0
        return *this;
3978
0
    } else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3979
0
        return *this;
3980
0
    } else {
3981
0
        detach();
3982
0
        UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
3983
0
        return *this;
3984
0
    }
3985
0
}
3986
3987
QRegion QRegion::united(const QRect &r) const
3988
0
{
3989
0
    if (isEmptyHelper(d->qt_rgn))
3990
0
        return r;
3991
0
    if (r.isEmpty())
3992
0
        return *this;
3993
3994
0
    if (d->qt_rgn->contains(r)) {
3995
0
        return *this;
3996
0
    } else if (d->qt_rgn->within(r)) {
3997
0
        return r;
3998
0
    } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
3999
0
        return *this;
4000
0
    } else if (d->qt_rgn->canAppend(&r)) {
4001
0
        QRegion result(*this);
4002
0
        result.detach();
4003
0
        result.d->qt_rgn->append(&r);
4004
0
        return result;
4005
0
    } else if (d->qt_rgn->canPrepend(&r)) {
4006
0
        QRegion result(*this);
4007
0
        result.detach();
4008
0
        result.d->qt_rgn->prepend(&r);
4009
0
        return result;
4010
0
    } else {
4011
0
        QRegion result;
4012
0
        result.detach();
4013
0
        QRegionPrivate rp(r);
4014
0
        UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4015
0
        return result;
4016
0
    }
4017
0
}
4018
4019
QRegion& QRegion::operator+=(const QRect &r)
4020
0
{
4021
0
    if (isEmptyHelper(d->qt_rgn))
4022
0
        return *this = r;
4023
0
    if (r.isEmpty())
4024
0
        return *this;
4025
4026
0
    if (d->qt_rgn->contains(r)) {
4027
0
        return *this;
4028
0
    } else if (d->qt_rgn->within(r)) {
4029
0
        return *this = r;
4030
0
    } else if (d->qt_rgn->canAppend(&r)) {
4031
0
        detach();
4032
0
        d->qt_rgn->append(&r);
4033
0
        return *this;
4034
0
    } else if (d->qt_rgn->canPrepend(&r)) {
4035
0
        detach();
4036
0
        d->qt_rgn->prepend(&r);
4037
0
        return *this;
4038
0
    } else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4039
0
        return *this;
4040
0
    } else {
4041
0
        detach();
4042
0
        QRegionPrivate p(r);
4043
0
        UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4044
0
        return *this;
4045
0
    }
4046
0
}
4047
4048
QRegion QRegion::intersected(const QRegion &r) const
4049
0
{
4050
0
    if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4051
0
        || !EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4052
0
        return QRegion();
4053
4054
    /* this is fully contained in r */
4055
0
    if (r.d->qt_rgn->contains(*d->qt_rgn))
4056
0
        return *this;
4057
4058
    /* r is fully contained in this */
4059
0
    if (d->qt_rgn->contains(*r.d->qt_rgn))
4060
0
        return r;
4061
4062
0
    if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
4063
0
        const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
4064
0
                                                        d->qt_rgn->extents);
4065
0
        return QRegion(rect);
4066
0
    } else if (r.d->qt_rgn->numRects == 1) {
4067
0
        QRegion result(*this);
4068
0
        result.detach();
4069
0
        result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4070
0
        return result;
4071
0
    } else if (d->qt_rgn->numRects == 1) {
4072
0
        QRegion result(r);
4073
0
        result.detach();
4074
0
        result.d->qt_rgn->intersect(d->qt_rgn->extents);
4075
0
        return result;
4076
0
    }
4077
4078
0
    QRegion result;
4079
0
    result.detach();
4080
0
    miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO, nullptr, nullptr);
4081
4082
    /*
4083
     * Can't alter dest's extents before we call miRegionOp because
4084
     * it might be one of the source regions and miRegionOp depends
4085
     * on the extents of those regions being the same. Besides, this
4086
     * way there's no checking against rectangles that will be nuked
4087
     * due to coalescing, so we have to examine fewer rectangles.
4088
     */
4089
0
    miSetExtents(*result.d->qt_rgn);
4090
0
    return result;
4091
0
}
4092
4093
QRegion QRegion::intersected(const QRect &r) const
4094
0
{
4095
0
    if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4096
0
        || !EXTENTCHECK(&d->qt_rgn->extents, &r))
4097
0
        return QRegion();
4098
4099
    /* this is fully contained in r */
4100
0
    if (d->qt_rgn->within(r))
4101
0
        return *this;
4102
4103
    /* r is fully contained in this */
4104
0
    if (d->qt_rgn->contains(r))
4105
0
        return r;
4106
4107
0
    if (d->qt_rgn->numRects == 1) {
4108
0
        const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4109
0
                                                        r.normalized());
4110
0
        return QRegion(rect);
4111
0
    }
4112
4113
0
    QRegion result(*this);
4114
0
    result.detach();
4115
0
    result.d->qt_rgn->intersect(r);
4116
0
    return result;
4117
0
}
4118
4119
QRegion QRegion::subtracted(const QRegion &r) const
4120
0
{
4121
0
    if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4122
0
        return *this;
4123
0
    if (r.d->qt_rgn->contains(*d->qt_rgn))
4124
0
        return QRegion();
4125
0
    if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4126
0
        return *this;
4127
0
    if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4128
0
        return QRegion();
4129
4130
#ifdef QT_REGION_DEBUG
4131
    d->qt_rgn->selfTest();
4132
    r.d->qt_rgn->selfTest();
4133
#endif
4134
4135
0
    QRegion result;
4136
0
    result.detach();
4137
0
    SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4138
#ifdef QT_REGION_DEBUG
4139
    result.d->qt_rgn->selfTest();
4140
#endif
4141
0
    return result;
4142
0
}
4143
4144
QRegion QRegion::xored(const QRegion &r) const
4145
0
{
4146
0
    if (isEmptyHelper(d->qt_rgn)) {
4147
0
        return r;
4148
0
    } else if (isEmptyHelper(r.d->qt_rgn)) {
4149
0
        return *this;
4150
0
    } else if (!EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4151
0
        return (*this + r);
4152
0
    } else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4153
0
        return QRegion();
4154
0
    } else {
4155
0
        QRegion result;
4156
0
        result.detach();
4157
0
        XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4158
0
        return result;
4159
0
    }
4160
0
}
4161
4162
QRect QRegion::boundingRect() const noexcept
4163
0
{
4164
0
    if (isEmpty())
4165
0
        return QRect();
4166
0
    return d->qt_rgn->extents;
4167
0
}
4168
4169
/*! \internal
4170
    Returns \c true if \a rect is guaranteed to be fully contained in \a region.
4171
    A false return value does not guarantee the opposite.
4172
*/
4173
Q_GUI_EXPORT
4174
bool qt_region_strictContains(const QRegion &region, const QRect &rect)
4175
0
{
4176
0
    if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4177
0
        return false;
4178
4179
#if 0 // TEST_INNERRECT
4180
    static bool guard = false;
4181
    if (guard)
4182
        return false;
4183
    guard = true;
4184
    QRegion inner = region.d->qt_rgn->innerRect;
4185
    Q_ASSERT((inner - region).isEmpty());
4186
    guard = false;
4187
4188
    int maxArea = 0;
4189
    for (int i = 0; i < region.d->qt_rgn->numRects; ++i) {
4190
        const QRect r = region.d->qt_rgn->rects.at(i);
4191
        if (r.width() * r.height() > maxArea)
4192
            maxArea = r.width() * r.height();
4193
    }
4194
4195
    if (maxArea > region.d->qt_rgn->innerArea) {
4196
        qDebug() << "not largest rectangle" << region << region.d->qt_rgn->innerRect;
4197
    }
4198
    Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
4199
#endif
4200
4201
0
    const QRect r1 = region.d->qt_rgn->innerRect;
4202
0
    return (rect.left() >= r1.left() && rect.right() <= r1.right()
4203
0
            && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
4204
0
}
4205
4206
QRegion::const_iterator QRegion::begin() const noexcept
4207
0
{
4208
0
    return d->qt_rgn ? d->qt_rgn->begin() : nullptr;
4209
0
}
4210
4211
QRegion::const_iterator QRegion::end() const noexcept
4212
0
{
4213
0
    return d->qt_rgn ? d->qt_rgn->end() : nullptr;
4214
0
}
4215
4216
static Q_DECL_COLD_FUNCTION
4217
void set_rects_warn(const char *what)
4218
0
{
4219
0
    qWarning("QRegion::setRects(): %s", what);
4220
0
}
4221
4222
void QRegion::setRects(const QRect *r, int n)
4223
0
{
4224
0
    if (!r && n) { // old setRects() allowed this, but QSpan doesn't
4225
0
        set_rects_warn("passing num != 0 when rects == nullptr is deprecated.");
4226
0
        n = 0;
4227
0
    }
4228
0
    setRects(QSpan<const QRect>(r, n));
4229
0
}
4230
4231
void QRegion::setRects(QSpan<const QRect> rects)
4232
0
{
4233
0
    const auto num = int(rects.size());
4234
0
    if (num != rects.size()) {
4235
0
        set_rects_warn("span size exceeds INT_MAX, ignoring");
4236
0
        return;
4237
0
    }
4238
4239
0
    *this = QRegion();
4240
0
    if (!rects.data() || num == 0 || (num == 1 && rects.front().isEmpty()))
4241
0
        return;
4242
4243
0
    detach();
4244
4245
0
    d->qt_rgn->numRects = num;
4246
0
    if (num == 1) {
4247
0
        d->qt_rgn->extents = rects.front();
4248
0
        d->qt_rgn->innerRect = rects.front();
4249
0
    } else {
4250
0
        d->qt_rgn->rects.resize(num);
4251
4252
0
        int left = INT_MAX,
4253
0
            right = INT_MIN,
4254
0
            top = INT_MAX,
4255
0
            bottom = INT_MIN;
4256
0
        for (int i = 0; i < num; ++i) {
4257
0
            const QRect &rect = rects[i];
4258
0
            d->qt_rgn->rects[i] = rect;
4259
0
            left = qMin(rect.left(), left);
4260
0
            right = qMax(rect.right(), right);
4261
0
            top = qMin(rect.top(), top);
4262
0
            bottom = qMax(rect.bottom(), bottom);
4263
0
            d->qt_rgn->updateInnerRect(rect);
4264
0
        }
4265
0
        d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4266
0
    }
4267
0
}
4268
4269
/*!
4270
    \since 6.8
4271
4272
    Returns a span of non-overlapping rectangles that make up the region. The
4273
    span remains valid until the next call of a mutating (non-const) method on
4274
    this region.
4275
4276
    The union of all the rectangles is equal to the original region.
4277
4278
    \note This functions existed in Qt 5, too, but returned QVector<QRect>
4279
    instead.
4280
4281
    \sa setRects()
4282
*/
4283
QSpan<const QRect> QRegion::rects() const noexcept
4284
0
{
4285
0
    return {begin(), end()};
4286
0
};
4287
4288
int QRegion::rectCount() const noexcept
4289
0
{
4290
0
    return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4291
0
}
4292
4293
bool QRegion::operator==(const QRegion &r) const
4294
0
{
4295
0
    if (!d->qt_rgn)
4296
0
        return r.isEmpty();
4297
0
    if (!r.d->qt_rgn)
4298
0
        return isEmpty();
4299
4300
0
    if (d == r.d)
4301
0
        return true;
4302
0
    else
4303
0
        return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4304
0
}
4305
4306
bool QRegion::intersects(const QRect &rect) const
4307
0
{
4308
0
    if (isEmptyHelper(d->qt_rgn) || rect.isNull())
4309
0
        return false;
4310
4311
0
    const QRect r = rect.normalized();
4312
0
    if (!rect_intersects(d->qt_rgn->extents, r))
4313
0
        return false;
4314
0
    if (d->qt_rgn->numRects == 1)
4315
0
        return true;
4316
4317
0
    for (const QRect &rect : *this) {
4318
0
        if (rect_intersects(r, rect))
4319
0
            return true;
4320
0
    }
4321
0
    return false;
4322
0
}
4323
4324
#if defined(Q_OS_WIN) || defined(Q_QDOC)
4325
4326
static inline HRGN qt_RectToHRGN(const QRect &rc)
4327
{
4328
    return CreateRectRgn(rc.left(), rc.top(), rc.right() + 1, rc.bottom() + 1);
4329
}
4330
4331
/*!
4332
    \since 6.0
4333
4334
    Returns a HRGN that is equivalent to the given region.
4335
*/
4336
HRGN QRegion::toHRGN() const
4337
{
4338
    const int size = rectCount();
4339
    if (size == 0)
4340
        return nullptr;
4341
4342
    HRGN resultRgn = nullptr;
4343
    const auto rects = begin();
4344
    resultRgn = qt_RectToHRGN(rects[0]);
4345
    for (int i = 1; i < size; ++i) {
4346
        HRGN tmpRgn = qt_RectToHRGN(rects[i]);
4347
        int err = CombineRgn(resultRgn, resultRgn, tmpRgn, RGN_OR);
4348
        if (err == ERROR)
4349
            qWarning("Error combining HRGNs.");
4350
        DeleteObject(tmpRgn);
4351
    }
4352
    return resultRgn;
4353
}
4354
4355
/*!
4356
    \since 6.0
4357
4358
    Returns a QRegion that is equivalent to the given \a hrgn.
4359
 */
4360
QRegion QRegion::fromHRGN(HRGN hrgn)
4361
{
4362
    DWORD regionDataSize = GetRegionData(hrgn, 0, nullptr);
4363
    if (regionDataSize == 0)
4364
        return QRegion();
4365
4366
    auto regionData = reinterpret_cast<LPRGNDATA>(malloc(regionDataSize));
4367
    if (!regionData)
4368
        return QRegion();
4369
4370
    QRegion region;
4371
    if (GetRegionData(hrgn, regionDataSize, regionData) == regionDataSize) {
4372
        auto pRect = reinterpret_cast<LPRECT>(regionData->Buffer);
4373
        for (DWORD i = 0; i < regionData->rdh.nCount; ++i)
4374
            region += QRect(pRect[i].left, pRect[i].top,
4375
                            pRect[i].right - pRect[i].left,
4376
                            pRect[i].bottom - pRect[i].top);
4377
    }
4378
4379
    free(regionData);
4380
    return region;
4381
}
4382
#endif // Q_OS_WIN || Q_QDOC
4383
4384
QT_END_NAMESPACE