16#include <private/qdebug_p.h>
19# include <qt_windows.h>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
66
67
68
69
70
71
72
75
76
77
78
79
80
81
82
83
84
87
88
91
92
93
94
95
96
99
100
101
102
103
104
105
106
107
110
111
112
113
114
115
116
117
118
119
120
121
124
125
126
127
130
131
132
133
134
135
136
137
140
141
142
143
144
145
146
147
148
149
150
153
154
155
156
157
158
159
160QRegion::QRegion(
int x,
int y,
int w,
int h, RegionType t)
162 QRegion tmp(QRect(x, y, w, h), t);
168
169
170
171
172
174void QRegion::detach()
176 if (d->ref.isShared())
181#define QRGN_SETRECT 1
182#define QRGN_SETELLIPSE 2
183#define QRGN_SETPTARRAY_ALT 3
184#define QRGN_SETPTARRAY_WIND 4
185#define QRGN_TRANSLATE 5
193#ifndef QT_NO_DATASTREAM
196
197
198
199
200
201
202
203
204void QRegion::exec(
const QByteArray &buffer,
int ver, QDataStream::ByteOrder byteOrder)
206 QByteArray copy = buffer;
207 QDataStream s(©, QIODevice::ReadOnly);
210 s.setByteOrder(byteOrder);
217 if (s.version() == 1) {
226 qWarning(
"QRegion::exec: Internal error");
232 rgn = QRegion(r, id ==
QRGN_SETRECT ? Rectangle : Ellipse);
240 rgn.translate(p.x(), p.y());
242 QByteArray bop1, bop2;
254 rgn = r1.intersected(r2);
257 rgn = r1.subtracted(r2);
268 for (
int i=0; i <
static_cast<
int>(n); i++) {
270 rgn = rgn.united(QRegion(r));
279
280
283
284
285
286
289
290
291
292
293
294
297
298
299
300
303
304
305
306
307
308
309
311QDataStream &operator<<(QDataStream &s,
const QRegion &r)
313 auto b = r.begin(), e = r.end();
315 s <<
static_cast<quint32>(0);
317 const auto size = e - b;
318 if (s.version() == 1) {
319 for (
auto i = size - 1; i > 0; --i) {
320 s <<
static_cast<quint32>(12 + i * 24);
321 s <<
static_cast<
int>(
QRGN_OR);
323 for (
auto it = b; it != e; ++it)
324 s <<
static_cast<quint32>(4+8) <<
static_cast<
int>(
QRGN_SETRECT) << *it;
326 s << quint32(4 + 4 + 16 * size);
329 for (
auto it = b; it != e; ++it)
337
338
339
340
341
342
343
345QDataStream &operator>>(QDataStream &s, QRegion &r)
349 r.exec(b, s.version(), s.byteOrder());
354#ifndef QT_NO_DEBUG_STREAM
357 QDebugStateSaver saver(s);
362 }
else if (r.isEmpty()) {
365 const int count = r.rectCount();
367 s <<
"size=" << count <<
", bounds=(";
368 QtDebugUtils::formatQRect(s, r.boundingRect());
372 for (
const QRect &rect : r) {
376 QtDebugUtils::formatQRect(s, rect);
394
395
396
397
398
399QRegion QRegion::operator|(
const QRegion &r)
const
400 {
return united(r); }
403
404
405
406
407
408QRegion QRegion::operator+(
const QRegion &r)
const
409 {
return united(r); }
412
413
414
415QRegion QRegion::operator+(
const QRect &r)
const
416 {
return united(r); }
419
420
421
422
423
424QRegion QRegion::operator&(
const QRegion &r)
const
425 {
return intersected(r); }
428
429
430
431QRegion QRegion::operator&(
const QRect &r)
const
433 return intersected(r);
437
438
439
440
441
442QRegion QRegion::operator-(
const QRegion &r)
const
443 {
return subtracted(r); }
446
447
448
449
450
451QRegion QRegion::operator^(
const QRegion &r)
const
455
456
457
458
459
460
461QRegion& QRegion::operator|=(
const QRegion &r)
462 {
return *
this = *
this | r; }
465
466
467
468
469
470
472
473
474
475
476
477
478
479
482
483
484
485
486
487
488
489
490QRegion& QRegion::operator&=(
const QRegion &r)
491 {
return *
this = *
this & r; }
494
495
496
497#if defined (Q_OS_UNIX) || defined (Q_OS_WIN)
498QRegion& QRegion::operator&=(
const QRect &r)
500 return *
this = *
this & r;
503QRegion& QRegion::operator&=(
const QRect &r)
505 return *
this &= (QRegion(r));
510
511
512
513
514
515
516
517
518QRegion& QRegion::operator-=(
const QRegion &r)
519 {
return *
this = *
this - r; }
522
523
524
525
526
527
528QRegion& QRegion::operator^=(
const QRegion &r)
529 {
return *
this = *
this ^ r; }
532
533
534
535
536
539
540
541QRegion::operator QVariant()
const
543 return QVariant::fromValue(*
this);
547
548
549
550
551
554
555
556
557
558
561
562
563
564
565
566
567
568
569
570
571
574
575
576
577
578
579
580
581
582
585QRegion::translated(
int dx,
int dy)
const
588 ret.translate(dx, dy);
595 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
596 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
600
601
602
603
604
605bool QRegion::intersects(
const QRegion ®ion)
const
607 if (isEmpty() || region.isEmpty())
610 if (!rect_intersects(boundingRect(), region.boundingRect()))
612 if (rectCount() == 1 && region.rectCount() == 1)
615 for (
const QRect &myRect : *
this)
616 for (
const QRect &otherRect : region)
617 if (rect_intersects(myRect, otherRect))
623
624
625
626
627
628
631#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_QDOC)
633
634
635
636QRegion QRegion::intersect(
const QRect &r)
const
638 return intersect(QRegion(r));
643
644
645
646
647
648
651
652
653
654
655
656
657
658
661
662
663
664
665
666
667
668
669
672
673
674
675
676
679
680
681
682
683
684
687
688
689
690
691
692
693
696
697
698
699
700
701
702
703
704
705
706
709
710
711
712
713
714
715
718
719
720
721
722
723
724
725
726
727
728
731
732
733
734
735
736
737
738
739
740
741
742
745
746
747
748
749
750
751
752
753
754
755
756
759
760
761
762
763
766
767
768
769
770
771
772
773
774
775
776
777
780
781
782
783
784
785
786
787
788
789
790
791
794
795
796
797
798
799
800
801
802
803
806
807
808
809
810
813
814
815
816
817
818
819
820
821
822
825
826
827
828
829
832
833
834
835
836
837
838
839
840
841
844
845
846
847
848
851
852
853
854
855
856
857
858
859
860
863
864
865
866
867
870
871
872
873
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
913 return qMin(point.x(), next->point.x());
918 return qMax(point.x(), next->point.x());
921 bool overlaps(
const Segment &other)
const
923 return left() < other.right() && other.left() < right();
926 void connect(Segment &other)
931 horizontal = (point.y() == other.point.y());
934 void merge(Segment &other)
936 if (right() <= other.right()) {
938 Segment *oprev = other.prev;
948 Segment *onext = other.next;
965void mergeSegments(Segment *a,
int na, Segment *b,
int nb)
970 while (i != na && j != nb) {
973 const int ra = sa.right();
974 const int rb = sb.right();
982void addSegmentsToPath(Segment *segment, QPainterPath &path)
984 Segment *current = segment;
985 path.moveTo(current->point);
987 current->added =
true;
989 Segment *last = current;
990 current = current->next;
991 while (current != segment) {
992 if (current->horizontal != last->horizontal)
993 path.lineTo(current->point);
994 current->added =
true;
996 current = current->next;
1012 QPainterPath result;
1013 if (region.rectCount() == 1) {
1014 result.addRect(region.boundingRect());
1018 auto rect = region.begin();
1019 const auto end = region.end();
1021 QVarLengthArray<Segment> segments;
1022 segments.resize(4 * (end - rect));
1024 int lastRowSegmentCount = 0;
1025 Segment *lastRowSegments =
nullptr;
1027 int lastSegment = 0;
1029 while (rect != end) {
1030 const int y = rect[0].y();
1032 while (&rect[count] != end && rect[count].y() == y)
1035 for (
int i = 0; i < count; ++i) {
1036 int offset = lastSegment + i;
1037 segments[offset] = Segment(rect[i].topLeft());
1038 segments[offset += count] = Segment(rect[i].topRight() + QPoint(1, 0));
1039 segments[offset += count] = Segment(rect[i].bottomRight() + QPoint(1, 1));
1040 segments[offset += count] = Segment(rect[i].bottomLeft() + QPoint(0, 1));
1042 offset = lastSegment + i;
1043 for (
int j = 0; j < 4; ++j)
1044 segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
1047 if (lastRowSegments && lastY == y)
1048 mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
1050 lastRowSegments = &segments[lastSegment + 2 * count];
1051 lastRowSegmentCount = count;
1052 lastSegment += 4 * count;
1053 lastY = y + rect[0].height();
1057 for (
int i = 0; i < lastSegment; ++i) {
1058 Segment *segment = &segments[i];
1059 if (!segment->added)
1060 addSegmentsToPath(segment, result);
1068
1069
1090
1091
1092
1094 return contains(r.extents);
1098 const QRect &r1 = innerRect;
1099 return r2.left() >= r1.left() && r2.right() <= r1.right()
1100 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1104
1105
1107 const QRect &r2 = extents;
1108 return r2.left() >= r1.left() && r2.right() <= r1.right()
1109 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1113 const int area = rect.width() * rect.height();
1129 {
return numRects == 1 ? &extents : rects.data(); }
1131 const QRect *
end()
const noexcept
1146 const QRect *nextToTop,
1147 const QRect *nextToBottom);
1149 const QRect *nextToBottom,
1150 const QRect *nextToTop);
1152#ifdef QT_REGION_DEBUG
1164 return (right->top() == left->top()
1165 && right->bottom() == left->bottom()
1166 && right->left() <= (left->right() + 1));
1177 left->setRight(right->right());
1187 right->setLeft(left->left());
1195 const QRect *nextToTop,
1196 const QRect *nextToBottom)
1198 if (nextToTop && nextToTop->y() == top->y())
1200 if (nextToBottom && nextToBottom->y() == bottom->y())
1203 return ((top->bottom() >= (bottom->top() - 1))
1204 && top->left() == bottom->left()
1205 && top->right() == bottom->right());
1209 const QRect *nextToTop,
1210 const QRect *nextToBottom)
1213 top->setBottom(bottom->bottom());
1221 const QRect *nextToBottom,
1222 const QRect *nextToTop)
1225 bottom->setTop(top->top());
1236 r.setLeft(qMax(r1.left(), r2.left()));
1237 r.setRight(qMin(r1.right(), r2.right()));
1238 r.setTop(qMax(r1.top(), r2.top()));
1239 r.setBottom(qMin(r1.bottom(), r2.bottom()));
1245 Q_ASSERT(extents.intersects(rect));
1248#ifdef QT_REGION_DEBUG
1252 const QRect r = rect.normalized();
1254 innerRect = QRect();
1257 QRect *dest = rects.data();
1258 const QRect *src = dest;
1262 *dest = qt_rect_intersect_normalized(*src++, r);
1263 if (dest->isEmpty())
1269 extents.setLeft(qMin(extents.left(), dest->left()));
1272 extents.setRight(qMax(extents.right(), dest->right()));
1273 extents.setBottom(qMax(extents.bottom(), dest->bottom()));
1275 const QRect *nextToLast = (
numRects > 1 ? dest - 2 :
nullptr);
1278 if (canMergeFromBelow(dest - 1, dest, nextToLast,
nullptr)) {
1279 if (!n || src->y() != dest->y() || src->left() > r.right()) {
1280 QRect *prev = dest - 1;
1281 prev->setBottom(dest->bottom());
1291#ifdef QT_REGION_DEBUG
1298 Q_ASSERT(!r->isEmpty());
1300 QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
1303 const QRect *nextToTop = (
numRects > 2 ? myLast - 2 :
nullptr);
1313 if (rects.size() < numRects)
1314 rects.resize(numRects);
1315 rects[numRects - 1] = *r;
1317 extents.setCoords(qMin(extents.left(), r->left()),
1318 qMin(extents.top(), r->top()),
1319 qMax(extents.right(), r->right()),
1320 qMax(extents.bottom(), r->bottom()));
1322#ifdef QT_REGION_DEBUG
1332 append(&r->extents);
1338 QRect *destRect = rects.data() + numRects;
1339 const QRect *srcRect = r->rects.constData();
1344 const QRect *rFirst = srcRect;
1345 QRect *myLast = destRect - 1;
1346 const QRect *nextToLast = (
numRects > 1 ? myLast - 1 :
nullptr);
1350 const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 :
nullptr);
1356 nextToLast = (
numRects > 2 ? myLast - 2 :
nullptr);
1357 rNextToFirst = (numAppend > 0 ? srcRect :
nullptr);
1370 if (numAppend > 0) {
1371 const int newNumRects =
numRects + numAppend;
1372 if (newNumRects > rects.size()) {
1373 rects.resize(newNumRects);
1374 destRect = rects.data() + numRects;
1376 memcpy(destRect, srcRect, numAppend *
sizeof(QRect));
1384 innerRect = r->innerRect;
1388 destRect = &extents;
1389 srcRect = &r->extents;
1390 extents.setCoords(qMin(destRect->left(), srcRect->left()),
1391 qMin(destRect->top(), srcRect->top()),
1392 qMax(destRect->right(), srcRect->right()),
1393 qMax(destRect->bottom(), srcRect->bottom()));
1395#ifdef QT_REGION_DEBUG
1405 prepend(&r->extents);
1416 QRect *myFirst = rects.data();
1417 const QRect *nextToFirst = (
numRects > 1 ? myFirst + 1 :
nullptr);
1418 const QRect *rLast = r->rects.constData() + r
->numRects - 1;
1419 const QRect *rNextToLast = (r
->numRects > 1 ? rLast - 1 :
nullptr);
1423 rNextToLast = (numPrepend > 1 ? rLast - 1 :
nullptr);
1429 nextToFirst = (
numRects > 2? myFirst + 2 :
nullptr);
1430 rNextToLast = (numPrepend > 0 ? rLast :
nullptr);
1441 if (numPrepend > 0) {
1442 const int newNumRects =
numRects + numPrepend;
1443 if (newNumRects > rects.size())
1444 rects.resize(newNumRects);
1447 memmove(rects.data() + numPrepend, rects.constData() + numSkip,
1448 numRects *
sizeof(QRect));
1451 memcpy(rects.data(), r->rects.constData(), numPrepend *
sizeof(QRect));
1459 innerRect = r->innerRect;
1463 extents.setCoords(qMin(extents.left(), r->extents.left()),
1464 qMin(extents.top(), r->extents.top()),
1465 qMax(extents.right(), r->extents.right()),
1466 qMax(extents.bottom(), r->extents.bottom()));
1468#ifdef QT_REGION_DEBUG
1475 Q_ASSERT(!r->isEmpty());
1477 QRect *myFirst = (numRects == 1 ? &extents : rects.data());
1480 const QRect *nextToFirst = (
numRects > 2 ? myFirst + 2 :
nullptr);
1483 memmove(rects.data(), rects.constData() + 1,
1484 numRects *
sizeof(QRect));
1495 extents.setCoords(qMin(extents.left(), r->left()),
1496 qMin(extents.top(), r->top()),
1497 qMax(extents.right(), r->right()),
1498 qMax(extents.bottom(), r->bottom()));
1500#ifdef QT_REGION_DEBUG
1507 Q_ASSERT(!r->isEmpty());
1509 const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
1510 if (r->top() > myLast->bottom())
1512 if (r->top() == myLast->top()
1513 && r->height() == myLast->height()
1514 && r->left() > myLast->right())
1524 return canAppend(r
->numRects == 1 ? &r->extents : r->rects.constData());
1529 Q_ASSERT(!r->isEmpty());
1531 const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
1532 if (r->bottom() < myFirst->top())
1534 if (r->top() == myFirst->top()
1535 && r->height() == myFirst->height()
1536 && r->right() < myFirst->left())
1549#ifdef QT_REGION_DEBUG
1550void QRegionPrivate::selfTest()
const
1552 if (numRects == 0) {
1553 Q_ASSERT(extents.isEmpty());
1554 Q_ASSERT(innerRect.isEmpty());
1558 Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
1560 if (numRects == 1) {
1561 Q_ASSERT(innerRect == extents);
1562 Q_ASSERT(!innerRect.isEmpty());
1566 for (
int i = 0; i < numRects; ++i) {
1567 const QRect r = rects.at(i);
1568 if ((r.width() * r.height()) > innerArea)
1569 qDebug() <<
"selfTest(): innerRect" << innerRect <<
'<' << r;
1572 QRect r = rects.first();
1573 for (
int i = 1; i < numRects; ++i) {
1574 const QRect r2 = rects.at(i);
1575 Q_ASSERT(!r2.isEmpty());
1576 if (r2.y() == r.y()) {
1577 Q_ASSERT(r.bottom() == r2.bottom());
1578 Q_ASSERT(r.right() < (r2.left() + 1));
1580 Q_ASSERT(r2.y() >= r.bottom());
1587Q_CONSTINIT
static QRegionPrivate qrp;
1588Q_CONSTINIT
const QRegion::QRegionData QRegion::shared_empty = {Q_REFCOUNT_INITIALIZE_STATIC, &qrp};
1591 const QRect *r2,
const QRect *r2End,
int y1,
int y2);
1601#define RectangleOut 0
1602#define RectangleIn 1
1603#define RectanglePart 2
1604#define EvenOddRule 0
1605#define WindingRule 1
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1660QT_BEGIN_INCLUDE_NAMESPACE
1662QT_END_INCLUDE_NAMESPACE
1665
1666
1667
1668#define EXTENTCHECK(r1, r2)
1669 ((r1)->right() >= (r2)->left() &&
1670 (r1)->left() <= (r2)->right() &&
1671 (r1)->bottom() >= (r2)->top() &&
1672 (r1)->top() <= (r2)->bottom())
1675
1676
1677#define EXTENTS(r,idRect){
1678 if((r)->left() < (idRect)->extents.left())
1679 (idRect)->extents.setLeft((r)->left());
1680 if((r)->top() < (idRect)->extents.top())
1681 (idRect)->extents.setTop((r)->top());
1682 if((r)->right() > (idRect)->extents.right())
1683 (idRect)->extents.setRight((r)->right());
1684 if((r)->bottom() > (idRect)->extents.bottom())
1685 (idRect)->extents.setBottom((r)->bottom());
1689
1690
1691#define MEMCHECK(dest, rect, firstrect){
1692 if ((dest).numRects >= ((dest).rects.size()-1
)){
1693 firstrect.resize(firstrect.size() * 2
);
1694 (rect) = (firstrect).data() + (dest).numRects;
1700
1701
1702
1703#define NUMPTSTOBUFFER 200
1706
1707
1708
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1797 if (rect->isEmpty())
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1833 dest.innerRect.setCoords(0, 0, -1, -1);
1836 dest.extents.setCoords(0, 0, -1, -1);
1840 pExtents = &dest.extents;
1841 if (dest.rects.isEmpty())
1842 pBox = &dest.extents;
1844 pBox = dest.rects.constData();
1848
1849
1850
1851
1852
1853
1854 pExtents->setLeft(pBox->left());
1855 pExtents->setTop(pBox->top());
1856 pExtents->setRight(pBoxEnd->right());
1857 pExtents->setBottom(pBoxEnd->bottom());
1859 Q_ASSERT(pExtents->top() <= pExtents->bottom());
1860 while (pBox <= pBoxEnd) {
1861 if (pBox->left() < pExtents->left())
1862 pExtents->setLeft(pBox->left());
1863 if (pBox->right() > pExtents->right())
1864 pExtents->setRight(pBox->right());
1868 Q_ASSERT(pExtents->left() <= pExtents->right());
1872
1873
1874
1878 if (region.rects.size()) {
1879 QRect *pbox = region.rects.data();
1883 pbox->translate(x, y);
1887 region.extents.translate(x, y);
1888 region.innerRect.translate(x, y);
1892
1893
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1908 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
1914 pNextRect = dest.rects.data() + dest
.numRects;
1916 while (r1 != r1End && r2 != r2End) {
1917 x1 = qMax(r1->left(), r2->left());
1918 x2 = qMin(r1->right(), r2->right());
1921
1922
1923
1924
1925
1926
1929 MEMCHECK(dest, pNextRect, dest.rects)
1930 pNextRect->setCoords(x1, y1, x2, y2);
1936
1937
1938
1939
1940 if (r1->right() < r2->right()) {
1942 }
else if (r2->right() < r1->right()) {
1952
1953
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1980 QRect *rData = dest.rects.data();
1984 pPrevBox = rData + prevStart;
1985 prevNumRects = curStart - prevStart;
1988
1989
1990
1991
1992 pCurBox = rData + curStart;
1993 bandY1 = pCurBox->top();
1994 for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
1998 if (pCurBox != pRegEnd) {
2000
2001
2002
2003
2004
2006 while ((pRegEnd - 1)->top() == pRegEnd->top())
2008 curStart = pRegEnd - rData;
2012 if (curNumRects == prevNumRects && curNumRects != 0) {
2013 pCurBox -= curNumRects;
2015
2016
2017
2018 if (pPrevBox->bottom() == pCurBox->top() - 1) {
2020
2021
2022
2023
2024
2026 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
2033 }
while (prevNumRects != 0);
2036 pCurBox -= curNumRects;
2037 pPrevBox -= curNumRects;
2040
2041
2042
2043
2045 pPrevBox->setBottom(pCurBox->bottom());
2050 }
while (curNumRects != 0);
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062 if (pCurBox == pRegEnd) {
2063 curStart = prevStart;
2066 *pPrevBox++ = *pCurBox++;
2068 }
while (pCurBox != pRegEnd);
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2114 const QRect *r1BandEnd;
2115 const QRect *r2BandEnd;
2120
2121
2122
2123
2124
2125
2127 r1 = ®1->extents;
2129 r1 = reg1->rects.constData();
2131 r2 = ®2->extents;
2133 r2 = reg2->rects.constData();
2141
2142
2143
2144
2145
2146 const QList<QRect> destRectsCopy = dest.rects;
2147 Q_UNUSED(destRectsCopy);
2152
2153
2154
2155
2156
2157
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173 if (reg1->extents.top() < reg2->extents.top())
2174 ybot = reg1->extents.top() - 1;
2176 ybot = reg2->extents.top() - 1;
2179
2180
2181
2182
2183
2184
2185
2186
2193
2194
2195
2196
2197
2198
2200 while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
2204 while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
2208
2209
2210
2211
2212
2213
2214
2215 if (r1->top() < r2->top()) {
2216 top = qMax(r1->top(), ybot + 1);
2217 bot = qMin(r1->bottom(), r2->top() - 1);
2219 if (nonOverlap1Func !=
nullptr && bot >= top)
2220 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
2222 }
else if (r2->top() < r1->top()) {
2223 top = qMax(r2->top(), ybot + 1);
2224 bot = qMin(r2->bottom(), r1->top() - 1);
2226 if (nonOverlap2Func !=
nullptr && bot >= top)
2227 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
2234
2235
2236
2237
2238
2243
2244
2245
2246 ybot = qMin(r1->bottom(), r2->bottom());
2249 (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
2255
2256
2257
2258 if (r1->bottom() == ybot)
2260 if (r2->bottom() == ybot)
2262 }
while (r1 != r1End && r2 != r2End);
2265
2266
2269 if (nonOverlap1Func !=
nullptr) {
2272 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
2274 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
2276 }
while (r1 != r1End);
2278 }
else if ((r2 != r2End) && (nonOverlap2Func !=
nullptr)) {
2281 while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
2283 (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
2285 }
while (r2 != r2End);
2292
2293
2294
2295
2296
2297
2298
2299 if (qMax(4, dest
.numRects) < (dest.rects.size() >> 1))
2304
2305
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2329 pNextRect = dest.rects.data() + dest
.numRects;
2334 Q_ASSERT(r->left() <= r->right());
2335 MEMCHECK(dest, pNextRect, dest.rects)
2336 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2361 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
2365 pNextRect = dest.rects.data() + dest
.numRects;
2368 if ((dest.numRects != 0
) &&
2369 (pNextRect[-1
].top() == y1) &&
2370 (pNextRect[-1
].bottom() == y2) &&
2371 (pNextRect[-1
].right() >= r->left()-1
)) {
2372 if (pNextRect[-1
].right() < r->right()) {
2373 pNextRect[-1
].setRight(r->right());
2374 dest.updateInnerRect(pNextRect[-1
]);
2375 Q_ASSERT(pNextRect[-1
].left() <= pNextRect[-1
].right());
2378 MEMCHECK(dest, pNextRect, dest.rects)
2379 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2380 dest.updateInnerRect(*pNextRect);
2387 while (r1 != r1End && r2 != r2End) {
2388 if (r1->left() < r2->left()) {
2398 }
while (r1 != r1End);
2400 while (r2 != r2End) {
2417 dest.innerRect = reg1->innerRect;
2420 dest.innerRect = reg2->innerRect;
2424 dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()),
2425 qMin(reg1->extents.top(), reg2->extents.top()),
2426 qMax(reg1->extents.right(), reg2->extents.right()),
2427 qMax(reg1->extents.bottom(), reg2->extents.bottom()));
2431
2432
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2450 const QRect *rEnd,
int y1,
int y2)
2454 pNextRect = dest.rects.data() + dest
.numRects;
2459 Q_ASSERT(r->left() <= r->right());
2460 MEMCHECK(dest, pNextRect, dest.rects)
2461 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2484 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
2492 pNextRect = dest.rects.data() + dest
.numRects;
2494 while (r1 != r1End && r2 != r2End) {
2495 if (r2->right() < x1) {
2497
2498
2500 }
else if (r2->left() <= x1) {
2502
2503
2504 x1 = r2->right() + 1;
2505 if (x1 > r1->right()) {
2507
2508
2509
2517 }
else if (r2->left() <= r1->right()) {
2519
2520
2521
2522 Q_ASSERT(x1 < r2->left());
2523 MEMCHECK(dest, pNextRect, dest.rects)
2524 pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
2528 x1 = r2->right() + 1;
2529 if (x1 > r1->right()) {
2531
2532
2542
2543
2544 if (r1->right() >= x1) {
2545 MEMCHECK(dest, pNextRect, dest.rects)
2546 pNextRect->setCoords(x1, y1, r1->right(), y2);
2557
2558
2559 while (r1 != r1End) {
2560 Q_ASSERT(x1 <= r1->right());
2561 MEMCHECK(dest, pNextRect, dest.rects)
2562 pNextRect->setCoords(x1, y1, r1->right(), y2);
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2589 Q_ASSERT(
EXTENTCHECK(®M->extents, ®S->extents));
2596
2597
2598
2599
2600
2601
2608 Q_ASSERT(
EXTENTCHECK(&sra->extents, &srb->extents));
2637
2638
2645 }
else if (r1->extents != r2->extents) {
2650 const QRect *rr1 = (r1
->numRects == 1) ? &r1->extents : r1->rects.constData();
2651 const QRect *rr2 = (r2
->numRects == 1) ? &r2->extents : r2->rects.constData();
2652 for (
int i = 0; i < r1
->numRects; ++i, ++rr1, ++rr2) {
2667 if (!pRegion->extents.contains(x, y))
2670 return pRegion->extents.contains(x, y);
2671 if (pRegion->innerRect.contains(x, y))
2674 if (pRegion->rects[i].contains(x, y))
2683 const QRect *pboxEnd;
2684 QRect rect(rx, ry, rwidth, rheight);
2685 QRect *prect = ▭
2686 int partIn, partOut;
2695 pbox = (region
->numRects == 1) ? ®ion->extents : region->rects.constData();
2697 for (; pbox < pboxEnd; ++pbox) {
2698 if (pbox->bottom() < ry)
2701 if (pbox->top() > ry) {
2703 if (partIn || pbox->top() > prect->bottom())
2708 if (pbox->right() < rx)
2711 if (pbox->left() > rx) {
2717 if (pbox->left() <= prect->right()) {
2723 if (pbox->right() >= prect->right()) {
2724 ry = pbox->bottom() + 1;
2725 if (ry > prect->bottom())
2730
2731
2732
2733
2734
2735
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) {
2831
2832
2833
2840 incr1 = -2
* dx + 2
* (dy) * m1;
2841 incr2 = -2
* dx + 2
* (dy) * m;
2842 d = 2
* m * (dy) - 2
* dx - 2
* (dy);
2846 incr1 = 2
* dx - 2
* (dy) * m1;
2847 incr2 = 2
* dx - 2
* (dy) * m;
2848 d = -2
* m * (dy) + 2
* dx;
2851}
2853#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) {
2873}
2877
2878
2879
2891#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
2893 bres.m, bres.m1, bres.incr1, bres.incr2)
2895#define BRESINCRPGONSTRUCT(bres)
2896 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2948
2950#define COUNTERCLOCKWISE -1
2952typedef struct _EdgeTableEntry {
2956 struct _EdgeTableEntry *next;
2957 struct _EdgeTableEntry *back;
2958 struct _EdgeTableEntry *nextWETE;
2962typedef struct _ScanLineList{
2964 EdgeTableEntry *edgelist;
2965 struct _ScanLineList *next;
2972 ScanLineList scanlines;
2977
2979
2981#define SLLSPERBLOCK 25
2983typedef struct _ScanLineListBlock {
2985 struct _ScanLineListBlock *next;
2991
2992
2993
2994
2995
2996
2997
2998
2999
3001
3002
3003#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) {
3004 if (pAET->ymax == y) {
3005 pPrevAET->next = pAET->next;
3006 pAET = pPrevAET->next;
3009 pAET->back = pPrevAET;
3016}
3020
3021
3022
3024
3025
3026#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) {
3027 if (pAET->ymax == y) {
3028 pPrevAET->next = pAET->next;
3029 pAET = pPrevAET->next;
3031 pAET->back = pPrevAET;
3038}
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3091#define LARGE_COORDINATE INT_MAX
3092#define SMALL_COORDINATE INT_MIN
3095
3096
3097
3098
3099
3101
3102
3103static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
int scanline,
3104 ScanLineListBlock **SLLBlock,
int *iSLLBlock)
3106 EdgeTableEntry *start, *prev;
3107 ScanLineList *pSLL, *pPrevSLL;
3108 ScanLineListBlock *tmpSLLBlock;
3111
3112
3113 pPrevSLL = &ET->scanlines;
3114 pSLL = pPrevSLL->next;
3115 while (pSLL && (pSLL->scanline < scanline)) {
3121
3122
3123 if ((!pSLL) || (pSLL->scanline > scanline)) {
3127 (ScanLineListBlock *)malloc(
sizeof(ScanLineListBlock));
3128 Q_CHECK_PTR(tmpSLLBlock);
3129 (*SLLBlock)->next = tmpSLLBlock;
3130 tmpSLLBlock->next = (ScanLineListBlock *)
nullptr;
3131 *SLLBlock = tmpSLLBlock;
3134 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3136 pSLL->next = pPrevSLL->next;
3137 pSLL->edgelist = (EdgeTableEntry *)
nullptr;
3138 pPrevSLL->next = pSLL;
3140 pSLL->scanline = scanline;
3143
3144
3146 start = pSLL->edgelist;
3147 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3149 start = start->next;
3156 pSLL->edgelist = ETE;
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3182
3184static void CreateETandAET(
int count,
const QPoint *pts,
3185 EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs,
3186 ScanLineListBlock *pSLLBlock)
3195 Q_ASSERT(count > 1);
3198
3199
3200 AET->next =
nullptr;
3201 AET->back =
nullptr;
3202 AET->nextWETE =
nullptr;
3206
3207
3208 ET->scanlines.next =
nullptr;
3211 pSLLBlock->next =
nullptr;
3213 PrevPt = &pts[count - 1];
3216
3217
3218
3219
3224
3225
3226 if (PrevPt->y() > CurrPt->y()) {
3229 pETEs->ClockWise = 0;
3233 pETEs->ClockWise = 1;
3237
3238
3239 if (bottom->y() != top->y()) {
3240 pETEs->ymax = bottom->y() - 1;
3243
3244
3245 dy = bottom->y() - top->y();
3248 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3250 if (PrevPt->y() > ET->ymax)
3251 ET->ymax = PrevPt->y();
3252 if (PrevPt->y() < ET->ymin)
3253 ET->ymin = PrevPt->y();
3262
3263
3264
3265
3266
3268
3270static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
3272 EdgeTableEntry *pPrevAET;
3273 EdgeTableEntry *tmp;
3278 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3286 ETEs->back = pPrevAET;
3287 pPrevAET->next = ETEs;
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3312
3313
3314static void computeWAET(EdgeTableEntry *AET)
3316 EdgeTableEntry *pWETE;
3320 AET->nextWETE =
nullptr;
3329 if ((!inside && !isInside) || (inside && isInside)) {
3330 pWETE->nextWETE = AET;
3336 pWETE->nextWETE =
nullptr;
3340
3341
3342
3343
3344
3346
3348static int InsertionSort(EdgeTableEntry *AET)
3350 EdgeTableEntry *pETEchase;
3351 EdgeTableEntry *pETEinsert;
3352 EdgeTableEntry *pETEchaseBackTMP;
3359 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3360 pETEchase = pETEchase->back;
3363 if (pETEchase != pETEinsert) {
3364 pETEchaseBackTMP = pETEchase->back;
3365 pETEinsert->back->next = AET;
3367 AET->back = pETEinsert->back;
3368 pETEinsert->next = pETEchase;
3369 pETEchase->back->next = pETEinsert;
3370 pETEchase->back = pETEinsert;
3371 pETEinsert->back = pETEchaseBackTMP;
3379
3380
3381static void FreeStorage(ScanLineListBlock *pSLLBlock)
3383 ScanLineListBlock *tmpSLLBlock;
3386 tmpSLLBlock = pSLLBlock->next;
3388 pSLLBlock = tmpSLLBlock;
3394 QRegionSpan(
int x1_,
int x2_) : x1(x1_), x2(x2_) {}
3398 int width()
const {
return x2 - x1; }
3401Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3403static inline void flushRow(
const QRegionSpan *spans,
int y,
int numSpans,
QRegionPrivate *reg,
int *lastRow,
int *extendTo,
bool *needsExtend)
3405 QRect *regRects = reg->rects.data() + *lastRow;
3406 bool canExtend = reg->rects.size() - *lastRow == numSpans
3407 && !(*needsExtend && *extendTo + 1 != y)
3408 && (*needsExtend || regRects[0].y() + regRects[0].height() == y);
3410 for (
int i = 0; i < numSpans && canExtend; ++i) {
3411 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3417 *needsExtend =
true;
3420 for (
int i = 0; i < reg->rects.size() - *lastRow; ++i)
3421 regRects[i].setBottom(*extendTo);
3424 *lastRow = reg->rects.size();
3425 reg->rects.reserve(*lastRow + numSpans);
3426 for (
int i = 0; i < numSpans; ++i)
3427 reg->rects << QRect(spans[i].x1, y, spans[i].width(), 1);
3429 if (spans[0].x1 < reg->extents.left())
3430 reg->extents.setLeft(spans[0].x1);
3432 if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3433 reg->extents.setRight(spans[numSpans-1].x2 - 1);
3435 *needsExtend =
false;
3440
3441
3442
3443
3445
3446
3447static void PtsToRegion(
int numFullPtBlocks,
int iCurPtBlock,
3452 bool needsExtend =
false;
3453 QVarLengthArray<QRegionSpan> row;
3454 qsizetype rowSize = 0;
3456 reg->extents.setLeft(INT_MAX);
3457 reg->extents.setRight(INT_MIN);
3460 POINTBLOCK *CurPtBlock = FirstPtBlock;
3461 for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3464 if (!numFullPtBlocks)
3465 i = iCurPtBlock >> 1;
3467 row.resize(qMax(row.size(), rowSize + i));
3468 for (
QPoint *pts = CurPtBlock
->pts; i--; pts += 2) {
3469 const int width = pts[1].x() - pts[0].x();
3471 if (rowSize && row[rowSize-1].x2 == pts[0].x())
3472 row[rowSize-1].x2 = pts[1].x();
3474 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3478 QPoint *next = i ? &pts[2] : (numFullPtBlocks && iCurPtBlock ? CurPtBlock->next->pts :
nullptr);
3480 if (!next || next->y() != pts[0].y()) {
3481 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3487 CurPtBlock = CurPtBlock
->next;
3491 for (
int i = lastRow; i < reg->rects.size(); ++i)
3492 reg->rects[i].setBottom(extendTo);
3498 reg->extents.setTop(reg->rects[0].top());
3499 reg->extents.setBottom(reg->rects[lastRow].bottom());
3501 for (
int i = 0; i < reg->rects.size(); ++i)
3504 reg->extents.setCoords(0, 0, 0, 0);
3509
3510
3511
3512
3513
3515
3516
3523 EdgeTableEntry *pAET;
3526 EdgeTableEntry *pWETE;
3529 EdgeTableEntry *pPrevAET;
3531 EdgeTableEntry *AET;
3532 EdgeTableEntry *pETEs;
3533 ScanLineListBlock SLLBlock;
3534 int fixWAET =
false;
3535 POINTBLOCK FirstPtBlock, *curPtBlock;
3536 FirstPtBlock
.pts =
reinterpret_cast<
QPoint *>(FirstPtBlock.data);
3537 FirstPtBlock
.next =
nullptr;
3538 POINTBLOCK *tmpPtBlock;
3539 int numFullPtBlocks = 0;
3541 Q_ASSERT(Count > 1);
3546 if (((Count == 4) ||
3547 ((Count == 5) && (Pts[4].x() == Pts[0].x()) && (Pts[4].y() == Pts[0].y())))
3548 && (((Pts[0].y() == Pts[1].y()) && (Pts[1].x() == Pts[2].x()) && (Pts[2].y() == Pts[3].y())
3549 && (Pts[3].x() == Pts[0].x())) || ((Pts[0].x() == Pts[1].x())
3550 && (Pts[1].y() == Pts[2].y()) && (Pts[2].x() == Pts[3].x())
3551 && (Pts[3].y() == Pts[0].y())))) {
3552 int x = qMin(Pts[0].x(), Pts[2].x());
3553 region->extents.setLeft(x);
3554 int y = qMin(Pts[0].y(), Pts[2].y());
3555 region->extents.setTop(y);
3556 region->extents.setWidth(qMax(Pts[0].x(), Pts[2].x()) - x);
3557 region->extents.setHeight(qMax(Pts[0].y(), Pts[2].y()) - y);
3558 if ((region->extents.left() <= region->extents.right()) &&
3559 (region->extents.top() <= region->extents.bottom())) {
3561 region->innerRect = region->extents;
3562 region
->innerArea = region->innerRect.width() * region->innerRect.height();
3567 if (!(pETEs =
static_cast<EdgeTableEntry *>(malloc(
sizeof(EdgeTableEntry) * Count)))) {
3574 AET =
new EdgeTableEntry;
3575 pts = FirstPtBlock
.pts;
3576 CreateETandAET(Count, Pts, &ET, AET, pETEs, &SLLBlock);
3578 pSLL = ET.scanlines.next;
3579 curPtBlock = &FirstPtBlock;
3582 if (ET.ymax - ET.ymin > 100000) {
3585 qWarning(
"QRegion: creating region from big polygon failed...!");
3596
3597
3598 for (y = ET.ymin; y < ET.ymax; ++y) {
3601
3602
3603
3604 if (pSLL && y == pSLL->scanline) {
3605 loadAET(AET, pSLL->edgelist);
3612
3613
3615 pts->setX(pAET->bres.minor_axis);
3621
3622
3624 tmpPtBlock = (POINTBLOCK *)malloc(
sizeof(POINTBLOCK));
3625 Q_CHECK_PTR(tmpPtBlock);
3626 tmpPtBlock->pts =
reinterpret_cast<QPoint *>(tmpPtBlock->data);
3627 curPtBlock->next = tmpPtBlock;
3628 curPtBlock = tmpPtBlock;
3629 pts = curPtBlock->pts;
3639
3640
3641 for (y = ET.ymin; y < ET.ymax; ++y) {
3643
3644
3645
3646 if (pSLL && y == pSLL->scanline) {
3647 loadAET(AET, pSLL->edgelist);
3656
3657
3660
3661
3662
3663 if (pWETE == pAET) {
3664 pts->setX(pAET->bres.minor_axis);
3670
3671
3673 tmpPtBlock =
static_cast<POINTBLOCK *>(malloc(
sizeof(POINTBLOCK)));
3674 tmpPtBlock->pts =
reinterpret_cast<QPoint *>(tmpPtBlock->data);
3675 curPtBlock->next = tmpPtBlock;
3676 curPtBlock = tmpPtBlock;
3677 pts = curPtBlock->pts;
3681 pWETE = pWETE->nextWETE;
3687
3688
3689
3690 if (InsertionSort(AET) || fixWAET) {
3697 FreeStorage(SLLBlock.next);
3698 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3699 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3700 tmpPtBlock = curPtBlock->next;
3702 curPtBlock = tmpPtBlock;
3708 FreeStorage(SLLBlock.next);
3709 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3710 for (curPtBlock = FirstPtBlock
.next; --numFullPtBlocks >= 0;) {
3711 tmpPtBlock = curPtBlock
->next;
3713 curPtBlock = tmpPtBlock;
3723 const QImage image = bitmap.toImage();
3731 xr.setCoords(prev1, y, x-1
, y);
3732 UnionRectWithRegion(&xr, region, *region);
3735 const uchar zero = 0;
3736 bool little = image.format() == QImage::Format_MonoLSB;
3740 for (y = 0; y < image.height(); ++y) {
3741 const uchar *line = image.constScanLine(y);
3742 int w = image.width();
3745 for (x = 0; x < w;) {
3746 uchar byte = line[x / 8];
3747 if (x > w - 8 || byte!=all) {
3749 for (
int b = 8; b > 0 && x < w; --b) {
3750 if (!(byte & 0x01) == !all) {
3766 for (
int b = 8; b > 0 && x < w; --b) {
3767 if (!(byte & 0x80) == !all) {
3797 : d(
const_cast<QRegionData*>(&shared_empty))
3801QRegion::QRegion(
const QRect &r, RegionType t)
3804 d =
const_cast<QRegionData*>(&shared_empty);
3806 d =
new QRegionData;
3807 if (t == Rectangle) {
3808 d->qt_rgn =
new QRegionPrivate(r);
3809 }
else if (t == Ellipse) {
3811 path.addEllipse(r.x(), r.y(), r.width(), r.height());
3812 QPolygon a = path.toSubpathPolygons().at(0).toPolygon();
3813 d->qt_rgn = PolygonRegion(a.constData(), a.size(),
EvenOddRule);
3818QRegion::QRegion(
const QPolygon &a, Qt::FillRule fillRule)
3821 QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
3824 d =
new QRegionData;
3827 d =
const_cast<QRegionData*>(&shared_empty);
3830 d =
const_cast<QRegionData*>(&shared_empty);
3834QRegion::QRegion(
const QRegion &r)
3841QRegion::QRegion(
const QBitmap &bm)
3844 d =
const_cast<QRegionData*>(&shared_empty);
3846 d =
new QRegionData;
3847 d->qt_rgn = qt_bitmapToRegion(bm);
3851void QRegion::cleanUp(QRegion::QRegionData *x)
3859 if (!d->ref.deref())
3864QRegion &QRegion::operator=(
const QRegion &r)
3867 if (!d->ref.deref())
3875
3876
3877QRegion QRegion::copy()
const
3880 auto x = std::make_unique<QRegionData>();
3881 x->ref.initializeOwned();
3883 x->qt_rgn =
new QRegionPrivate(*d->qt_rgn);
3885 x->qt_rgn =
new QRegionPrivate;
3886 if (!r.d->ref.deref())
3892bool QRegion::isEmpty()
const
3894 return d == &shared_empty || d->qt_rgn->numRects == 0;
3897bool QRegion::isNull()
const
3899 return d == &shared_empty || d->qt_rgn->numRects == 0;
3902bool QRegion::contains(
const QPoint &p)
const
3904 return PointInRegion(d->qt_rgn, p.x(), p.y());
3907bool QRegion::contains(
const QRect &r)
const
3909 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) !=
RectangleOut;
3914void QRegion::translate(
int dx,
int dy)
3916 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
3920 OffsetRegion(*d->qt_rgn, dx, dy);
3923QRegion QRegion::united(
const QRegion &r)
const
3925 if (isEmptyHelper(d->qt_rgn))
3927 if (isEmptyHelper(r.d->qt_rgn))
3932 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3934 }
else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3936 }
else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3937 QRegion result(*
this);
3939 result.d->qt_rgn->append(r.d->qt_rgn);
3941 }
else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3942 QRegion result(*
this);
3944 result.d->qt_rgn->prepend(r.d->qt_rgn);
3946 }
else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3951 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
3956QRegion& QRegion::operator+=(
const QRegion &r)
3958 if (isEmptyHelper(d->qt_rgn))
3960 if (isEmptyHelper(r.d->qt_rgn))
3965 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3967 }
else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3969 }
else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3971 d->qt_rgn->append(r.d->qt_rgn);
3973 }
else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3975 d->qt_rgn->prepend(r.d->qt_rgn);
3977 }
else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3981 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
3986QRegion QRegion::united(
const QRect &r)
const
3988 if (isEmptyHelper(d->qt_rgn))
3993 if (d->qt_rgn->contains(r)) {
3995 }
else if (d->qt_rgn->within(r)) {
3997 }
else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
3999 }
else if (d->qt_rgn->canAppend(&r)) {
4000 QRegion result(*
this);
4002 result.d->qt_rgn->append(&r);
4004 }
else if (d->qt_rgn->canPrepend(&r)) {
4005 QRegion result(*
this);
4007 result.d->qt_rgn->prepend(&r);
4012 QRegionPrivate rp(r);
4013 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4018QRegion& QRegion::operator+=(
const QRect &r)
4020 if (isEmptyHelper(d->qt_rgn))
4025 if (d->qt_rgn->contains(r)) {
4027 }
else if (d->qt_rgn->within(r)) {
4029 }
else if (d->qt_rgn->canAppend(&r)) {
4031 d->qt_rgn->append(&r);
4033 }
else if (d->qt_rgn->canPrepend(&r)) {
4035 d->qt_rgn->prepend(&r);
4037 }
else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4041 QRegionPrivate p(r);
4042 UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4047QRegion QRegion::intersected(
const QRegion &r)
const
4049 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4050 || !
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4054 if (r.d->qt_rgn->contains(*d->qt_rgn))
4058 if (d->qt_rgn->contains(*r.d->qt_rgn))
4061 if (r.d->qt_rgn->numRects == 1 && d->qt_rgn->numRects == 1) {
4062 const QRect rect = qt_rect_intersect_normalized(r.d->qt_rgn->extents,
4063 d->qt_rgn->extents);
4064 return QRegion(rect);
4065 }
else if (r.d->qt_rgn->numRects == 1) {
4066 QRegion result(*
this);
4068 result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4070 }
else if (d->qt_rgn->numRects == 1) {
4073 result.d->qt_rgn->intersect(d->qt_rgn->extents);
4079 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO,
nullptr,
nullptr);
4082
4083
4084
4085
4086
4087
4088 miSetExtents(*result.d->qt_rgn);
4092QRegion QRegion::intersected(
const QRect &r)
const
4094 if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4099 if (d->qt_rgn->within(r))
4103 if (d->qt_rgn->contains(r))
4106 if (d->qt_rgn->numRects == 1) {
4107 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4109 return QRegion(rect);
4112 QRegion result(*
this);
4114 result.d->qt_rgn->intersect(r);
4118QRegion QRegion::subtracted(
const QRegion &r)
const
4120 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4122 if (r.d->qt_rgn->contains(*d->qt_rgn))
4124 if (!
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4126 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4129#ifdef QT_REGION_DEBUG
4130 d->qt_rgn->selfTest();
4131 r.d->qt_rgn->selfTest();
4136 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4137#ifdef QT_REGION_DEBUG
4138 result.d->qt_rgn->selfTest();
4143QRegion QRegion::xored(
const QRegion &r)
const
4145 if (isEmptyHelper(d->qt_rgn)) {
4147 }
else if (isEmptyHelper(r.d->qt_rgn)) {
4149 }
else if (!
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4151 }
else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4156 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4161QRect QRegion::boundingRect()
const noexcept
4165 return d->qt_rgn->extents;
4169
4171
4173bool qt_region_strictContains(
const QRegion ®ion,
const QRect &rect)
4175 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4179 static bool guard =
false;
4183 QRegion inner = region.d->qt_rgn->innerRect;
4184 Q_ASSERT((inner - region).isEmpty());
4188 for (
int i = 0; i < region.d->qt_rgn->numRects; ++i) {
4189 const QRect r = region.d->qt_rgn->rects.at(i);
4190 if (r.width() * r.height() > maxArea)
4191 maxArea = r.width() * r.height();
4194 if (maxArea > region.d->qt_rgn->innerArea) {
4195 qDebug() <<
"not largest rectangle" << region << region.d->qt_rgn->innerRect;
4197 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
4200 const QRect r1 = region.d->qt_rgn->innerRect;
4201 return (rect.left() >= r1.left() && rect.right() <= r1.right()
4202 && rect.top() >= r1.top() && rect.bottom() <= r1.bottom());
4205QRegion::const_iterator QRegion::begin()
const noexcept
4207 return d->qt_rgn ? d->qt_rgn->begin() :
nullptr;
4210QRegion::const_iterator QRegion::end()
const noexcept
4212 return d->qt_rgn ? d->qt_rgn->end() :
nullptr;
4215static Q_DECL_COLD_FUNCTION
4216void set_rects_warn(
const char *what)
4218 qWarning(
"QRegion::setRects(): %s", what);
4221void QRegion::setRects(
const QRect *r,
int n)
4224 set_rects_warn(
"passing num != 0 when rects == nullptr is deprecated.");
4227 setRects(QSpan<
const QRect>(r, n));
4230void QRegion::setRects(QSpan<
const QRect> rects)
4232 const auto num =
int(rects.size());
4233 if (num != rects.size()) {
4234 set_rects_warn(
"span size exceeds INT_MAX, ignoring");
4239 if (!rects.data() || num == 0 || (num == 1 && rects.front().isEmpty()))
4244 d->qt_rgn->numRects = num;
4246 d->qt_rgn->extents = rects.front();
4247 d->qt_rgn->innerRect = rects.front();
4249 d->qt_rgn->rects.resize(num);
4255 for (
int i = 0; i < num; ++i) {
4256 const QRect &rect = rects[i];
4257 d->qt_rgn->rects[i] = rect;
4258 left = qMin(rect.left(), left);
4259 right = qMax(rect.right(), right);
4260 top = qMin(rect.top(), top);
4261 bottom = qMax(rect.bottom(), bottom);
4262 d->qt_rgn->updateInnerRect(rect);
4264 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4280
4281
4282QSpan<
const QRect> QRegion::rects()
const noexcept
4284 return {begin(), end()};
4287int QRegion::rectCount()
const noexcept
4289 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4292bool QRegion::operator==(
const QRegion &r)
const
4302 return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4305bool QRegion::intersects(
const QRect &rect)
const
4307 if (isEmptyHelper(d->qt_rgn) || rect.isNull())
4310 const QRect r = rect.normalized();
4311 if (!rect_intersects(d->qt_rgn->extents, r))
4313 if (d->qt_rgn->numRects == 1)
4316 for (
const QRect &rect : *
this) {
4317 if (rect_intersects(r, rect))
4323#if defined(Q_OS_WIN) || defined(Q_QDOC)
4325static inline HRGN qt_RectToHRGN(
const QRect &rc)
4327 return CreateRectRgn(rc.left(), rc.top(), rc.right() + 1, rc.bottom() + 1);
4331
4332
4333
4334
4335HRGN QRegion::toHRGN()
const
4337 const int size = rectCount();
4341 HRGN resultRgn =
nullptr;
4342 const auto rects = begin();
4343 resultRgn = qt_RectToHRGN(rects[0]);
4344 for (
int i = 1; i < size; ++i) {
4345 HRGN tmpRgn = qt_RectToHRGN(rects[i]);
4346 int err = CombineRgn(resultRgn, resultRgn, tmpRgn, RGN_OR);
4348 qWarning(
"Error combining HRGNs.");
4349 DeleteObject(tmpRgn);
4355
4356
4357
4358
4359QRegion QRegion::fromHRGN(HRGN hrgn)
4361 DWORD regionDataSize = GetRegionData(hrgn, 0,
nullptr);
4362 if (regionDataSize == 0)
4365 auto regionData =
reinterpret_cast<LPRGNDATA>(malloc(regionDataSize));
4370 if (GetRegionData(hrgn, regionDataSize, regionData) == regionDataSize) {
4371 auto pRect =
reinterpret_cast<LPRECT>(regionData->Buffer);
4372 for (DWORD i = 0; i < regionData->rdh.nCount; ++i)
4373 region += QRect(pRect[i].left, pRect[i].top,
4374 pRect[i].right - pRect[i].left,
4375 pRect[i].bottom - pRect[i].top);
\inmodule QtCore\reentrant
static bool canMergeFromBelow(const QRect *top, const QRect *bottom, const QRect *nextToTop, const QRect *nextToBottom)
static void miSubtractO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End, const QRect *r2, const QRect *r2End, int y1, int y2)
Q_DECLARE_TYPEINFO(Segment, Q_PRIMITIVE_TYPE)
static bool isEmptyHelper(const QRegionPrivate *preg)
static void OffsetRegion(QRegionPrivate ®ion, int x, int y)
static bool canMergeFromLeft(const QRect *right, const QRect *left)
static QRect qt_rect_intersect_normalized(const QRect &r1, const QRect &r2)
static bool canMergeFromRight(const QRect *left, const QRect *right)
static bool EqualRegion(const QRegionPrivate *r1, const QRegionPrivate *r2)
static void XorRegion(QRegionPrivate *sra, QRegionPrivate *srb, QRegionPrivate &dest)
static int miCoalesce(QRegionPrivate &dest, int prevStart, int curStart)
static bool PointInRegion(QRegionPrivate *pRegion, int x, int y)
#define EXTENTCHECK(r1, r2)
#define QRGN_SETPTARRAY_ALT
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
static bool RectInRegion(QRegionPrivate *region, int rx, int ry, uint rwidth, uint rheight)
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2)
QDebug operator<<(QDebug s, const QRegion &r)
static void miUnionO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End, const QRect *r2, const QRect *r2End, int y1, int y2)
void(* OverlapFunc)(QRegionPrivate &dest, const QRect *r1, const QRect *r1End, const QRect *r2, const QRect *r2End, int y1, int y2)
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
#define MEMCHECK(dest, rect, firstrect)
#define BRESINCRPGONSTRUCT(bres)
static void miSubtractNonO1(QRegionPrivate &dest, const QRect *r, const QRect *rEnd, int y1, int y2)
bool rect_intersects(const QRect &r1, const QRect &r2)
static void UnionRectWithRegion(const QRect *rect, const QRegionPrivate *source, QRegionPrivate &dest)
static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest)
#define QRGN_SETPTARRAY_WIND
static void miSetExtents(QRegionPrivate &dest)
void(* NonOverlapFunc)(QRegionPrivate &dest, const QRect *r, const QRect *rEnd, int y1, int y2)
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
static void SubtractRegion(QRegionPrivate *regM, QRegionPrivate *regS, QRegionPrivate &dest)
static void miUnionNonO(QRegionPrivate &dest, const QRect *r, const QRect *rEnd, int y1, int y2)
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2)
static void miIntersectO(QRegionPrivate &dest, const QRect *r1, const QRect *r1End, const QRect *r2, const QRect *r2End, int y1, int y2)
static void miRegionOp(QRegionPrivate &dest, const QRegionPrivate *reg1, const QRegionPrivate *reg2, OverlapFunc overlapFunc, NonOverlapFunc nonOverlap1Func, NonOverlapFunc nonOverlap2Func)
void prepend(const QRect *r)
bool canPrepend(const QRegionPrivate *r) const
constexpr QRegionPrivate()
bool mergeFromAbove(QRect *bottom, const QRect *top, const QRect *nextToBottom, const QRect *nextToTop)
const QRect * end() const noexcept
const QRect * begin() const noexcept
bool canAppend(const QRegionPrivate *r) const
bool within(const QRect &r1) const
bool contains(const QRect &r2) const
void append(const QRegionPrivate *r)
bool mergeFromRight(QRect *left, const QRect *right)
void updateInnerRect(const QRect &rect)
bool contains(const QRegionPrivate &r) const
void append(const QRect *r)
bool canAppend(const QRect *r) const
QRegionPrivate(const QRect &r)
bool mergeFromLeft(QRect *left, const QRect *right)
bool canPrepend(const QRect *r) const
bool mergeFromBelow(QRect *top, const QRect *bottom, const QRect *nextToTop, const QRect *nextToBottom)
void prepend(const QRegionPrivate *r)
void intersect(const QRect &r)
char data[NUMPTSTOBUFFER *sizeof(QPoint)]
struct _POINTBLOCK * next