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