17#include <private/qdebug_p.h>
20# include <qt_windows.h>
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
63
67
68
69
70
71
72
73
76
77
78
79
80
81
82
83
84
85
88
89
92
93
94
95
96
97
100
101
102
103
104
105
106
107
108
111
112
113
114
115
116
117
118
119
120
121
122
125
126
127
128
131
132
133
134
135
136
137
138
141
142
143
144
145
146
147
148
149
150
151
154
155
156
157
158
159
160
161QRegion::QRegion(
int x,
int y,
int w,
int h, RegionType t)
163 QRegion tmp(QRect(x, y, w, h), t);
169
170
171
172
173
175void QRegion::detach()
177 if (d->ref.isShared())
182#define QRGN_SETRECT 1
183#define QRGN_SETELLIPSE 2
184#define QRGN_SETPTARRAY_ALT 3
185#define QRGN_SETPTARRAY_WIND 4
186#define QRGN_TRANSLATE 5
194#ifndef QT_NO_DATASTREAM
197
198
199
200
201
202
203
204
205void QRegion::exec(
const QByteArray &buffer,
int ver, QDataStream::ByteOrder byteOrder)
207 QByteArray copy = buffer;
208 QDataStream s(©, QIODevice::ReadOnly);
211 s.setByteOrder(byteOrder);
218 if (s.version() == 1) {
227 qWarning(
"QRegion::exec: Internal error");
233 rgn = QRegion(r, id ==
QRGN_SETRECT ? Rectangle : Ellipse);
241 rgn.translate(p.x(), p.y());
243 QByteArray bop1, bop2;
255 rgn = r1.intersected(r2);
258 rgn = r1.subtracted(r2);
269 for (
int i=0; i <
static_cast<
int>(n); i++) {
271 rgn = rgn.united(QRegion(r));
280
281
284
285
286
287
290
291
292
293
294
295
298
299
300
301
304
305
306
307
308
309
310
312QDataStream &operator<<(QDataStream &s,
const QRegion &r)
314 auto b = r.begin(), e = r.end();
316 s <<
static_cast<quint32>(0);
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);
324 for (
auto it = b; it != e; ++it)
325 s <<
static_cast<quint32>(4+8) <<
static_cast<
int>(
QRGN_SETRECT) << *it;
327 s << quint32(4 + 4 + 16 * size);
330 for (
auto it = b; it != e; ++it)
338
339
340
341
342
343
344
346QDataStream &operator>>(QDataStream &s, QRegion &r)
350 r.exec(b, s.version(), s.byteOrder());
355#ifndef QT_NO_DEBUG_STREAM
358 QDebugStateSaver saver(s);
363 }
else if (r.isEmpty()) {
366 const int count = r.rectCount();
368 s <<
"size=" << count <<
", bounds=(";
369 QtDebugUtils::formatQRect(s, r.boundingRect());
373 for (
const QRect &rect : r) {
377 QtDebugUtils::formatQRect(s, rect);
395
396
397
398
399
400QRegion QRegion::operator|(
const QRegion &r)
const
401 {
return united(r); }
404
405
406
407
408
409QRegion QRegion::operator+(
const QRegion &r)
const
410 {
return united(r); }
413
414
415
416QRegion QRegion::operator+(
const QRect &r)
const
417 {
return united(r); }
420
421
422
423
424
425QRegion QRegion::operator&(
const QRegion &r)
const
426 {
return intersected(r); }
429
430
431
432QRegion QRegion::operator&(
const QRect &r)
const
434 return intersected(r);
438
439
440
441
442
443QRegion QRegion::operator-(
const QRegion &r)
const
444 {
return subtracted(r); }
447
448
449
450
451
452QRegion QRegion::operator^(
const QRegion &r)
const
456
457
458
459
460
461
462QRegion& QRegion::operator|=(
const QRegion &r)
463 {
return *
this = *
this | r; }
466
467
468
469
470
471
473
474
475
476
477
478
479
480
483
484
485
486
487
488
489
490
491QRegion& QRegion::operator&=(
const QRegion &r)
492 {
return *
this = *
this & r; }
495
496
497
498#if defined (Q_OS_UNIX) || defined (Q_OS_WIN)
499QRegion& QRegion::operator&=(
const QRect &r)
501 return *
this = *
this & r;
504QRegion& QRegion::operator&=(
const QRect &r)
506 return *
this &= (QRegion(r));
511
512
513
514
515
516
517
518
519QRegion& QRegion::operator-=(
const QRegion &r)
520 {
return *
this = *
this - r; }
523
524
525
526
527
528
529QRegion& QRegion::operator^=(
const QRegion &r)
530 {
return *
this = *
this ^ r; }
533
534
535
536
537
540
541
542QRegion::operator QVariant()
const
544 return QVariant::fromValue(*
this);
548
549
550
551
552
555
556
557
558
559
562
563
564
565
566
567
568
569
570
571
572
575
576
577
578
579
580
581
582
583
586QRegion::translated(
int dx,
int dy)
const
589 ret.translate(dx, dy);
596 return (r1.right() >= r2.left() && r1.left() <= r2.right() &&
597 r1.bottom() >= r2.top() && r1.top() <= r2.bottom());
601
602
603
604
605
606bool QRegion::intersects(
const QRegion ®ion)
const
608 if (isEmpty() || region.isEmpty())
611 if (!rect_intersects(boundingRect(), region.boundingRect()))
613 if (rectCount() == 1 && region.rectCount() == 1)
616 for (
const QRect &myRect : *
this)
617 for (
const QRect &otherRect : region)
618 if (rect_intersects(myRect, otherRect))
624
625
626
627
628
629
632#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_QDOC)
634
635
636
637QRegion QRegion::intersect(
const QRect &r)
const
639 return intersect(QRegion(r));
644
645
646
647
648
649
652
653
654
655
656
657
658
659
662
663
664
665
666
667
668
669
670
673
674
675
676
677
680
681
682
683
684
685
688
689
690
691
692
693
694
697
698
699
700
701
702
703
704
705
706
707
710
711
712
713
714
715
716
719
720
721
722
723
724
725
726
727
728
729
732
733
734
735
736
737
738
739
740
741
742
743
746
747
748
749
750
751
752
753
754
755
756
757
760
761
762
763
764
767
768
769
770
771
772
773
774
775
776
777
778
781
782
783
784
785
786
787
788
789
790
791
792
795
796
797
798
799
800
801
802
803
804
807
808
809
810
811
814
815
816
817
818
819
820
821
822
823
826
827
828
829
830
833
834
835
836
837
838
839
840
841
842
845
846
847
848
849
852
853
854
855
856
857
858
859
860
861
864
865
866
867
868
871
872
873
874
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
914 return qMin(point.x(), next->point.x());
919 return qMax(point.x(), next->point.x());
922 bool overlaps(
const Segment &other)
const
924 return left() < other.right() && other.left() < right();
927 void connect(Segment &other)
932 horizontal = (point.y() == other.point.y());
935 void merge(Segment &other)
937 if (right() <= other.right()) {
939 Segment *oprev = other.prev;
949 Segment *onext = other.next;
966void mergeSegments(Segment *a,
int na, Segment *b,
int nb)
971 while (i != na && j != nb) {
974 const int ra = sa.right();
975 const int rb = sb.right();
983void addSegmentsToPath(Segment *segment, QPainterPath &path)
985 Segment *current = segment;
986 path.moveTo(current->point);
988 current->added =
true;
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;
997 current = current->next;
1013 QPainterPath result;
1014 if (region.rectCount() == 1) {
1015 result.addRect(region.boundingRect());
1019 auto rect = region.begin();
1020 const auto end = region.end();
1022 QVarLengthArray<Segment> segments;
1023 segments.resize(4 * (end - rect));
1025 int lastRowSegmentCount = 0;
1026 Segment *lastRowSegments =
nullptr;
1028 int lastSegment = 0;
1030 while (rect != end) {
1031 const int y = rect[0].y();
1033 while (&rect[count] != end && rect[count].y() == y)
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));
1043 offset = lastSegment + i;
1044 for (
int j = 0; j < 4; ++j)
1045 segments[offset + j * count].connect(segments[offset + ((j + 1) % 4) * count]);
1048 if (lastRowSegments && lastY == y)
1049 mergeSegments(lastRowSegments, lastRowSegmentCount, &segments[lastSegment], count);
1051 lastRowSegments = &segments[lastSegment + 2 * count];
1052 lastRowSegmentCount = count;
1053 lastSegment += 4 * count;
1054 lastY = y + rect[0].height();
1058 for (
int i = 0; i < lastSegment; ++i) {
1059 Segment *segment = &segments[i];
1060 if (!segment->added)
1061 addSegmentsToPath(segment, result);
1069
1070
1091
1092
1093
1095 return contains(r.extents);
1099 const QRect &r1 = innerRect;
1100 return r2.left() >= r1.left() && r2.right() <= r1.right()
1101 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1105
1106
1108 const QRect &r2 = extents;
1109 return r2.left() >= r1.left() && r2.right() <= r1.right()
1110 && r2.top() >= r1.top() && r2.bottom() <= r1.bottom();
1114 const int area = rect.width() * rect.height();
1130 {
return numRects == 1 ? &extents : rects.data(); }
1132 const QRect *
end()
const noexcept
1147 const QRect *nextToTop,
1148 const QRect *nextToBottom);
1150 const QRect *nextToBottom,
1151 const QRect *nextToTop);
1153#ifdef QT_REGION_DEBUG
1165 return (right->top() == left->top()
1166 && right->bottom() == left->bottom()
1167 && right->left() <= (left->right() + 1));
1178 left->setRight(right->right());
1188 right->setLeft(left->left());
1196 const QRect *nextToTop,
1197 const QRect *nextToBottom)
1199 if (nextToTop && nextToTop->y() == top->y())
1201 if (nextToBottom && nextToBottom->y() == bottom->y())
1204 return ((top->bottom() >= (bottom->top() - 1))
1205 && top->left() == bottom->left()
1206 && top->right() == bottom->right());
1210 const QRect *nextToTop,
1211 const QRect *nextToBottom)
1214 top->setBottom(bottom->bottom());
1222 const QRect *nextToBottom,
1223 const QRect *nextToTop)
1226 bottom->setTop(top->top());
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()));
1246 Q_ASSERT(extents.intersects(rect));
1249#ifdef QT_REGION_DEBUG
1253 const QRect r = rect.normalized();
1255 innerRect = QRect();
1258 QRect *dest = rects.data();
1259 const QRect *src = dest;
1263 *dest = qt_rect_intersect_normalized(*src++, r);
1264 if (dest->isEmpty())
1270 extents.setLeft(qMin(extents.left(), dest->left()));
1273 extents.setRight(qMax(extents.right(), dest->right()));
1274 extents.setBottom(qMax(extents.bottom(), dest->bottom()));
1276 const QRect *nextToLast = (
numRects > 1 ? dest - 2 :
nullptr);
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());
1292#ifdef QT_REGION_DEBUG
1299 Q_ASSERT(!r->isEmpty());
1301 QRect *myLast = (numRects == 1 ? &extents : rects.data() + (numRects - 1));
1304 const QRect *nextToTop = (
numRects > 2 ? myLast - 2 :
nullptr);
1314 if (rects.size() < numRects)
1315 rects.resize(numRects);
1316 rects[numRects - 1] = *r;
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()));
1323#ifdef QT_REGION_DEBUG
1333 append(&r->extents);
1339 QRect *destRect = rects.data() + numRects;
1340 const QRect *srcRect = r->rects.constData();
1345 const QRect *rFirst = srcRect;
1346 QRect *myLast = destRect - 1;
1347 const QRect *nextToLast = (
numRects > 1 ? myLast - 1 :
nullptr);
1351 const QRect *rNextToFirst = (numAppend > 1 ? rFirst + 2 :
nullptr);
1357 nextToLast = (
numRects > 2 ? myLast - 2 :
nullptr);
1358 rNextToFirst = (numAppend > 0 ? srcRect :
nullptr);
1371 if (numAppend > 0) {
1372 const int newNumRects =
numRects + numAppend;
1373 if (newNumRects > rects.size()) {
1374 rects.resize(newNumRects);
1375 destRect = rects.data() + numRects;
1377 memcpy(destRect, srcRect, numAppend *
sizeof(QRect));
1385 innerRect = r->innerRect;
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()));
1396#ifdef QT_REGION_DEBUG
1406 prepend(&r->extents);
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);
1424 rNextToLast = (numPrepend > 1 ? rLast - 1 :
nullptr);
1430 nextToFirst = (
numRects > 2? myFirst + 2 :
nullptr);
1431 rNextToLast = (numPrepend > 0 ? rLast :
nullptr);
1442 if (numPrepend > 0) {
1443 const int newNumRects =
numRects + numPrepend;
1444 if (newNumRects > rects.size())
1445 rects.resize(newNumRects);
1448 memmove(rects.data() + numPrepend, rects.constData() + numSkip,
1449 numRects *
sizeof(QRect));
1452 memcpy(rects.data(), r->rects.constData(), numPrepend *
sizeof(QRect));
1460 innerRect = r->innerRect;
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()));
1469#ifdef QT_REGION_DEBUG
1476 Q_ASSERT(!r->isEmpty());
1478 QRect *myFirst = (numRects == 1 ? &extents : rects.data());
1481 const QRect *nextToFirst = (
numRects > 2 ? myFirst + 2 :
nullptr);
1484 memmove(rects.data(), rects.constData() + 1,
1485 numRects *
sizeof(QRect));
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()));
1501#ifdef QT_REGION_DEBUG
1508 Q_ASSERT(!r->isEmpty());
1510 const QRect *myLast = (numRects == 1) ? &extents : (rects.constData() + (numRects - 1));
1511 if (r->top() > myLast->bottom())
1513 if (r->top() == myLast->top()
1514 && r->height() == myLast->height()
1515 && r->left() > myLast->right())
1525 return canAppend(r
->numRects == 1 ? &r->extents : r->rects.constData());
1530 Q_ASSERT(!r->isEmpty());
1532 const QRect *myFirst = (numRects == 1) ? &extents : rects.constData();
1533 if (r->bottom() < myFirst->top())
1535 if (r->top() == myFirst->top()
1536 && r->height() == myFirst->height()
1537 && r->right() < myFirst->left())
1550#ifdef QT_REGION_DEBUG
1551void QRegionPrivate::selfTest()
const
1553 if (numRects == 0) {
1554 Q_ASSERT(extents.isEmpty());
1555 Q_ASSERT(innerRect.isEmpty());
1559 Q_ASSERT(innerArea == (innerRect.width() * innerRect.height()));
1561 if (numRects == 1) {
1562 Q_ASSERT(innerRect == extents);
1563 Q_ASSERT(!innerRect.isEmpty());
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;
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));
1581 Q_ASSERT(r2.y() >= r.bottom());
1588Q_CONSTINIT
static QRegionPrivate qrp;
1589Q_CONSTINIT
const QRegion::QRegionData QRegion::shared_empty = {Q_REFCOUNT_INITIALIZE_STATIC, &qrp};
1592 const QRect *r2,
const QRect *r2End,
int y1,
int y2);
1602#define RectangleOut 0
1603#define RectangleIn 1
1604#define RectanglePart 2
1605#define EvenOddRule 0
1606#define WindingRule 1
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
1656
1661QT_BEGIN_INCLUDE_NAMESPACE
1663QT_END_INCLUDE_NAMESPACE
1666
1667
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())
1676
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());
1690
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;
1701
1702
1703
1704#define NUMPTSTOBUFFER 200
1707
1708
1709
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
1767
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1798 if (rect->isEmpty())
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1834 dest.innerRect.setCoords(0, 0, -1, -1);
1837 dest.extents.setCoords(0, 0, -1, -1);
1841 pExtents = &dest.extents;
1842 if (dest.rects.isEmpty())
1843 pBox = &dest.extents;
1845 pBox = dest.rects.constData();
1849
1850
1851
1852
1853
1854
1855 pExtents->setLeft(pBox->left());
1856 pExtents->setTop(pBox->top());
1857 pExtents->setRight(pBoxEnd->right());
1858 pExtents->setBottom(pBoxEnd->bottom());
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());
1869 Q_ASSERT(pExtents->left() <= pExtents->right());
1873
1874
1875
1879 if (region.rects.size()) {
1880 QRect *pbox = region.rects.data();
1884 pbox->translate(x, y);
1888 region.extents.translate(x, y);
1889 region.innerRect.translate(x, y);
1893
1894
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1909 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
1915 pNextRect = dest.rects.data() + dest
.numRects;
1917 while (r1 != r1End && r2 != r2End) {
1918 x1 = qMax(r1->left(), r2->left());
1919 x2 = qMin(r1->right(), r2->right());
1922
1923
1924
1925
1926
1927
1930 MEMCHECK(dest, pNextRect, dest.rects)
1931 pNextRect->setCoords(x1, y1, x2, y2);
1937
1938
1939
1940
1941 if (r1->right() < r2->right()) {
1943 }
else if (r2->right() < r1->right()) {
1953
1954
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1981 QRect *rData = dest.rects.data();
1985 pPrevBox = rData + prevStart;
1986 prevNumRects = curStart - prevStart;
1989
1990
1991
1992
1993 pCurBox = rData + curStart;
1994 bandY1 = pCurBox->top();
1995 for (curNumRects = 0; pCurBox != pRegEnd && pCurBox->top() == bandY1; ++curNumRects) {
1999 if (pCurBox != pRegEnd) {
2001
2002
2003
2004
2005
2007 while ((pRegEnd - 1)->top() == pRegEnd->top())
2009 curStart = pRegEnd - rData;
2013 if (curNumRects == prevNumRects && curNumRects != 0) {
2014 pCurBox -= curNumRects;
2016
2017
2018
2019 if (pPrevBox->bottom() == pCurBox->top() - 1) {
2021
2022
2023
2024
2025
2027 if (pPrevBox->left() != pCurBox->left() || pPrevBox->right() != pCurBox->right()) {
2034 }
while (prevNumRects != 0);
2037 pCurBox -= curNumRects;
2038 pPrevBox -= curNumRects;
2041
2042
2043
2044
2046 pPrevBox->setBottom(pCurBox->bottom());
2051 }
while (curNumRects != 0);
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063 if (pCurBox == pRegEnd) {
2064 curStart = prevStart;
2067 *pPrevBox++ = *pCurBox++;
2069 }
while (pCurBox != pRegEnd);
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2115 const QRect *r1BandEnd;
2116 const QRect *r2BandEnd;
2121
2122
2123
2124
2125
2126
2128 r1 = ®1->extents;
2130 r1 = reg1->rects.constData();
2132 r2 = ®2->extents;
2134 r2 = reg2->rects.constData();
2142
2143
2144
2145
2146
2147 const QList<QRect> destRectsCopy = dest.rects;
2148 Q_UNUSED(destRectsCopy);
2153
2154
2155
2156
2157
2158
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174 if (reg1->extents.top() < reg2->extents.top())
2175 ybot = reg1->extents.top() - 1;
2177 ybot = reg2->extents.top() - 1;
2180
2181
2182
2183
2184
2185
2186
2187
2194
2195
2196
2197
2198
2199
2201 while (r1BandEnd != r1End && r1BandEnd->top() == r1->top())
2205 while (r2BandEnd != r2End && r2BandEnd->top() == r2->top())
2209
2210
2211
2212
2213
2214
2215
2216 if (r1->top() < r2->top()) {
2217 top = qMax(r1->top(), ybot + 1);
2218 bot = qMin(r1->bottom(), r2->top() - 1);
2220 if (nonOverlap1Func !=
nullptr && bot >= top)
2221 (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot);
2223 }
else if (r2->top() < r1->top()) {
2224 top = qMax(r2->top(), ybot + 1);
2225 bot = qMin(r2->bottom(), r1->top() - 1);
2227 if (nonOverlap2Func !=
nullptr && bot >= top)
2228 (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot);
2235
2236
2237
2238
2239
2244
2245
2246
2247 ybot = qMin(r1->bottom(), r2->bottom());
2250 (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
2256
2257
2258
2259 if (r1->bottom() == ybot)
2261 if (r2->bottom() == ybot)
2263 }
while (r1 != r1End && r2 != r2End);
2266
2267
2270 if (nonOverlap1Func !=
nullptr) {
2273 while (r1BandEnd < r1End && r1BandEnd->top() == r1->top())
2275 (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom());
2277 }
while (r1 != r1End);
2279 }
else if ((r2 != r2End) && (nonOverlap2Func !=
nullptr)) {
2282 while (r2BandEnd < r2End && r2BandEnd->top() == r2->top())
2284 (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom());
2286 }
while (r2 != r2End);
2293
2294
2295
2296
2297
2298
2299
2300 if (qMax(4, dest
.numRects) < (dest.rects.size() >> 1))
2305
2306
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2330 pNextRect = dest.rects.data() + dest
.numRects;
2335 Q_ASSERT(r->left() <= r->right());
2336 MEMCHECK(dest, pNextRect, dest.rects)
2337 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2362 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
2366 pNextRect = dest.rects.data() + dest
.numRects;
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());
2379 MEMCHECK(dest, pNextRect, dest.rects)
2380 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2381 dest.updateInnerRect(*pNextRect);
2388 while (r1 != r1End && r2 != r2End) {
2389 if (r1->left() < r2->left()) {
2399 }
while (r1 != r1End);
2401 while (r2 != r2End) {
2418 dest.innerRect = reg1->innerRect;
2421 dest.innerRect = reg2->innerRect;
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()));
2432
2433
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2451 const QRect *rEnd,
int y1,
int y2)
2455 pNextRect = dest.rects.data() + dest
.numRects;
2460 Q_ASSERT(r->left() <= r->right());
2461 MEMCHECK(dest, pNextRect, dest.rects)
2462 pNextRect->setCoords(r->left(), y1, r->right(), y2);
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2485 const QRect *r2,
const QRect *r2End,
int y1,
int y2)
2493 pNextRect = dest.rects.data() + dest
.numRects;
2495 while (r1 != r1End && r2 != r2End) {
2496 if (r2->right() < x1) {
2498
2499
2501 }
else if (r2->left() <= x1) {
2503
2504
2505 x1 = r2->right() + 1;
2506 if (x1 > r1->right()) {
2508
2509
2510
2518 }
else if (r2->left() <= r1->right()) {
2520
2521
2522
2523 Q_ASSERT(x1 < r2->left());
2524 MEMCHECK(dest, pNextRect, dest.rects)
2525 pNextRect->setCoords(x1, y1, r2->left() - 1, y2);
2529 x1 = r2->right() + 1;
2530 if (x1 > r1->right()) {
2532
2533
2543
2544
2545 if (r1->right() >= x1) {
2546 MEMCHECK(dest, pNextRect, dest.rects)
2547 pNextRect->setCoords(x1, y1, r1->right(), y2);
2558
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);
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2590 Q_ASSERT(
EXTENTCHECK(®M->extents, ®S->extents));
2597
2598
2599
2600
2601
2602
2609 Q_ASSERT(
EXTENTCHECK(&sra->extents, &srb->extents));
2638
2639
2646 }
else if (r1->extents != r2->extents) {
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) {
2668 if (!pRegion->extents.contains(x, y))
2671 return pRegion->extents.contains(x, y);
2672 if (pRegion->innerRect.contains(x, y))
2675 if (pRegion->rects[i].contains(x, y))
2684 const QRect *pboxEnd;
2685 QRect rect(rx, ry, rwidth, rheight);
2686 QRect *prect = ▭
2687 int partIn, partOut;
2696 pbox = (region
->numRects == 1) ? ®ion->extents : region->rects.constData();
2698 for (; pbox < pboxEnd; ++pbox) {
2699 if (pbox->bottom() < ry)
2702 if (pbox->top() > ry) {
2704 if (partIn || pbox->top() > prect->bottom())
2709 if (pbox->right() < rx)
2712 if (pbox->left() > rx) {
2718 if (pbox->left() <= prect->right()) {
2724 if (pbox->right() >= prect->right()) {
2725 ry = pbox->bottom() + 1;
2726 if (ry > prect->bottom())
2731
2732
2733
2734
2735
2736
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
2791
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) {
2832
2833
2834
2841 incr1 = -2
* dx + 2
* (dy) * m1;
2842 incr2 = -2
* dx + 2
* (dy) * m;
2843 d = 2
* m * (dy) - 2
* dx - 2
* (dy);
2847 incr1 = 2
* dx - 2
* (dy) * m1;
2848 incr2 = 2
* dx - 2
* (dy) * m;
2849 d = -2
* m * (dy) + 2
* dx;
2852}
2854#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) {
2874}
2878
2879
2880
2892#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
2894 bres.m, bres.m1, bres.incr1, bres.incr2)
2896#define BRESINCRPGONSTRUCT(bres)
2897 BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
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
2945
2949
2951#define COUNTERCLOCKWISE -1
2953typedef struct _EdgeTableEntry {
2957 struct _EdgeTableEntry *next;
2958 struct _EdgeTableEntry *back;
2959 struct _EdgeTableEntry *nextWETE;
2963typedef struct _ScanLineList{
2965 EdgeTableEntry *edgelist;
2966 struct _ScanLineList *next;
2973 ScanLineList scanlines;
2978
2980
2982#define SLLSPERBLOCK 25
2984typedef struct _ScanLineListBlock {
2986 struct _ScanLineListBlock *next;
2992
2993
2994
2995
2996
2997
2998
2999
3000
3002
3003
3004#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) {
3005 if (pAET->ymax == y) {
3006 pPrevAET->next = pAET->next;
3007 pAET = pPrevAET->next;
3010 pAET->back = pPrevAET;
3017}
3021
3022
3023
3025
3026
3027#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) {
3028 if (pAET->ymax == y) {
3029 pPrevAET->next = pAET->next;
3030 pAET = pPrevAET->next;
3032 pAET->back = pPrevAET;
3039}
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
3088
3092#define LARGE_COORDINATE INT_MAX
3093#define SMALL_COORDINATE INT_MIN
3096
3097
3098
3099
3100
3102
3103
3104static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
int scanline,
3105 ScanLineListBlock **SLLBlock,
int *iSLLBlock)
3107 EdgeTableEntry *start, *prev;
3108 ScanLineList *pSLL, *pPrevSLL;
3109 ScanLineListBlock *tmpSLLBlock;
3112
3113
3114 pPrevSLL = &ET->scanlines;
3115 pSLL = pPrevSLL->next;
3116 while (pSLL && (pSLL->scanline < scanline)) {
3122
3123
3124 if ((!pSLL) || (pSLL->scanline > scanline)) {
3128 (ScanLineListBlock *)malloc(
sizeof(ScanLineListBlock));
3129 Q_CHECK_PTR(tmpSLLBlock);
3130 (*SLLBlock)->next = tmpSLLBlock;
3131 tmpSLLBlock->next = (ScanLineListBlock *)
nullptr;
3132 *SLLBlock = tmpSLLBlock;
3135 pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
3137 pSLL->next = pPrevSLL->next;
3138 pSLL->edgelist = (EdgeTableEntry *)
nullptr;
3139 pPrevSLL->next = pSLL;
3141 pSLL->scanline = scanline;
3144
3145
3147 start = pSLL->edgelist;
3148 while (start && (start->bres.minor_axis < ETE->bres.minor_axis)) {
3150 start = start->next;
3157 pSLL->edgelist = ETE;
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3183
3185static void CreateETandAET(
int count,
const QPoint *pts,
3186 EdgeTable *ET, EdgeTableEntry *AET, EdgeTableEntry *pETEs,
3187 ScanLineListBlock *pSLLBlock)
3196 Q_ASSERT(count > 1);
3199
3200
3201 AET->next =
nullptr;
3202 AET->back =
nullptr;
3203 AET->nextWETE =
nullptr;
3207
3208
3209 ET->scanlines.next =
nullptr;
3212 pSLLBlock->next =
nullptr;
3214 PrevPt = &pts[count - 1];
3217
3218
3219
3220
3225
3226
3227 if (PrevPt->y() > CurrPt->y()) {
3230 pETEs->ClockWise = 0;
3234 pETEs->ClockWise = 1;
3238
3239
3240 if (bottom->y() != top->y()) {
3241 pETEs->ymax = bottom->y() - 1;
3244
3245
3246 dy = bottom->y() - top->y();
3249 InsertEdgeInET(ET, pETEs, top->y(), &pSLLBlock, &iSLLBlock);
3251 if (PrevPt->y() > ET->ymax)
3252 ET->ymax = PrevPt->y();
3253 if (PrevPt->y() < ET->ymin)
3254 ET->ymin = PrevPt->y();
3263
3264
3265
3266
3267
3269
3271static void loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
3273 EdgeTableEntry *pPrevAET;
3274 EdgeTableEntry *tmp;
3279 while (AET && AET->bres.minor_axis < ETEs->bres.minor_axis) {
3287 ETEs->back = pPrevAET;
3288 pPrevAET->next = ETEs;
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3313
3314
3315static void computeWAET(EdgeTableEntry *AET)
3317 EdgeTableEntry *pWETE;
3321 AET->nextWETE =
nullptr;
3330 if ((!inside && !isInside) || (inside && isInside)) {
3331 pWETE->nextWETE = AET;
3337 pWETE->nextWETE =
nullptr;
3341
3342
3343
3344
3345
3347
3349static int InsertionSort(EdgeTableEntry *AET)
3351 EdgeTableEntry *pETEchase;
3352 EdgeTableEntry *pETEinsert;
3353 EdgeTableEntry *pETEchaseBackTMP;
3360 while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
3361 pETEchase = pETEchase->back;
3364 if (pETEchase != pETEinsert) {
3365 pETEchaseBackTMP = pETEchase->back;
3366 pETEinsert->back->next = AET;
3368 AET->back = pETEinsert->back;
3369 pETEinsert->next = pETEchase;
3370 pETEchase->back->next = pETEinsert;
3371 pETEchase->back = pETEinsert;
3372 pETEinsert->back = pETEchaseBackTMP;
3380
3381
3382static void FreeStorage(ScanLineListBlock *pSLLBlock)
3384 ScanLineListBlock *tmpSLLBlock;
3387 tmpSLLBlock = pSLLBlock->next;
3389 pSLLBlock = tmpSLLBlock;
3395 QRegionSpan(
int x1_,
int x2_) : x1(x1_), x2(x2_) {}
3399 int width()
const {
return x2 - x1; }
3402Q_DECLARE_TYPEINFO(QRegionSpan, Q_PRIMITIVE_TYPE);
3404static inline void flushRow(
const QRegionSpan *spans,
int y,
int numSpans,
QRegionPrivate *reg,
int *lastRow,
int *extendTo,
bool *needsExtend)
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);
3411 for (
int i = 0; i < numSpans && canExtend; ++i) {
3412 if (regRects[i].x() != spans[i].x1 || regRects[i].right() != spans[i].x2 - 1)
3418 *needsExtend =
true;
3421 for (
int i = 0; i < reg->rects.size() - *lastRow; ++i)
3422 regRects[i].setBottom(*extendTo);
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);
3430 if (spans[0].x1 < reg->extents.left())
3431 reg->extents.setLeft(spans[0].x1);
3433 if (spans[numSpans-1].x2 - 1 > reg->extents.right())
3434 reg->extents.setRight(spans[numSpans-1].x2 - 1);
3436 *needsExtend =
false;
3441
3442
3443
3444
3446
3447
3448static void PtsToRegion(
int numFullPtBlocks,
int iCurPtBlock,
3453 bool needsExtend =
false;
3454 QVarLengthArray<QRegionSpan> row;
3455 qsizetype rowSize = 0;
3457 reg->extents.setLeft(INT_MAX);
3458 reg->extents.setRight(INT_MIN);
3461 POINTBLOCK *CurPtBlock = FirstPtBlock;
3462 for (; numFullPtBlocks >= 0; --numFullPtBlocks) {
3465 if (!numFullPtBlocks)
3466 i = iCurPtBlock >> 1;
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();
3472 if (rowSize && row[rowSize-1].x2 == pts[0].x())
3473 row[rowSize-1].x2 = pts[1].x();
3475 row[rowSize++] = QRegionSpan(pts[0].x(), pts[1].x());
3479 QPoint *next = i ? &pts[2] : (numFullPtBlocks && iCurPtBlock ? CurPtBlock->next->pts :
nullptr);
3481 if (!next || next->y() != pts[0].y()) {
3482 flushRow(row.data(), pts[0].y(), rowSize, reg, &lastRow, &extendTo, &needsExtend);
3488 CurPtBlock = CurPtBlock
->next;
3492 for (
int i = lastRow; i < reg->rects.size(); ++i)
3493 reg->rects[i].setBottom(extendTo);
3499 reg->extents.setTop(reg->rects[0].top());
3500 reg->extents.setBottom(reg->rects[lastRow].bottom());
3502 for (
int i = 0; i < reg->rects.size(); ++i)
3505 reg->extents.setCoords(0, 0, 0, 0);
3510
3511
3512
3513
3514
3516
3517
3524 EdgeTableEntry *pAET;
3527 EdgeTableEntry *pWETE;
3530 EdgeTableEntry *pPrevAET;
3532 EdgeTableEntry *AET;
3533 EdgeTableEntry *pETEs;
3534 ScanLineListBlock SLLBlock;
3535 int fixWAET =
false;
3536 POINTBLOCK FirstPtBlock, *curPtBlock;
3537 FirstPtBlock
.pts =
reinterpret_cast<
QPoint *>(FirstPtBlock.data);
3538 FirstPtBlock
.next =
nullptr;
3539 POINTBLOCK *tmpPtBlock;
3540 int numFullPtBlocks = 0;
3542 Q_ASSERT(Count > 1);
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())) {
3562 region->innerRect = region->extents;
3563 region
->innerArea = region->innerRect.width() * region->innerRect.height();
3568 if (!(pETEs =
static_cast<EdgeTableEntry *>(malloc(
sizeof(EdgeTableEntry) * Count)))) {
3575 AET =
new EdgeTableEntry;
3576 pts = FirstPtBlock
.pts;
3577 CreateETandAET(Count, Pts, &ET, AET, pETEs, &SLLBlock);
3579 pSLL = ET.scanlines.next;
3580 curPtBlock = &FirstPtBlock;
3583 if (ET.ymax - ET.ymin > 100000) {
3586 qWarning(
"QRegion: creating region from big polygon failed...!");
3597
3598
3599 for (y = ET.ymin; y < ET.ymax; ++y) {
3602
3603
3604
3605 if (pSLL && y == pSLL->scanline) {
3606 loadAET(AET, pSLL->edgelist);
3613
3614
3616 pts->setX(pAET->bres.minor_axis);
3622
3623
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;
3640
3641
3642 for (y = ET.ymin; y < ET.ymax; ++y) {
3644
3645
3646
3647 if (pSLL && y == pSLL->scanline) {
3648 loadAET(AET, pSLL->edgelist);
3657
3658
3661
3662
3663
3664 if (pWETE == pAET) {
3665 pts->setX(pAET->bres.minor_axis);
3671
3672
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;
3682 pWETE = pWETE->nextWETE;
3688
3689
3690
3691 if (InsertionSort(AET) || fixWAET) {
3698 FreeStorage(SLLBlock.next);
3699 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3700 for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
3701 tmpPtBlock = curPtBlock->next;
3703 curPtBlock = tmpPtBlock;
3709 FreeStorage(SLLBlock.next);
3710 PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
3711 for (curPtBlock = FirstPtBlock
.next; --numFullPtBlocks >= 0;) {
3712 tmpPtBlock = curPtBlock
->next;
3714 curPtBlock = tmpPtBlock;
3724 const QImage image = bitmap.toImage();
3732 xr.setCoords(prev1, y, x-1
, y);
3733 UnionRectWithRegion(&xr, region, *region);
3736 const uchar zero = 0;
3737 bool little = image.format() == QImage::Format_MonoLSB;
3741 for (y = 0; y < image.height(); ++y) {
3742 const uchar *line = image.constScanLine(y);
3743 int w = image.width();
3746 for (x = 0; x < w;) {
3747 uchar byte = line[x / 8];
3748 if (x > w - 8 || byte!=all) {
3750 for (
int b = 8; b > 0 && x < w; --b) {
3751 if (!(byte & 0x01) == !all) {
3767 for (
int b = 8; b > 0 && x < w; --b) {
3768 if (!(byte & 0x80) == !all) {
3798 : d(
const_cast<QRegionData*>(&shared_empty))
3802QRegion::QRegion(
const QRect &r, RegionType t)
3805 d =
const_cast<QRegionData*>(&shared_empty);
3807 d =
new QRegionData;
3808 if (t == Rectangle) {
3809 d->qt_rgn =
new QRegionPrivate(r);
3810 }
else if (t == Ellipse) {
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);
3819QRegion::QRegion(
const QPolygon &a, Qt::FillRule fillRule)
3822 QRegionPrivate *qt_rgn = PolygonRegion(a.constData(), a.size(),
3825 d =
new QRegionData;
3828 d =
const_cast<QRegionData*>(&shared_empty);
3831 d =
const_cast<QRegionData*>(&shared_empty);
3835QRegion::QRegion(
const QRegion &r)
3842QRegion::QRegion(
const QBitmap &bm)
3845 d =
const_cast<QRegionData*>(&shared_empty);
3847 d =
new QRegionData;
3848 d->qt_rgn = qt_bitmapToRegion(bm);
3852void QRegion::cleanUp(QRegion::QRegionData *x)
3860 if (!d->ref.deref())
3865QRegion &QRegion::operator=(
const QRegion &r)
3868 if (!d->ref.deref())
3876
3877
3878QRegion QRegion::copy()
const
3881 auto x = std::make_unique<QRegionData>();
3882 x->ref.initializeOwned();
3884 x->qt_rgn =
new QRegionPrivate(*d->qt_rgn);
3886 x->qt_rgn =
new QRegionPrivate;
3887 if (!r.d->ref.deref())
3893bool QRegion::isEmpty()
const
3895 return d == &shared_empty || d->qt_rgn->numRects == 0;
3898bool QRegion::isNull()
const
3900 return d == &shared_empty || d->qt_rgn->numRects == 0;
3903bool QRegion::contains(
const QPoint &p)
const
3905 return PointInRegion(d->qt_rgn, p.x(), p.y());
3908bool QRegion::contains(
const QRect &r)
const
3910 return RectInRegion(d->qt_rgn, r.left(), r.top(), r.width(), r.height()) !=
RectangleOut;
3915void QRegion::translate(
int dx,
int dy)
3917 if ((dx == 0 && dy == 0) || isEmptyHelper(d->qt_rgn))
3921 OffsetRegion(*d->qt_rgn, dx, dy);
3924QRegion QRegion::united(
const QRegion &r)
const
3926 if (isEmptyHelper(d->qt_rgn))
3928 if (isEmptyHelper(r.d->qt_rgn))
3933 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3935 }
else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3937 }
else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3938 QRegion result(*
this);
3940 result.d->qt_rgn->append(r.d->qt_rgn);
3942 }
else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3943 QRegion result(*
this);
3945 result.d->qt_rgn->prepend(r.d->qt_rgn);
3947 }
else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3952 UnionRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
3957QRegion& QRegion::operator+=(
const QRegion &r)
3959 if (isEmptyHelper(d->qt_rgn))
3961 if (isEmptyHelper(r.d->qt_rgn))
3966 if (d->qt_rgn->contains(*r.d->qt_rgn)) {
3968 }
else if (r.d->qt_rgn->contains(*d->qt_rgn)) {
3970 }
else if (d->qt_rgn->canAppend(r.d->qt_rgn)) {
3972 d->qt_rgn->append(r.d->qt_rgn);
3974 }
else if (d->qt_rgn->canPrepend(r.d->qt_rgn)) {
3976 d->qt_rgn->prepend(r.d->qt_rgn);
3978 }
else if (EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
3982 UnionRegion(d->qt_rgn, r.d->qt_rgn, *d->qt_rgn);
3987QRegion QRegion::united(
const QRect &r)
const
3989 if (isEmptyHelper(d->qt_rgn))
3994 if (d->qt_rgn->contains(r)) {
3996 }
else if (d->qt_rgn->within(r)) {
3998 }
else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4000 }
else if (d->qt_rgn->canAppend(&r)) {
4001 QRegion result(*
this);
4003 result.d->qt_rgn->append(&r);
4005 }
else if (d->qt_rgn->canPrepend(&r)) {
4006 QRegion result(*
this);
4008 result.d->qt_rgn->prepend(&r);
4013 QRegionPrivate rp(r);
4014 UnionRegion(d->qt_rgn, &rp, *result.d->qt_rgn);
4019QRegion& QRegion::operator+=(
const QRect &r)
4021 if (isEmptyHelper(d->qt_rgn))
4026 if (d->qt_rgn->contains(r)) {
4028 }
else if (d->qt_rgn->within(r)) {
4030 }
else if (d->qt_rgn->canAppend(&r)) {
4032 d->qt_rgn->append(&r);
4034 }
else if (d->qt_rgn->canPrepend(&r)) {
4036 d->qt_rgn->prepend(&r);
4038 }
else if (d->qt_rgn->numRects == 1 && d->qt_rgn->extents == r) {
4042 QRegionPrivate p(r);
4043 UnionRegion(d->qt_rgn, &p, *d->qt_rgn);
4048QRegion QRegion::intersected(
const QRegion &r)
const
4050 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn)
4051 || !
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4055 if (r.d->qt_rgn->contains(*d->qt_rgn))
4059 if (d->qt_rgn->contains(*r.d->qt_rgn))
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);
4069 result.d->qt_rgn->intersect(r.d->qt_rgn->extents);
4071 }
else if (d->qt_rgn->numRects == 1) {
4074 result.d->qt_rgn->intersect(d->qt_rgn->extents);
4080 miRegionOp(*result.d->qt_rgn, d->qt_rgn, r.d->qt_rgn, miIntersectO,
nullptr,
nullptr);
4083
4084
4085
4086
4087
4088
4089 miSetExtents(*result.d->qt_rgn);
4093QRegion QRegion::intersected(
const QRect &r)
const
4095 if (isEmptyHelper(d->qt_rgn) || r.isEmpty()
4100 if (d->qt_rgn->within(r))
4104 if (d->qt_rgn->contains(r))
4107 if (d->qt_rgn->numRects == 1) {
4108 const QRect rect = qt_rect_intersect_normalized(d->qt_rgn->extents,
4110 return QRegion(rect);
4113 QRegion result(*
this);
4115 result.d->qt_rgn->intersect(r);
4119QRegion QRegion::subtracted(
const QRegion &r)
const
4121 if (isEmptyHelper(d->qt_rgn) || isEmptyHelper(r.d->qt_rgn))
4123 if (r.d->qt_rgn->contains(*d->qt_rgn))
4125 if (!
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents))
4127 if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn))
4130#ifdef QT_REGION_DEBUG
4131 d->qt_rgn->selfTest();
4132 r.d->qt_rgn->selfTest();
4137 SubtractRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4138#ifdef QT_REGION_DEBUG
4139 result.d->qt_rgn->selfTest();
4144QRegion QRegion::xored(
const QRegion &r)
const
4146 if (isEmptyHelper(d->qt_rgn)) {
4148 }
else if (isEmptyHelper(r.d->qt_rgn)) {
4150 }
else if (!
EXTENTCHECK(&d->qt_rgn->extents, &r.d->qt_rgn->extents)) {
4152 }
else if (d == r.d || EqualRegion(d->qt_rgn, r.d->qt_rgn)) {
4157 XorRegion(d->qt_rgn, r.d->qt_rgn, *result.d->qt_rgn);
4162QRect QRegion::boundingRect()
const noexcept
4166 return d->qt_rgn->extents;
4170
4172
4174bool qt_region_strictContains(
const QRegion ®ion,
const QRect &rect)
4176 if (isEmptyHelper(region.d->qt_rgn) || !rect.isValid())
4180 static bool guard =
false;
4184 QRegion inner = region.d->qt_rgn->innerRect;
4185 Q_ASSERT((inner - region).isEmpty());
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();
4195 if (maxArea > region.d->qt_rgn->innerArea) {
4196 qDebug() <<
"not largest rectangle" << region << region.d->qt_rgn->innerRect;
4198 Q_ASSERT(maxArea <= region.d->qt_rgn->innerArea);
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());
4206QRegion::const_iterator QRegion::begin()
const noexcept
4208 return d->qt_rgn ? d->qt_rgn->begin() :
nullptr;
4211QRegion::const_iterator QRegion::end()
const noexcept
4213 return d->qt_rgn ? d->qt_rgn->end() :
nullptr;
4216static Q_DECL_COLD_FUNCTION
4217void set_rects_warn(
const char *what)
4219 qWarning(
"QRegion::setRects(): %s", what);
4222void QRegion::setRects(
const QRect *r,
int n)
4225 set_rects_warn(
"passing num != 0 when rects == nullptr is deprecated.");
4228 setRects(QSpan<
const QRect>(r, n));
4231void QRegion::setRects(QSpan<
const QRect> rects)
4233 const auto num =
int(rects.size());
4234 if (num != rects.size()) {
4235 set_rects_warn(
"span size exceeds INT_MAX, ignoring");
4240 if (!rects.data() || num == 0 || (num == 1 && rects.front().isEmpty()))
4245 d->qt_rgn->numRects = num;
4247 d->qt_rgn->extents = rects.front();
4248 d->qt_rgn->innerRect = rects.front();
4250 d->qt_rgn->rects.resize(num);
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);
4265 d->qt_rgn->extents = QRect(QPoint(left, top), QPoint(right, bottom));
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4281
4282
4283QSpan<
const QRect> QRegion::rects()
const noexcept
4285 return {begin(), end()};
4288int QRegion::rectCount()
const noexcept
4290 return (d->qt_rgn ? d->qt_rgn->numRects : 0);
4293bool QRegion::operator==(
const QRegion &r)
const
4303 return EqualRegion(d->qt_rgn, r.d->qt_rgn);
4306bool QRegion::intersects(
const QRect &rect)
const
4308 if (isEmptyHelper(d->qt_rgn) || rect.isNull())
4311 const QRect r = rect.normalized();
4312 if (!rect_intersects(d->qt_rgn->extents, r))
4314 if (d->qt_rgn->numRects == 1)
4317 for (
const QRect &rect : *
this) {
4318 if (rect_intersects(r, rect))
4324#if defined(Q_OS_WIN) || defined(Q_QDOC)
4326static inline HRGN qt_RectToHRGN(
const QRect &rc)
4328 return CreateRectRgn(rc.left(), rc.top(), rc.right() + 1, rc.bottom() + 1);
4332
4333
4334
4335
4336HRGN QRegion::toHRGN()
const
4338 const int size = rectCount();
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);
4349 qWarning(
"Error combining HRGNs.");
4350 DeleteObject(tmpRgn);
4356
4357
4358
4359
4360QRegion QRegion::fromHRGN(HRGN hrgn)
4362 DWORD regionDataSize = GetRegionData(hrgn, 0,
nullptr);
4363 if (regionDataSize == 0)
4366 auto regionData =
reinterpret_cast<LPRGNDATA>(malloc(regionDataSize));
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);
\inmodule QtCore\reentrant
Combined button and popup list for selecting options.
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