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