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