QtBase  v6.3.1
qpainterpath.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 "qpainterpath.h"
41 #include "qpainterpath_p.h"
42 
43 #include <qbitmap.h>
44 #include <qdebug.h>
45 #include <qiodevice.h>
46 #include <qlist.h>
47 #include <qpen.h>
48 #include <qpolygon.h>
49 #include <qtextlayout.h>
50 #include <qvarlengtharray.h>
51 #include <qmath.h>
52 
53 #include <private/qbezier_p.h>
54 #include <private/qfontengine_p.h>
55 #include <private/qnumeric_p.h>
56 #include <private/qobject_p.h>
57 #include <private/qpathclipper_p.h>
58 #include <private/qstroker_p.h>
59 #include <private/qtextengine_p.h>
60 
61 #include <limits.h>
62 
63 #if 0
64 #include <performance.h>
65 #else
66 #define PM_INIT
67 #define PM_MEASURE(x)
68 #define PM_DISPLAY
69 #endif
70 
72 
73 static inline bool isValidCoord(qreal c)
74 {
75  if (sizeof(qreal) >= sizeof(double))
76  return qIsFinite(c) && fabs(c) < 1e128;
77  else
78  return qIsFinite(c) && fabsf(float(c)) < 1e16f;
79 }
80 
81 static bool hasValidCoords(QPointF p)
82 {
83  return isValidCoord(p.x()) && isValidCoord(p.y());
84 }
85 
86 static bool hasValidCoords(QRectF r)
87 {
88  return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
89 }
90 
91 // This value is used to determine the length of control point vectors
92 // when approximating arc segments as curves. The factor is multiplied
93 // with the radius of the circle.
94 
95 // #define QPP_DEBUG
96 // #define QPP_STROKE_DEBUG
97 //#define QPP_FILLPOLYGONS_DEBUG
98 
100 
102  QPointF* startPoint, QPointF *endPoint)
103 {
104  if (r.isNull()) {
105  if (startPoint)
106  *startPoint = QPointF();
107  if (endPoint)
108  *endPoint = QPointF();
109  return;
110  }
111 
112  qreal w2 = r.width() / 2;
113  qreal h2 = r.height() / 2;
114 
115  qreal angles[2] = { angle, angle + length };
116  QPointF *points[2] = { startPoint, endPoint };
117 
118  for (int i = 0; i < 2; ++i) {
119  if (!points[i])
120  continue;
121 
122  qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
123  qreal t = theta / 90;
124  // truncate
125  int quadrant = int(t);
126  t -= quadrant;
127 
128  t = qt_t_for_arc_angle(90 * t);
129 
130  // swap x and y?
131  if (quadrant & 1)
132  t = 1 - t;
133 
134  qreal a, b, c, d;
135  QBezier::coefficients(t, a, b, c, d);
136  QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
137 
138  // left quadrants
139  if (quadrant == 1 || quadrant == 2)
140  p.rx() = -p.x();
141 
142  // top quadrants
143  if (quadrant == 0 || quadrant == 1)
144  p.ry() = -p.y();
145 
146  *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
147  }
148 }
149 
150 #ifdef QPP_DEBUG
151 static void qt_debug_path(const QPainterPath &path)
152 {
153  const char *names[] = {
154  "MoveTo ",
155  "LineTo ",
156  "CurveTo ",
157  "CurveToData"
158  };
159 
160  printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
161  for (int i=0; i<path.elementCount(); ++i) {
162  const QPainterPath::Element &e = path.elementAt(i);
163  Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
164  printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
165  }
166 }
167 #endif
168 
488 {
489  return d_ptr ? d_ptr->elements.size() : 0;
490 }
491 
501 {
502  Q_ASSERT(d_ptr);
503  Q_ASSERT(i >= 0 && i < elementCount());
504  return d_ptr->elements.at(i);
505 }
506 
516 {
517  Q_ASSERT(d_ptr);
518  Q_ASSERT(i >= 0 && i < elementCount());
519  detach();
520  QPainterPath::Element &e = d_ptr->elements[i];
521  e.x = x;
522  e.y = y;
523 }
524 
525 
526 /*###
527  \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
528 
529  Appends the \a other painter path to this painter path and returns a
530  reference to the result.
531 */
532 
537  : d_ptr(nullptr)
538 {
539 }
540 
549 
556  : d_ptr(new QPainterPathPrivate)
557 {
558  Element e = { startPoint.x(), startPoint.y(), MoveToElement };
559  d_func()->elements << e;
560 }
561 
562 void QPainterPath::detach()
563 {
564  d_ptr.detach();
565  setDirty(true);
566 }
567 
571 void QPainterPath::ensureData_helper()
572 {
574  data->elements.reserve(16);
576  data->elements << e;
577  d_ptr.reset(data);
578  Q_ASSERT(d_ptr != nullptr);
579 }
580 
589 {
590  QPainterPath copy(other);
591  swap(copy);
592  return *this;
593 }
594 
615 {
616 }
617 
627 {
628  if (!d_ptr)
629  return;
630 
631  detach();
632  d_func()->clear();
633  d_func()->elements.append( {0, 0, MoveToElement} );
634 }
635 
645 {
646  Q_D(QPainterPath);
647  if ((!d && size > 0) || (d && d->elements.capacity() < size)) {
648  ensureData();
649  detach();
650  d_func()->elements.reserve(size);
651  }
652 }
653 
661 {
662  Q_D(QPainterPath);
663  if (d)
664  return d->elements.capacity();
665 
666  return 0;
667 }
668 
681 {
682 #ifdef QPP_DEBUG
683  printf("QPainterPath::closeSubpath()\n");
684 #endif
685  if (isEmpty())
686  return;
687  detach();
688 
689  d_func()->close();
690 }
691 
711 {
712 #ifdef QPP_DEBUG
713  printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
714 #endif
715 
716  if (!hasValidCoords(p)) {
717 #ifndef QT_NO_DEBUG
718  qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call");
719 #endif
720  return;
721  }
722 
723  ensureData();
724  detach();
725 
726  QPainterPathPrivate *d = d_func();
727  Q_ASSERT(!d->elements.isEmpty());
728 
729  d->require_moveTo = false;
730 
731  if (d->elements.constLast().type == MoveToElement) {
732  d->elements.last().x = p.x();
733  d->elements.last().y = p.y();
734  } else {
735  Element elm = { p.x(), p.y(), MoveToElement };
736  d->elements.append(elm);
737  }
738  d->cStart = d->elements.size() - 1;
739 }
740 
761 {
762 #ifdef QPP_DEBUG
763  printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
764 #endif
765 
766  if (!hasValidCoords(p)) {
767 #ifndef QT_NO_DEBUG
768  qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call");
769 #endif
770  return;
771  }
772 
773  ensureData();
774  detach();
775 
776  QPainterPathPrivate *d = d_func();
777  Q_ASSERT(!d->elements.isEmpty());
778  d->maybeMoveTo();
779  if (p == QPointF(d->elements.constLast()))
780  return;
781  Element elm = { p.x(), p.y(), LineToElement };
782  d->elements.append(elm);
783 
784  d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
785 }
786 
818 void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
819 {
820 #ifdef QPP_DEBUG
821  printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
822  c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
823 #endif
824 
825  if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) {
826 #ifndef QT_NO_DEBUG
827  qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call");
828 #endif
829  return;
830  }
831 
832  ensureData();
833  detach();
834 
835  QPainterPathPrivate *d = d_func();
836  Q_ASSERT(!d->elements.isEmpty());
837 
838 
839  // Abort on empty curve as a stroker cannot handle this and the
840  // curve is irrelevant anyway.
841  if (d->elements.constLast() == c1 && c1 == c2 && c2 == e)
842  return;
843 
844  d->maybeMoveTo();
845 
846  Element ce1 = { c1.x(), c1.y(), CurveToElement };
847  Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
848  Element ee = { e.x(), e.y(), CurveToDataElement };
849  d->elements << ce1 << ce2 << ee;
850 }
851 
874 void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
875 {
876 #ifdef QPP_DEBUG
877  printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
878  c.x(), c.y(), e.x(), e.y());
879 #endif
880 
881  if (!hasValidCoords(c) || !hasValidCoords(e)) {
882 #ifndef QT_NO_DEBUG
883  qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call");
884 #endif
885  return;
886  }
887 
888  ensureData();
889  detach();
890 
891  Q_D(QPainterPath);
892  Q_ASSERT(!d->elements.isEmpty());
893  const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
894  QPointF prev(elm.x, elm.y);
895 
896  // Abort on empty curve as a stroker cannot handle this and the
897  // curve is irrelevant anyway.
898  if (prev == c && c == e)
899  return;
900 
901  QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
902  QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
903  cubicTo(c1, c2, e);
904 }
905 
945 void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
946 {
947 #ifdef QPP_DEBUG
948  printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
949  rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
950 #endif
951 
952  if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) {
953 #ifndef QT_NO_DEBUG
954  qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call");
955 #endif
956  return;
957  }
958 
959  if (rect.isNull())
960  return;
961 
962  ensureData();
963  detach();
964 
965  int point_count;
966  QPointF pts[15];
967  QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
968 
969  lineTo(curve_start);
970  for (int i=0; i<point_count; i+=3) {
971  cubicTo(pts[i].x(), pts[i].y(),
972  pts[i+1].x(), pts[i+1].y(),
973  pts[i+2].x(), pts[i+2].y());
974  }
975 
976 }
977 
978 
1003 {
1004  if (rect.isNull())
1005  return;
1006 
1007  QPointF pt;
1008  qt_find_ellipse_coords(rect, angle, 0, &pt, nullptr);
1009  moveTo(pt);
1010 }
1011 
1012 
1013 
1020 {
1021  return !d_ptr || d_func()->elements.isEmpty()
1022  ? QPointF()
1023  : QPointF(d_func()->elements.constLast().x, d_func()->elements.constLast().y);
1024 }
1025 
1026 
1056 {
1057  if (!hasValidCoords(r)) {
1058 #ifndef QT_NO_DEBUG
1059  qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call");
1060 #endif
1061  return;
1062  }
1063 
1064  if (r.isNull())
1065  return;
1066 
1067  ensureData();
1068  detach();
1069 
1070  bool first = d_func()->elements.size() < 2;
1071 
1072  moveTo(r.x(), r.y());
1073 
1074  Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1075  Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1076  Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1077  Element l4 = { r.x(), r.y(), LineToElement };
1078 
1079  d_func()->elements << l1 << l2 << l3 << l4;
1080  d_func()->require_moveTo = true;
1081  d_func()->convex = first;
1082 }
1083 
1102 {
1103  if (polygon.isEmpty())
1104  return;
1105 
1106  ensureData();
1107  detach();
1108 
1109  moveTo(polygon.constFirst());
1110  for (int i=1; i<polygon.size(); ++i) {
1111  Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1112  d_func()->elements << elm;
1113  }
1114 }
1115 
1135 void QPainterPath::addEllipse(const QRectF &boundingRect)
1136 {
1137  if (!hasValidCoords(boundingRect)) {
1138 #ifndef QT_NO_DEBUG
1139  qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call");
1140 #endif
1141  return;
1142  }
1143 
1144  if (boundingRect.isNull())
1145  return;
1146 
1147  ensureData();
1148  detach();
1149 
1150  bool first = d_func()->elements.size() < 2;
1151 
1152  QPointF pts[12];
1153  int point_count;
1154  QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1155 
1156  moveTo(start);
1157  cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1158  cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1159  cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1160  cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1161  d_func()->require_moveTo = true;
1162 
1163  d_func()->convex = first;
1164 }
1165 
1184 void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1185 {
1186  if (text.isEmpty())
1187  return;
1188 
1189  ensureData();
1190  detach();
1191 
1193  layout.setCacheEnabled(true);
1194 
1195  QTextOption opt = layout.textOption();
1196  opt.setUseDesignMetrics(true);
1197  layout.setTextOption(opt);
1198 
1199  QTextEngine *eng = layout.engine();
1200  layout.beginLayout();
1201  QTextLine line = layout.createLine();
1202  Q_UNUSED(line);
1203  layout.endLayout();
1204  const QScriptLine &sl = eng->lines[0];
1205  if (!sl.length || !eng->layoutData)
1206  return;
1207 
1208  int nItems = eng->layoutData->items.size();
1209 
1210  qreal x(point.x());
1211  qreal y(point.y());
1212 
1213  QVarLengthArray<int> visualOrder(nItems);
1215  for (int i = 0; i < nItems; ++i)
1217  QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1218 
1219  for (int i = 0; i < nItems; ++i) {
1220  int item = visualOrder[i];
1221  const QScriptItem &si = eng->layoutData->items.at(item);
1222 
1224  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1225  QFontEngine *fe = eng->fontEngine(si);
1226  Q_ASSERT(fe);
1227  fe->addOutlineToPath(x, y, glyphs, this,
1228  si.analysis.bidiLevel % 2
1229  ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1230  : QTextItem::RenderFlags{});
1231 
1232  const qreal lw = fe->lineThickness().toReal();
1233  if (f.d->underline) {
1234  qreal pos = fe->underlinePosition().toReal();
1235  addRect(x, y + pos, si.width.toReal(), lw);
1236  }
1237  if (f.d->overline) {
1238  qreal pos = fe->ascent().toReal() + 1;
1239  addRect(x, y - pos, si.width.toReal(), lw);
1240  }
1241  if (f.d->strikeOut) {
1242  qreal pos = fe->ascent().toReal() / 3;
1243  addRect(x, y - pos, si.width.toReal(), lw);
1244  }
1245  }
1246  x += si.width.toReal();
1247  }
1248 }
1249 
1259 {
1260  if (other.isEmpty())
1261  return;
1262 
1263  ensureData();
1264  detach();
1265 
1266  QPainterPathPrivate *d = d_func();
1267  // Remove last moveto so we don't get multiple moveto's
1268  if (d->elements.constLast().type == MoveToElement)
1269  d->elements.remove(d->elements.size()-1);
1270 
1271  // Locate where our own current subpath will start after the other path is added.
1272  int cStart = d->elements.size() + other.d_func()->cStart;
1273  d->elements += other.d_func()->elements;
1274  d->cStart = cStart;
1275 
1276  d->require_moveTo = other.d_func()->isClosed();
1277 }
1278 
1279 
1290 {
1291  if (other.isEmpty())
1292  return;
1293 
1294  ensureData();
1295  detach();
1296 
1297  QPainterPathPrivate *d = d_func();
1298  // Remove last moveto so we don't get multiple moveto's
1299  if (d->elements.constLast().type == MoveToElement)
1300  d->elements.remove(d->elements.size()-1);
1301 
1302  // Locate where our own current subpath will start after the other path is added.
1303  int cStart = d->elements.size() + other.d_func()->cStart;
1304  int first = d->elements.size();
1305  d->elements += other.d_func()->elements;
1306 
1307  if (first != 0)
1308  d->elements[first].type = LineToElement;
1309 
1310  // avoid duplicate points
1311  if (first > 0 && QPointF(d->elements.at(first)) == QPointF(d->elements.at(first - 1))) {
1312  d->elements.remove(first--);
1313  --cStart;
1314  }
1315 
1316  if (cStart != first)
1317  d->cStart = cStart;
1318 }
1319 
1328 {
1329  ensureData();
1330  detach();
1331 
1332  for (const QRect &rect : region)
1333  addRect(rect);
1334 }
1335 
1336 
1343 {
1344  return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
1345 }
1346 
1365 {
1366  ensureData();
1367  if (d_func()->fillRule == fillRule)
1368  return;
1369  detach();
1370 
1371  d_func()->fillRule = fillRule;
1372 }
1373 
1374 #define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1375  + 3*bezier.coord##2 \
1376  - 3*bezier.coord##3 \
1377  +bezier.coord##4)
1378 
1379 #define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1380  - 2*bezier.coord##2 \
1381  + bezier.coord##3)
1382 
1383 #define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1384  + bezier.coord##2)
1385 
1386 #define QT_BEZIER_CHECK_T(bezier, t) \
1387  if (t >= 0 && t <= 1) { \
1388  QPointF p(b.pointAt(t)); \
1389  if (p.x() < minx) minx = p.x(); \
1390  else if (p.x() > maxx) maxx = p.x(); \
1391  if (p.y() < miny) miny = p.y(); \
1392  else if (p.y() > maxy) maxy = p.y(); \
1393  }
1394 
1395 
1396 static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1397 {
1398  qreal minx, miny, maxx, maxy;
1399 
1400  // initialize with end points
1401  if (b.x1 < b.x4) {
1402  minx = b.x1;
1403  maxx = b.x4;
1404  } else {
1405  minx = b.x4;
1406  maxx = b.x1;
1407  }
1408  if (b.y1 < b.y4) {
1409  miny = b.y1;
1410  maxy = b.y4;
1411  } else {
1412  miny = b.y4;
1413  maxy = b.y1;
1414  }
1415 
1416  // Update for the X extrema
1417  {
1418  qreal ax = QT_BEZIER_A(b, x);
1419  qreal bx = QT_BEZIER_B(b, x);
1420  qreal cx = QT_BEZIER_C(b, x);
1421  // specialcase quadratic curves to avoid div by zero
1422  if (qFuzzyIsNull(ax)) {
1423 
1424  // linear curves are covered by initialization.
1425  if (!qFuzzyIsNull(bx)) {
1426  qreal t = -cx / bx;
1427  QT_BEZIER_CHECK_T(b, t);
1428  }
1429 
1430  } else {
1431  const qreal tx = bx * bx - 4 * ax * cx;
1432 
1433  if (tx >= 0) {
1434  qreal temp = qSqrt(tx);
1435  qreal rcp = 1 / (2 * ax);
1436  qreal t1 = (-bx + temp) * rcp;
1438 
1439  qreal t2 = (-bx - temp) * rcp;
1441  }
1442  }
1443  }
1444 
1445  // Update for the Y extrema
1446  {
1447  qreal ay = QT_BEZIER_A(b, y);
1448  qreal by = QT_BEZIER_B(b, y);
1449  qreal cy = QT_BEZIER_C(b, y);
1450 
1451  // specialcase quadratic curves to avoid div by zero
1452  if (qFuzzyIsNull(ay)) {
1453 
1454  // linear curves are covered by initialization.
1455  if (!qFuzzyIsNull(by)) {
1456  qreal t = -cy / by;
1457  QT_BEZIER_CHECK_T(b, t);
1458  }
1459 
1460  } else {
1461  const qreal ty = by * by - 4 * ay * cy;
1462 
1463  if (ty > 0) {
1464  qreal temp = qSqrt(ty);
1465  qreal rcp = 1 / (2 * ay);
1466  qreal t1 = (-by + temp) * rcp;
1468 
1469  qreal t2 = (-by - temp) * rcp;
1471  }
1472  }
1473  }
1474  return QRectF(minx, miny, maxx - minx, maxy - miny);
1475 }
1476 
1484 {
1485  if (!d_ptr)
1486  return QRectF();
1487  QPainterPathPrivate *d = d_func();
1488 
1489  if (d->dirtyBounds)
1490  computeBoundingRect();
1491  return d->bounds;
1492 }
1493 
1505 {
1506  if (!d_ptr)
1507  return QRectF();
1508  QPainterPathPrivate *d = d_func();
1509 
1510  if (d->dirtyControlBounds)
1511  computeControlPointRect();
1512  return d->controlBounds;
1513 }
1514 
1515 
1526 {
1527  return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
1528 }
1529 
1539 {
1540  Q_D(const QPainterPath);
1541  QPainterPath rev;
1542 
1543  if (isEmpty()) {
1544  rev = *this;
1545  return rev;
1546  }
1547 
1548  rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1549 
1550  for (int i=d->elements.size()-1; i>=1; --i) {
1551  const QPainterPath::Element &elm = d->elements.at(i);
1552  const QPainterPath::Element &prev = d->elements.at(i-1);
1553  switch (elm.type) {
1554  case LineToElement:
1555  rev.lineTo(prev.x, prev.y);
1556  break;
1557  case MoveToElement:
1558  rev.moveTo(prev.x, prev.y);
1559  break;
1560  case CurveToDataElement:
1561  {
1562  Q_ASSERT(i>=3);
1563  const QPainterPath::Element &cp1 = d->elements.at(i-2);
1564  const QPainterPath::Element &sp = d->elements.at(i-3);
1565  Q_ASSERT(prev.type == CurveToDataElement);
1566  Q_ASSERT(cp1.type == CurveToElement);
1567  rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1568  i -= 2;
1569  break;
1570  }
1571  default:
1572  Q_ASSERT(!"qt_reversed_path");
1573  break;
1574  }
1575  }
1576  //qt_debug_path(rev);
1577  return rev;
1578 }
1579 
1593 {
1594 
1595  Q_D(const QPainterPath);
1596  QList<QPolygonF> flatCurves;
1597  if (isEmpty())
1598  return flatCurves;
1599 
1600  QPolygonF current;
1601  for (int i=0; i<elementCount(); ++i) {
1602  const QPainterPath::Element &e = d->elements.at(i);
1603  switch (e.type) {
1605  if (current.size() > 1)
1606  flatCurves += current;
1607  current.clear();
1608  current.reserve(16);
1609  current += QPointF(e.x, e.y) * matrix;
1610  break;
1612  current += QPointF(e.x, e.y) * matrix;
1613  break;
1615  Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1616  Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1617  QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1618  QPointF(e.x, e.y) * matrix,
1619  QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1620  QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1621  bezier.addToPolygon(&current);
1622  i+=2;
1623  break;
1624  }
1626  Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1627  break;
1628  }
1629  }
1630 
1631  if (current.size()>1)
1632  flatCurves += current;
1633 
1634  return flatCurves;
1635 }
1636 
1660 {
1661 
1662  QList<QPolygonF> polys;
1663 
1665  int count = subpaths.size();
1666 
1667  if (count == 0)
1668  return polys;
1669 
1670  QList<QRectF> bounds;
1671  bounds.reserve(count);
1672  for (int i=0; i<count; ++i)
1673  bounds += subpaths.at(i).boundingRect();
1674 
1675 #ifdef QPP_FILLPOLYGONS_DEBUG
1676  printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1677  for (int i=0; i<bounds.size(); ++i)
1678  qDebug() << " bounds" << i << bounds.at(i);
1679 #endif
1680 
1681  QList< QList<int> > isects;
1682  isects.resize(count);
1683 
1684  // find all intersections
1685  for (int j=0; j<count; ++j) {
1686  if (subpaths.at(j).size() <= 2)
1687  continue;
1688  QRectF cbounds = bounds.at(j);
1689  for (int i=0; i<count; ++i) {
1690  if (cbounds.intersects(bounds.at(i))) {
1691  isects[j] << i;
1692  }
1693  }
1694  }
1695 
1696 #ifdef QPP_FILLPOLYGONS_DEBUG
1697  printf("Intersections before flattening:\n");
1698  for (int i = 0; i < count; ++i) {
1699  printf("%d: ", i);
1700  for (int j = 0; j < isects[i].size(); ++j) {
1701  printf("%d ", isects[i][j]);
1702  }
1703  printf("\n");
1704  }
1705 #endif
1706 
1707  // flatten the sets of intersections
1708  for (int i=0; i<count; ++i) {
1709  const QList<int> &current_isects = isects.at(i);
1710  for (int j=0; j<current_isects.size(); ++j) {
1711  int isect_j = current_isects.at(j);
1712  if (isect_j == i)
1713  continue;
1714  const QList<int> &isects_j = isects.at(isect_j);
1715  for (int k = 0, size = isects_j.size(); k < size; ++k) {
1716  int isect_k = isects_j.at(k);
1717  if (isect_k != i && !isects.at(i).contains(isect_k)) {
1718  isects[i] += isect_k;
1719  }
1720  }
1721  isects[isect_j].clear();
1722  }
1723  }
1724 
1725 #ifdef QPP_FILLPOLYGONS_DEBUG
1726  printf("Intersections after flattening:\n");
1727  for (int i = 0; i < count; ++i) {
1728  printf("%d: ", i);
1729  for (int j = 0; j < isects[i].size(); ++j) {
1730  printf("%d ", isects[i][j]);
1731  }
1732  printf("\n");
1733  }
1734 #endif
1735 
1736  // Join the intersected subpaths as rewinded polygons
1737  for (int i=0; i<count; ++i) {
1738  const QList<int> &subpath_list = isects.at(i);
1739  if (!subpath_list.isEmpty()) {
1740  QPolygonF buildUp;
1741  for (int j=0; j<subpath_list.size(); ++j) {
1742  const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1743  buildUp += subpath;
1744  if (!subpath.isClosed())
1745  buildUp += subpath.first();
1746  if (!buildUp.isClosed())
1747  buildUp += buildUp.constFirst();
1748  }
1749  polys += buildUp;
1750  }
1751  }
1752 
1753  return polys;
1754 }
1755 
1756 //same as qt_polygon_isect_line in qpolygon.cpp
1757 static void qt_painterpath_isect_line(const QPointF &p1,
1758  const QPointF &p2,
1759  const QPointF &pos,
1760  int *winding)
1761 {
1762  qreal x1 = p1.x();
1763  qreal y1 = p1.y();
1764  qreal x2 = p2.x();
1765  qreal y2 = p2.y();
1766  qreal y = pos.y();
1767 
1768  int dir = 1;
1769 
1770  if (qFuzzyCompare(y1, y2)) {
1771  // ignore horizontal lines according to scan conversion rule
1772  return;
1773  } else if (y2 < y1) {
1774  qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1775  qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1776  dir = -1;
1777  }
1778 
1779  if (y >= y1 && y < y2) {
1780  qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1781 
1782  // count up the winding number if we're
1783  if (x<=pos.x()) {
1784  (*winding) += dir;
1785  }
1786  }
1787 }
1788 
1789 static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1790  int *winding, int depth = 0)
1791 {
1792  qreal y = pt.y();
1793  qreal x = pt.x();
1794  QRectF bounds = bezier.bounds();
1795 
1796  // potential intersection, divide and try again...
1797  // Please note that a sideeffect of the bottom exclusion is that
1798  // horizontal lines are dropped, but this is correct according to
1799  // scan conversion rules.
1800  if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1801 
1802  // hit lower limit... This is a rough threshold, but its a
1803  // tradeoff between speed and precision.
1804  const qreal lower_bound = qreal(.001);
1805  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1806  // We make the assumption here that the curve starts to
1807  // approximate a line after while (i.e. that it doesn't
1808  // change direction drastically during its slope)
1809  if (bezier.pt1().x() <= x) {
1810  (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1811  }
1812  return;
1813  }
1814 
1815  // split curve and try again...
1816  const auto halves = bezier.split();
1817  qt_painterpath_isect_curve(halves.first, pt, winding, depth + 1);
1818  qt_painterpath_isect_curve(halves.second, pt, winding, depth + 1);
1819  }
1820 }
1821 
1830 bool QPainterPath::contains(const QPointF &pt) const
1831 {
1832  if (isEmpty() || !controlPointRect().contains(pt))
1833  return false;
1834 
1835  QPainterPathPrivate *d = d_func();
1836 
1837  int winding_number = 0;
1838 
1839  QPointF last_pt;
1840  QPointF last_start;
1841  for (int i=0; i<d->elements.size(); ++i) {
1842  const Element &e = d->elements.at(i);
1843 
1844  switch (e.type) {
1845 
1846  case MoveToElement:
1847  if (i > 0) // implicitly close all paths.
1848  qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1849  last_start = last_pt = e;
1850  break;
1851 
1852  case LineToElement:
1853  qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1854  last_pt = e;
1855  break;
1856 
1857  case CurveToElement:
1858  {
1859  const QPainterPath::Element &cp2 = d->elements.at(++i);
1860  const QPainterPath::Element &ep = d->elements.at(++i);
1861  qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1862  pt, &winding_number);
1863  last_pt = ep;
1864 
1865  }
1866  break;
1867 
1868  default:
1869  break;
1870  }
1871  }
1872 
1873  // implicitly close last subpath
1874  if (last_pt != last_start)
1875  qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1876 
1877  return (d->fillRule == Qt::WindingFill
1878  ? (winding_number != 0)
1879  : ((winding_number % 2) != 0));
1880 }
1881 
1883 
1884 static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1885  const QRectF &rect)
1886 {
1887  qreal left = rect.left();
1888  qreal right = rect.right();
1889  qreal top = rect.top();
1890  qreal bottom = rect.bottom();
1891 
1892  // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1893  int p1 = ((x1 < left) << Left)
1894  | ((x1 > right) << Right)
1895  | ((y1 < top) << Top)
1896  | ((y1 > bottom) << Bottom);
1897  int p2 = ((x2 < left) << Left)
1898  | ((x2 > right) << Right)
1899  | ((y2 < top) << Top)
1900  | ((y2 > bottom) << Bottom);
1901 
1902  if (p1 & p2)
1903  // completely inside
1904  return false;
1905 
1906  if (p1 | p2) {
1907  qreal dx = x2 - x1;
1908  qreal dy = y2 - y1;
1909 
1910  // clip x coordinates
1911  if (x1 < left) {
1912  y1 += dy/dx * (left - x1);
1913  x1 = left;
1914  } else if (x1 > right) {
1915  y1 -= dy/dx * (x1 - right);
1916  x1 = right;
1917  }
1918  if (x2 < left) {
1919  y2 += dy/dx * (left - x2);
1920  x2 = left;
1921  } else if (x2 > right) {
1922  y2 -= dy/dx * (x2 - right);
1923  x2 = right;
1924  }
1925 
1926  p1 = ((y1 < top) << Top)
1927  | ((y1 > bottom) << Bottom);
1928  p2 = ((y2 < top) << Top)
1929  | ((y2 > bottom) << Bottom);
1930 
1931  if (p1 & p2)
1932  return false;
1933 
1934  // clip y coordinates
1935  if (y1 < top) {
1936  x1 += dx/dy * (top - y1);
1937  y1 = top;
1938  } else if (y1 > bottom) {
1939  x1 -= dx/dy * (y1 - bottom);
1940  y1 = bottom;
1941  }
1942  if (y2 < top) {
1943  x2 += dx/dy * (top - y2);
1944  y2 = top;
1945  } else if (y2 > bottom) {
1946  x2 -= dx/dy * (y2 - bottom);
1947  y2 = bottom;
1948  }
1949 
1950  p1 = ((x1 < left) << Left)
1951  | ((x1 > right) << Right);
1952  p2 = ((x2 < left) << Left)
1953  | ((x2 > right) << Right);
1954 
1955  if (p1 & p2)
1956  return false;
1957 
1958  return true;
1959  }
1960  return false;
1961 }
1962 
1963 static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
1964 {
1965  QRectF bounds = bezier.bounds();
1966 
1967  if (y >= bounds.top() && y < bounds.bottom()
1968  && bounds.right() >= x1 && bounds.left() < x2) {
1969  const qreal lower_bound = qreal(.01);
1970  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1971  return true;
1972 
1973  const auto halves = bezier.split();
1974  if (qt_isect_curve_horizontal(halves.first, y, x1, x2, depth + 1)
1975  || qt_isect_curve_horizontal(halves.second, y, x1, x2, depth + 1))
1976  return true;
1977  }
1978  return false;
1979 }
1980 
1981 static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
1982 {
1983  QRectF bounds = bezier.bounds();
1984 
1985  if (x >= bounds.left() && x < bounds.right()
1986  && bounds.bottom() >= y1 && bounds.top() < y2) {
1987  const qreal lower_bound = qreal(.01);
1988  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1989  return true;
1990 
1991  const auto halves = bezier.split();
1992  if (qt_isect_curve_vertical(halves.first, x, y1, y2, depth + 1)
1993  || qt_isect_curve_vertical(halves.second, x, y1, y2, depth + 1))
1994  return true;
1995  }
1996  return false;
1997 }
1998 
1999 static bool pointOnEdge(const QRectF &rect, const QPointF &point)
2000 {
2001  if ((point.x() == rect.left() || point.x() == rect.right()) &&
2002  (point.y() >= rect.top() && point.y() <= rect.bottom()))
2003  return true;
2004  if ((point.y() == rect.top() || point.y() == rect.bottom()) &&
2005  (point.x() >= rect.left() && point.x() <= rect.right()))
2006  return true;
2007  return false;
2008 }
2009 
2010 /*
2011  Returns \c true if any lines or curves cross the four edges in of rect
2012 */
2013 static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
2014 {
2015  QPointF last_pt;
2016  QPointF last_start;
2017  enum { OnRect, InsideRect, OutsideRect} edgeStatus = OnRect;
2018  for (int i=0; i<path->elementCount(); ++i) {
2019  const QPainterPath::Element &e = path->elementAt(i);
2020 
2021  switch (e.type) {
2022 
2024  if (i > 0
2025  && qFuzzyCompare(last_pt.x(), last_start.x())
2026  && qFuzzyCompare(last_pt.y(), last_start.y())
2027  && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2028  last_start.x(), last_start.y(), rect))
2029  return true;
2030  last_start = last_pt = e;
2031  break;
2032 
2034  if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2035  return true;
2036  last_pt = e;
2037  break;
2038 
2040  {
2041  QPointF cp2 = path->elementAt(++i);
2042  QPointF ep = path->elementAt(++i);
2043  QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2044  if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2045  || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2046  || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2047  || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2048  return true;
2049  last_pt = ep;
2050  }
2051  break;
2052 
2053  default:
2054  break;
2055  }
2056  // Handle crossing the edges of the rect at the end-points of individual sub-paths.
2057  // A point on on the edge itself is considered neither inside nor outside for this purpose.
2058  if (!pointOnEdge(rect, last_pt)) {
2059  bool contained = rect.contains(last_pt);
2060  switch (edgeStatus) {
2061  case OutsideRect:
2062  if (contained)
2063  return true;
2064  break;
2065  case InsideRect:
2066  if (!contained)
2067  return true;
2068  break;
2069  case OnRect:
2070  edgeStatus = contained ? InsideRect : OutsideRect;
2071  break;
2072  }
2073  } else {
2074  if (last_pt == last_start)
2075  edgeStatus = OnRect;
2076  }
2077  }
2078 
2079  // implicitly close last subpath
2080  if (last_pt != last_start
2081  && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2082  last_start.x(), last_start.y(), rect))
2083  return true;
2084 
2085  return false;
2086 }
2087 
2103 {
2104  if (elementCount() == 1 && rect.contains(elementAt(0)))
2105  return true;
2106 
2107  if (isEmpty())
2108  return false;
2109 
2110  QRectF cp = controlPointRect();
2111  QRectF rn = rect.normalized();
2112 
2113  // QRectF::intersects returns false if one of the rects is a null rect
2114  // which would happen for a painter path consisting of a vertical or
2115  // horizontal line
2116  if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2117  || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2118  return false;
2119 
2120  // If any path element cross the rect its bound to be an intersection
2121  if (qt_painterpath_check_crossing(this, rect))
2122  return true;
2123 
2124  if (contains(rect.center()))
2125  return true;
2126 
2127  Q_D(QPainterPath);
2128 
2129  // Check if the rectangle surrounds any subpath...
2130  for (int i=0; i<d->elements.size(); ++i) {
2131  const Element &e = d->elements.at(i);
2132  if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2133  return true;
2134  }
2135 
2136  return false;
2137 }
2138 
2146 {
2147  if (!d_ptr || (dx == 0 && dy == 0))
2148  return;
2149 
2150  int elementsLeft = d_ptr->elements.size();
2151  if (elementsLeft <= 0)
2152  return;
2153 
2154  detach();
2155  QPainterPath::Element *element = d_func()->elements.data();
2156  Q_ASSERT(element);
2157  while (elementsLeft--) {
2158  element->x += dx;
2159  element->y += dy;
2160  ++element;
2161  }
2162 }
2163 
2181 {
2182  QPainterPath copy(*this);
2183  copy.translate(dx, dy);
2184  return copy;
2185 }
2186 
2204 {
2205  Q_D(QPainterPath);
2206 
2207  // the path is empty or the control point rect doesn't completely
2208  // cover the rectangle we abort stratight away.
2209  if (isEmpty() || !controlPointRect().contains(rect))
2210  return false;
2211 
2212  // if there are intersections, chances are that the rect is not
2213  // contained, except if we have winding rule, in which case it
2214  // still might.
2215  if (qt_painterpath_check_crossing(this, rect)) {
2216  if (fillRule() == Qt::OddEvenFill) {
2217  return false;
2218  } else {
2219  // Do some wague sampling in the winding case. This is not
2220  // precise but it should mostly be good enough.
2221  if (!contains(rect.topLeft()) ||
2222  !contains(rect.topRight()) ||
2223  !contains(rect.bottomRight()) ||
2224  !contains(rect.bottomLeft()))
2225  return false;
2226  }
2227  }
2228 
2229  // If there exists a point inside that is not part of the path its
2230  // because: rectangle lies completely outside path or a subpath
2231  // excludes parts of the rectangle. Both cases mean that the rect
2232  // is not contained
2233  if (!contains(rect.center()))
2234  return false;
2235 
2236  // If there are any subpaths inside this rectangle we need to
2237  // check if they are still contained as a result of the fill
2238  // rule. This can only be the case for WindingFill though. For
2239  // OddEvenFill the rect will never be contained if it surrounds a
2240  // subpath. (the case where two subpaths are completely identical
2241  // can be argued but we choose to neglect it).
2242  for (int i=0; i<d->elements.size(); ++i) {
2243  const Element &e = d->elements.at(i);
2244  if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2245  if (fillRule() == Qt::OddEvenFill)
2246  return false;
2247 
2248  bool stop = false;
2249  for (; !stop && i<d->elements.size(); ++i) {
2250  const Element &el = d->elements.at(i);
2251  switch (el.type) {
2252  case MoveToElement:
2253  stop = true;
2254  break;
2255  case LineToElement:
2256  if (!contains(el))
2257  return false;
2258  break;
2259  case CurveToElement:
2260  if (!contains(d->elements.at(i+2)))
2261  return false;
2262  i += 2;
2263  break;
2264  default:
2265  break;
2266  }
2267  }
2268 
2269  // compensate for the last ++i in the inner for
2270  --i;
2271  }
2272  }
2273 
2274  return true;
2275 }
2276 
2277 static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2278 {
2279  return qAbs(a.x() - b.x()) <= epsilon.width()
2280  && qAbs(a.y() - b.y()) <= epsilon.height();
2281 }
2282 
2293 {
2294  QPainterPathPrivate *d = d_func();
2295  QPainterPathPrivate *other_d = path.d_func();
2296  if (other_d == d) {
2297  return true;
2298  } else if (!d || !other_d) {
2299  if (!other_d && isEmpty() && elementAt(0) == QPointF() && d->fillRule == Qt::OddEvenFill)
2300  return true;
2301  if (!d && path.isEmpty() && path.elementAt(0) == QPointF() && other_d->fillRule == Qt::OddEvenFill)
2302  return true;
2303  return false;
2304  }
2305  else if (d->fillRule != other_d->fillRule)
2306  return false;
2307  else if (d->elements.size() != other_d->elements.size())
2308  return false;
2309 
2310  const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2311 
2313  epsilon.rwidth() *= qt_epsilon;
2314  epsilon.rheight() *= qt_epsilon;
2315 
2316  for (int i = 0; i < d->elements.size(); ++i)
2317  if (d->elements.at(i).type != other_d->elements.at(i).type
2318  || !epsilonCompare(d->elements.at(i), other_d->elements.at(i), epsilon))
2319  return false;
2320 
2321  return true;
2322 }
2323 
2334 {
2335  return !(*this==path);
2336 }
2337 
2346 {
2347  return intersected(other);
2348 }
2349 
2358 {
2359  return united(other);
2360 }
2361 
2371 {
2372  return united(other);
2373 }
2374 
2383 {
2384  return subtracted(other);
2385 }
2386 
2395 {
2396  return *this = (*this & other);
2397 }
2398 
2407 {
2408  return *this = (*this | other);
2409 }
2410 
2420 {
2421  return *this = (*this + other);
2422 }
2423 
2433 {
2434  return *this = (*this - other);
2435 }
2436 
2437 #ifndef QT_NO_DATASTREAM
2448 {
2449  if (p.isEmpty()) {
2450  s << 0;
2451  return s;
2452  }
2453 
2454  s << p.elementCount();
2455  for (int i=0; i < p.d_func()->elements.size(); ++i) {
2456  const QPainterPath::Element &e = p.d_func()->elements.at(i);
2457  s << int(e.type);
2458  s << double(e.x) << double(e.y);
2459  }
2460  s << p.d_func()->cStart;
2461  s << int(p.d_func()->fillRule);
2462  return s;
2463 }
2464 
2475 {
2476  bool errorDetected = false;
2477  int size;
2478  s >> size;
2479 
2480  if (size == 0)
2481  return s;
2482 
2483  p.ensureData(); // in case if p.d_func() == 0
2484  if (p.d_func()->elements.size() == 1) {
2485  Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2486  p.d_func()->elements.clear();
2487  }
2488  for (int i=0; i<size; ++i) {
2489  int type;
2490  double x, y;
2491  s >> type;
2492  s >> x;
2493  s >> y;
2494  Q_ASSERT(type >= 0 && type <= 3);
2495  if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) {
2496 #ifndef QT_NO_DEBUG
2497  qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it");
2498 #endif
2499  errorDetected = true;
2500  continue;
2501  }
2503  p.d_func()->elements.append(elm);
2504  }
2505  s >> p.d_func()->cStart;
2506  int fillRule;
2507  s >> fillRule;
2508  Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
2509  p.d_func()->fillRule = Qt::FillRule(fillRule);
2510  p.d_func()->dirtyBounds = true;
2511  p.d_func()->dirtyControlBounds = true;
2512  if (errorDetected)
2513  p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
2514  return s;
2515 }
2516 #endif // QT_NO_DATASTREAM
2517 
2518 
2519 /*******************************************************************************
2520  * class QPainterPathStroker
2521  */
2522 
2524 {
2526 }
2527 
2529 {
2531 }
2532 
2534  qfixed c2x, qfixed c2y,
2535  qfixed ex, qfixed ey,
2536  void *data)
2537 {
2538  ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2541 }
2542 
2595  : dashOffset(0)
2596 {
2600 }
2601 
2606  : d_ptr(new QPainterPathStrokerPrivate)
2607 {
2608 }
2609 
2616  : d_ptr(new QPainterPathStrokerPrivate)
2617 {
2618  setWidth(pen.widthF());
2619  setCapStyle(pen.capStyle());
2620  setJoinStyle(pen.joinStyle());
2621  setMiterLimit(pen.miterLimit());
2622  setDashOffset(pen.dashOffset());
2623 
2624  if (pen.style() == Qt::CustomDashLine)
2625  setDashPattern(pen.dashPattern());
2626  else
2627  setDashPattern(pen.style());
2628 }
2629 
2634 {
2635 }
2636 
2637 
2652 {
2653  QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2654  QPainterPath stroke;
2655  if (path.isEmpty())
2656  return path;
2657  if (d->dashPattern.isEmpty()) {
2658  d->stroker.strokePath(path, &stroke, QTransform());
2659  } else {
2660  QDashStroker dashStroker(&d->stroker);
2661  dashStroker.setDashPattern(d->dashPattern);
2662  dashStroker.setDashOffset(d->dashOffset);
2663  dashStroker.setClipRect(d->stroker.clipRect());
2664  dashStroker.strokePath(path, &stroke, QTransform());
2665  }
2666  stroke.setFillRule(Qt::WindingFill);
2667  return stroke;
2668 }
2669 
2677 {
2678  Q_D(QPainterPathStroker);
2679  if (width <= 0)
2680  width = 1;
2681  d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2682 }
2683 
2688 {
2689  return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2690 }
2691 
2692 
2699 {
2700  d_func()->stroker.setCapStyle(style);
2701 }
2702 
2703 
2708 {
2709  return d_func()->stroker.capStyle();
2710 }
2711 
2716 {
2717  d_func()->stroker.setJoinStyle(style);
2718 }
2719 
2724 {
2725  return d_func()->stroker.joinStyle();
2726 }
2727 
2739 {
2740  d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2741 }
2742 
2747 {
2748  return qt_fixed_to_real(d_func()->stroker.miterLimit());
2749 }
2750 
2751 
2761 {
2762  d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2763 }
2764 
2770 {
2771  return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2772 }
2773 
2778 {
2779  d_func()->dashPattern = QDashStroker::patternForStyle(style);
2780 }
2781 
2799 {
2800  d_func()->dashPattern.clear();
2801  for (int i=0; i<dashPattern.size(); ++i)
2802  d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2803 }
2804 
2809 {
2810  return d_func()->dashPattern;
2811 }
2812 
2817 {
2818  return d_func()->dashOffset;
2819 }
2820 
2828 {
2829  d_func()->dashOffset = offset;
2830 }
2831 
2848 {
2849  const QList<QPolygonF> flats = toSubpathPolygons(matrix);
2851  if (flats.isEmpty())
2852  return polygon;
2853  QPointF first = flats.first().first();
2854  for (int i=0; i<flats.size(); ++i) {
2855  polygon += flats.at(i);
2856  if (!flats.at(i).isClosed())
2857  polygon += flats.at(i).first();
2858  if (i > 0)
2859  polygon += first;
2860  }
2861  return polygon;
2862 }
2863 
2864 //derivative of the equation
2865 static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2866 {
2867  return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2868 }
2869 
2874 {
2875  Q_D(QPainterPath);
2876  if (isEmpty())
2877  return 0;
2878 
2879  qreal len = 0;
2880  for (int i=1; i<d->elements.size(); ++i) {
2881  const Element &e = d->elements.at(i);
2882 
2883  switch (e.type) {
2884  case MoveToElement:
2885  break;
2886  case LineToElement:
2887  {
2888  len += QLineF(d->elements.at(i-1), e).length();
2889  break;
2890  }
2891  case CurveToElement:
2892  {
2893  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2894  e,
2895  d->elements.at(i+1),
2896  d->elements.at(i+2));
2897  len += b.length();
2898  i += 2;
2899  break;
2900  }
2901  default:
2902  break;
2903  }
2904  }
2905  return len;
2906 }
2907 
2917 {
2918  Q_D(QPainterPath);
2919  if (isEmpty() || len <= 0)
2920  return 0;
2921 
2922  qreal totalLength = length();
2923  if (len > totalLength)
2924  return 1;
2925 
2926  qreal curLen = 0;
2927  for (int i=1; i<d->elements.size(); ++i) {
2928  const Element &e = d->elements.at(i);
2929 
2930  switch (e.type) {
2931  case MoveToElement:
2932  break;
2933  case LineToElement:
2934  {
2935  QLineF line(d->elements.at(i-1), e);
2936  qreal llen = line.length();
2937  curLen += llen;
2938  if (curLen >= len) {
2939  return len/totalLength ;
2940  }
2941 
2942  break;
2943  }
2944  case CurveToElement:
2945  {
2946  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2947  e,
2948  d->elements.at(i+1),
2949  d->elements.at(i+2));
2950  qreal blen = b.length();
2951  qreal prevLen = curLen;
2952  curLen += blen;
2953 
2954  if (curLen >= len) {
2955  qreal res = b.tAtLength(len - prevLen);
2956  return (res * blen + prevLen)/totalLength;
2957  }
2958 
2959  i += 2;
2960  break;
2961  }
2962  default:
2963  break;
2964  }
2965  }
2966 
2967  return 0;
2968 }
2969 
2970 static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2971 {
2972  *startingLength = 0;
2973  if (t > 1)
2974  return QBezier();
2975 
2976  qreal curLen = 0;
2977  qreal totalLength = path.length();
2978 
2979  const int lastElement = path.elementCount() - 1;
2980  for (int i=0; i <= lastElement; ++i) {
2981  const QPainterPath::Element &e = path.elementAt(i);
2982 
2983  switch (e.type) {
2985  break;
2987  {
2988  QLineF line(path.elementAt(i-1), e);
2989  qreal llen = line.length();
2990  curLen += llen;
2991  if (i == lastElement || curLen/totalLength >= t) {
2992  *bezierLength = llen;
2993  QPointF a = path.elementAt(i-1);
2994  QPointF delta = e - a;
2995  return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2996  }
2997  break;
2998  }
3000  {
3001  QBezier b = QBezier::fromPoints(path.elementAt(i-1),
3002  e,
3003  path.elementAt(i+1),
3004  path.elementAt(i+2));
3005  qreal blen = b.length();
3006  curLen += blen;
3007 
3008  if (i + 2 == lastElement || curLen/totalLength >= t) {
3009  *bezierLength = blen;
3010  return b;
3011  }
3012 
3013  i += 2;
3014  break;
3015  }
3016  default:
3017  break;
3018  }
3019  *startingLength = curLen;
3020  }
3021  return QBezier();
3022 }
3023 
3034 {
3035  if (t < 0 || t > 1) {
3036  qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
3037  return QPointF();
3038  }
3039 
3040  if (!d_ptr || d_ptr->elements.size() == 0)
3041  return QPointF();
3042 
3043  if (d_ptr->elements.size() == 1)
3044  return d_ptr->elements.at(0);
3045 
3046  qreal totalLength = length();
3047  qreal curLen = 0;
3048  qreal bezierLen = 0;
3049  QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
3050  qreal realT = (totalLength * t - curLen) / bezierLen;
3051 
3052  return b.pointAt(qBound(qreal(0), realT, qreal(1)));
3053 }
3054 
3068 {
3069  if (t < 0 || t > 1) {
3070  qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
3071  return 0;
3072  }
3073 
3074  qreal totalLength = length();
3075  qreal curLen = 0;
3076  qreal bezierLen = 0;
3077  QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3078  qreal realT = (totalLength * t - curLen) / bezierLen;
3079 
3080  qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3081  qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3082 
3083  return QLineF(0, 0, m1, m2).angle();
3084 }
3085 
3086 
3097 {
3098  if (t < 0 || t > 1) {
3099  qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3100  return 0;
3101  }
3102 
3103  qreal totalLength = length();
3104  qreal curLen = 0;
3105  qreal bezierLen = 0;
3106  QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3107  qreal realT = (totalLength * t - curLen) / bezierLen;
3108 
3109  qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3110  qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3111  //tangent line
3112  qreal slope = 0;
3113 
3114  if (m1)
3115  slope = m2/m1;
3116  else {
3117  if (std::numeric_limits<qreal>::has_infinity) {
3118  slope = (m2 < 0) ? -std::numeric_limits<qreal>::infinity()
3119  : std::numeric_limits<qreal>::infinity();
3120  } else {
3121  if (sizeof(qreal) == sizeof(double)) {
3122  return 1.79769313486231570e+308;
3123  } else {
3124  return ((qreal)3.40282346638528860e+38);
3125  }
3126  }
3127  }
3128 
3129  return slope;
3130 }
3131 
3145 void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
3147 {
3148  QRectF r = rect.normalized();
3149 
3150  if (r.isNull())
3151  return;
3152 
3153  if (mode == Qt::AbsoluteSize) {
3154  qreal w = r.width() / 2;
3155  qreal h = r.height() / 2;
3156 
3157  if (w == 0) {
3158  xRadius = 0;
3159  } else {
3160  xRadius = 100 * qMin(xRadius, w) / w;
3161  }
3162  if (h == 0) {
3163  yRadius = 0;
3164  } else {
3165  yRadius = 100 * qMin(yRadius, h) / h;
3166  }
3167  } else {
3168  if (xRadius > 100) // fix ranges
3169  xRadius = 100;
3170 
3171  if (yRadius > 100)
3172  yRadius = 100;
3173  }
3174 
3175  if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3176  addRect(r);
3177  return;
3178  }
3179 
3180  qreal x = r.x();
3181  qreal y = r.y();
3182  qreal w = r.width();
3183  qreal h = r.height();
3184  qreal rxx2 = w*xRadius/100;
3185  qreal ryy2 = h*yRadius/100;
3186 
3187  ensureData();
3188  detach();
3189 
3190  bool first = d_func()->elements.size() < 2;
3191 
3192  arcMoveTo(x, y, rxx2, ryy2, 180);
3193  arcTo(x, y, rxx2, ryy2, 180, -90);
3194  arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3195  arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3196  arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3197  closeSubpath();
3198 
3199  d_func()->require_moveTo = true;
3200  d_func()->convex = first;
3201 }
3202 
3224 {
3225  if (isEmpty() || p.isEmpty())
3226  return isEmpty() ? p : *this;
3227  QPathClipper clipper(*this, p);
3228  return clipper.clip(QPathClipper::BoolOr);
3229 }
3230 
3239 {
3240  if (isEmpty() || p.isEmpty())
3241  return QPainterPath();
3242  QPathClipper clipper(*this, p);
3243  return clipper.clip(QPathClipper::BoolAnd);
3244 }
3245 
3257 {
3258  if (isEmpty() || p.isEmpty())
3259  return *this;
3260  QPathClipper clipper(*this, p);
3261  return clipper.clip(QPathClipper::BoolSub);
3262 }
3263 
3274 {
3275  if (isEmpty())
3276  return *this;
3277  QPathClipper clipper(*this, QPainterPath());
3278  return clipper.clip(QPathClipper::Simplify);
3279 }
3280 
3293 {
3294  if (p.elementCount() == 1)
3295  return contains(p.elementAt(0));
3296  if (isEmpty() || p.isEmpty())
3297  return false;
3298  QPathClipper clipper(*this, p);
3299  return clipper.intersect();
3300 }
3301 
3315 {
3316  if (p.elementCount() == 1)
3317  return contains(p.elementAt(0));
3318  if (isEmpty() || p.isEmpty())
3319  return false;
3320  QPathClipper clipper(*this, p);
3321  return clipper.contains();
3322 }
3323 
3324 void QPainterPath::setDirty(bool dirty)
3325 {
3326  d_func()->dirtyBounds = dirty;
3327  d_func()->dirtyControlBounds = dirty;
3328  d_func()->pathConverter.reset();
3329  d_func()->convex = false;
3330 }
3331 
3332 void QPainterPath::computeBoundingRect() const
3333 {
3334  QPainterPathPrivate *d = d_func();
3335  d->dirtyBounds = false;
3336  if (!d_ptr) {
3337  d->bounds = QRect();
3338  return;
3339  }
3340 
3341  qreal minx, maxx, miny, maxy;
3342  minx = maxx = d->elements.at(0).x;
3343  miny = maxy = d->elements.at(0).y;
3344  for (int i=1; i<d->elements.size(); ++i) {
3345  const Element &e = d->elements.at(i);
3346 
3347  switch (e.type) {
3348  case MoveToElement:
3349  case LineToElement:
3350  if (e.x > maxx) maxx = e.x;
3351  else if (e.x < minx) minx = e.x;
3352  if (e.y > maxy) maxy = e.y;
3353  else if (e.y < miny) miny = e.y;
3354  break;
3355  case CurveToElement:
3356  {
3357  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3358  e,
3359  d->elements.at(i+1),
3360  d->elements.at(i+2));
3361  QRectF r = qt_painterpath_bezier_extrema(b);
3362  qreal right = r.right();
3363  qreal bottom = r.bottom();
3364  if (r.x() < minx) minx = r.x();
3365  if (right > maxx) maxx = right;
3366  if (r.y() < miny) miny = r.y();
3367  if (bottom > maxy) maxy = bottom;
3368  i += 2;
3369  }
3370  break;
3371  default:
3372  break;
3373  }
3374  }
3375  d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3376 }
3377 
3378 
3379 void QPainterPath::computeControlPointRect() const
3380 {
3381  QPainterPathPrivate *d = d_func();
3382  d->dirtyControlBounds = false;
3383  if (!d_ptr) {
3384  d->controlBounds = QRect();
3385  return;
3386  }
3387 
3388  qreal minx, maxx, miny, maxy;
3389  minx = maxx = d->elements.at(0).x;
3390  miny = maxy = d->elements.at(0).y;
3391  for (int i=1; i<d->elements.size(); ++i) {
3392  const Element &e = d->elements.at(i);
3393  if (e.x > maxx) maxx = e.x;
3394  else if (e.x < minx) minx = e.x;
3395  if (e.y > maxy) maxy = e.y;
3396  else if (e.y < miny) miny = e.y;
3397  }
3398  d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3399 }
3400 
3401 #ifndef QT_NO_DEBUG_STREAM
3403 {
3404  s.nospace() << "QPainterPath: Element count=" << p.elementCount() << Qt::endl;
3405  const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3406  for (int i=0; i<p.elementCount(); ++i) {
3407  s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << Qt::endl;
3408 
3409  }
3410  return s;
3411 }
3412 #endif
3413 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
QPointF pt1() const
Definition: qbezier_p.h:95
qreal x4
Definition: qbezier_p.h:117
QRectF bounds() const
Definition: qbezier.cpp:173
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition: qbezier_p.h:70
std::pair< QBezier, QBezier > split() const
Definition: qbezier_p.h:225
qreal y1
Definition: qbezier_p.h:117
qreal y4
Definition: qbezier_p.h:117
static void coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal &d)
Definition: qbezier_p.h:153
qreal x1
Definition: qbezier_p.h:117
QPointF pt4() const
Definition: qbezier_p.h:98
qreal x3
Definition: qbezier_p.h:117
qreal y3
Definition: qbezier_p.h:117
qreal x2
Definition: qbezier_p.h:117
void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold=0.5) const
Definition: qbezier.cpp:101
qreal y2
Definition: qbezier_p.h:117
void setDashPattern(const QList< qfixed > &dashPattern)
Definition: qstroker_p.h:273
void setDashOffset(qreal offset)
Definition: qstroker_p.h:276
static QList< qfixed > patternForStyle(Qt::PenStyle style)
Definition: qstroker.cpp:1031
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
void reset(T *ptr=nullptr) noexcept
Definition: qshareddata.h:197
virtual QFixed ascent() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual QFixed lineThickness() const
virtual QFixed underlinePosition() const
The QFont class specifies a query for a font used for drawing text.
Definition: qfont.h:56
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:215
qreal angle() const
Definition: qline.cpp:585
qreal length() const
Definition: qline.cpp:569
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
const T & constFirst() const noexcept
Definition: qlist.h:645
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
void reserve(qsizetype size)
Definition: qlist.h:757
pointer data()
Definition: qlist.h:442
void resize(qsizetype size)
Definition: qlist.h:420
T & first()
Definition: qlist.h:643
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
bool qFuzzyCompare(const QMatrix4x4 &m1, const QMatrix4x4 &m2)
Definition: qmatrix4x4.cpp:774
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:74
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
void quadTo(const QPointF &ctrlPt, const QPointF &endPt)
int capacity() const
QPainterPath operator-(const QPainterPath &other) const
QPainterPath translated(qreal dx, qreal dy) const
void translate(qreal dx, qreal dy)
void addRect(const QRectF &rect)
QList< QPolygonF > toSubpathPolygons(const QTransform &matrix=QTransform()) const
void moveTo(const QPointF &p)
void addEllipse(const QRectF &rect)
qreal angleAtPercent(qreal t) const
void setFillRule(Qt::FillRule fillRule)
void setElementPositionAt(int i, qreal x, qreal y)
QPainterPath subtracted(const QPainterPath &r) const
QPainterPath & operator=(const QPainterPath &other)
QPainterPath operator+(const QPainterPath &other) const
QPainterPath::Element elementAt(int i) const
QPainterPath() noexcept
void connectPath(const QPainterPath &path)
int elementCount() const
void addPolygon(const QPolygonF &polygon)
QPainterPath & operator&=(const QPainterPath &other)
QPainterPath simplified() const
void addPath(const QPainterPath &path)
QPolygonF toFillPolygon(const QTransform &matrix=QTransform()) const
QRectF controlPointRect() const
QPainterPath & operator|=(const QPainterPath &other)
bool intersects(const QRectF &rect) const
QList< QPolygonF > toFillPolygons(const QTransform &matrix=QTransform()) const
QRectF boundingRect() const
bool contains(const QPointF &pt) const
bool operator!=(const QPainterPath &other) const
Qt::FillRule fillRule() const
bool isEmpty() const
QPointF pointAtPercent(qreal t) const
QPainterPath united(const QPainterPath &r) const
void addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
void reserve(int size)
QPainterPath & operator-=(const QPainterPath &other)
void arcTo(const QRectF &rect, qreal startAngle, qreal arcLength)
QPainterPath operator|(const QPainterPath &other) const
bool operator==(const QPainterPath &other) const
QPainterPath intersected(const QPainterPath &r) const
qreal percentAtLength(qreal t) const
QPainterPath toReversed() const
QPainterPath & operator+=(const QPainterPath &other)
qreal slopeAtPercent(qreal t) const
void closeSubpath()
void addText(const QPointF &point, const QFont &f, const QString &text)
void lineTo(const QPointF &p)
QPointF currentPosition() const
qreal length() const
void swap(QPainterPath &other) noexcept
Definition: qpainterpath.h:98
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
void addRegion(const QRegion &region)
QPainterPath operator&(const QPainterPath &other) const
void arcMoveTo(const QRectF &rect, qreal angle)
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
Definition: qpainterpath.h:232
void setCurveThreshold(qreal threshold)
Qt::PenJoinStyle joinStyle() const
QList< qreal > dashPattern() const
void setDashPattern(Qt::PenStyle)
qreal miterLimit() const
qreal curveThreshold() const
Qt::PenCapStyle capStyle() const
void setDashOffset(qreal offset)
void setCapStyle(Qt::PenCapStyle style)
void setWidth(qreal width)
QPainterPath createStroke(const QPainterPath &path) const
void setJoinStyle(Qt::PenJoinStyle style)
qreal dashOffset() const
void setMiterLimit(qreal length)
QPainterPath clip(Operation op=BoolAnd)
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:61
qreal widthF() const
Definition: qpen.cpp:634
QList< qreal > dashPattern() const
Definition: qpen.cpp:456
Qt::PenCapStyle capStyle() const
Definition: qpen.cpp:698
Qt::PenJoinStyle joinStyle() const
Definition: qpen.cpp:725
qreal miterLimit() const
Definition: qpen.cpp:584
qreal dashOffset() const
Definition: qpen.cpp:542
Qt::PenStyle style() const
Definition: qpen.cpp:421
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr qreal x() const noexcept
Definition: qpoint.h:361
constexpr qreal y() const noexcept
Definition: qpoint.h:366
The QPolygonF class provides a list of points using floating point precision. \inmodule QtGui.
Definition: qpolygon.h:128
bool isClosed() const
Definition: qpolygon.h:148
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
constexpr qreal bottom() const noexcept
Definition: qrect.h:527
constexpr qreal y() const noexcept
Definition: qrect.h:681
constexpr qreal height() const noexcept
Definition: qrect.h:741
constexpr qreal width() const noexcept
Definition: qrect.h:738
constexpr qreal left() const noexcept
Definition: qrect.h:524
bool intersects(const QRectF &r) const noexcept
Definition: qrect.cpp:2284
constexpr bool isNull() const noexcept
Definition: qrect.h:667
constexpr QSizeF size() const noexcept
Definition: qrect.h:744
constexpr qreal top() const noexcept
Definition: qrect.h:525
constexpr qreal right() const noexcept
Definition: qrect.h:526
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:59
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:63
The QSizeF class defines the size of a two-dimensional object using floating point precision.
Definition: qsize.h:235
The QString class provides a Unicode character string.
Definition: qstring.h:388
qsizetype length() const
Definition: qstring.h:415
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition: qstroker_p.h:150
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition: qstroker_p.h:148
void strokePath(const QPainterPath &path, void *data, const QTransform &matrix)
Definition: qstroker.cpp:236
void setLineToHook(qStrokerLineToHook lineToHook)
Definition: qstroker_p.h:149
void setClipRect(const QRectF &clip)
Definition: qstroker_p.h:165
QScriptLineArray lines
LayoutData * layoutData
QGlyphLayout shapedGlyphs(const QScriptItem *si) const
QFontEngine * fontEngine(const QScriptItem &si, QFixed *ascent=nullptr, QFixed *descent=nullptr, QFixed *leading=nullptr) const
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
The QTextLayout class is used to lay out and render text. \inmodule QtGui.
Definition: qtextlayout.h:106
The QTextLine class represents a line of text inside a QTextLayout. \inmodule QtGui.
Definition: qtextlayout.h:208
The QTextOption class provides a description of general rich text properties. \inmodule QtGui.
Definition: qtextoption.h:54
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:56
T * data() noexcept
QPixmap p2
QPixmap p1
[0]
QString text
[meta data]
double e
rect
[4]
QStyleOptionButton opt
SizeMode
Definition: qnamespace.h:1161
@ AbsoluteSize
Definition: qnamespace.h:1162
PenStyle
Definition: qnamespace.h:1111
@ CustomDashLine
Definition: qnamespace.h:1118
PenJoinStyle
Definition: qnamespace.h:1131
FillRule
Definition: qnamespace.h:1320
@ WindingFill
Definition: qnamespace.h:1322
@ OddEvenFill
Definition: qnamespace.h:1321
QTextStream & endl(QTextStream &stream)
PenCapStyle
Definition: qnamespace.h:1124
bool qIsFinite(qfloat16 f) noexcept
Definition: qfloat16.h:222
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition: qfloat16.h:249
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
@ text
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
auto qSqrt(T v)
Definition: qmath.h:132
int qFloor(T v)
Definition: qmath.h:78
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum GLenum * types
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLfloat GLfloat f
GLsizei levels
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLint GLsizei width
GLint left
GLint GLint bottom
GLfloat angle
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLsizei dashCount
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLfixed GLfixed GLint GLint GLfixed points
Definition: qopenglext.h:5206
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
Definition: qopenglext.h:12395
GLuint res
Definition: qopenglext.h:8867
const GLubyte * c
Definition: qopenglext.h:12701
GLfixed GLfixed GLfixed y2
Definition: qopenglext.h:5231
GLuint GLuint * names
Definition: qopenglext.h:5654
GLenum GLsizei len
Definition: qopenglext.h:3292
GLint limit
Definition: qopenglext.h:9975
GLuint GLenum matrix
Definition: qopenglext.h:11564
GLfixed GLfixed x2
Definition: qopenglext.h:5231
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLbyte ty
Definition: qopenglext.h:6700
GLbyte by
Definition: qopenglext.h:6710
void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
#define QT_BEZIER_CHECK_T(bezier, t)
PainterDirections
@ Bottom
@ Top
@ Left
@ Right
#define QT_BEZIER_C(bezier, coord)
void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)
#define QT_BEZIER_A(bezier, coord)
#define QT_BEZIER_B(bezier, coord)
QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount)
void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
QPointF qAbs(const QPointF &p)
Definition: qscroller.cpp:119
qreal qt_t_for_arc_angle(qreal angle)
Definition: qstroker.cpp:792
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition: qstroker.cpp:852
#define QT_PATH_KAPPA
Definition: qstroker_p.h:113
#define qt_fixed_to_real(fixed)
Definition: qstroker_p.h:101
#define qt_real_to_fixed(real)
Definition: qstroker_p.h:100
QT_BEGIN_NAMESPACE typedef qreal qfixed
Definition: qstroker_p.h:99
#define sp
Q_UNUSED(salary)
[21]
QStringView el
QVBoxLayout * layout
MyCustomStruct c2
QSharedPointer< T > other(t)
[5]
QSize t2(10, 12)
QString dir
[11]
QGraphicsItem * item
constexpr qreal toReal() const
Definition: qfixed_p.h:78
unsigned short flags
unsigned short bidiLevel
QScriptAnalysis analysis
signed int length
QScriptItemArray items
const qreal epsilon
Definition: tst_qline.cpp:63