Qt 4.8
qpainterpath.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qpainterpath.h"
43 #include "qpainterpath_p.h"
44 
45 #include <qbitmap.h>
46 #include <qdebug.h>
47 #include <qiodevice.h>
48 #include <qlist.h>
49 #include <qmatrix.h>
50 #include <qpen.h>
51 #include <qpolygon.h>
52 #include <qtextlayout.h>
53 #include <qvarlengtharray.h>
54 #include <qmath.h>
55 
56 #include <private/qbezier_p.h>
57 #include <private/qfontengine_p.h>
58 #include <private/qnumeric_p.h>
59 #include <private/qobject_p.h>
60 #include <private/qpathclipper_p.h>
61 #include <private/qstroker_p.h>
62 #include <private/qtextengine_p.h>
63 
64 #include <limits.h>
65 
66 #if 0
67 #include <performance.h>
68 #else
69 #define PM_INIT
70 #define PM_MEASURE(x)
71 #define PM_DISPLAY
72 #endif
73 
75 
77 {
78  static inline void cleanup(QPainterPathPrivate *d)
79  {
80  // note - we must up-cast to QPainterPathData since QPainterPathPrivate
81  // has a non-virtual destructor!
82  if (d && !d->ref.deref())
83  delete static_cast<QPainterPathData *>(d);
84  }
85 };
86 
87 // This value is used to determine the length of control point vectors
88 // when approximating arc segments as curves. The factor is multiplied
89 // with the radius of the circle.
90 
91 // #define QPP_DEBUG
92 // #define QPP_STROKE_DEBUG
93 //#define QPP_FILLPOLYGONS_DEBUG
94 
95 QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount);
96 
98  QPointF* startPoint, QPointF *endPoint)
99 {
100  if (r.isNull()) {
101  if (startPoint)
102  *startPoint = QPointF();
103  if (endPoint)
104  *endPoint = QPointF();
105  return;
106  }
107 
108  qreal w2 = r.width() / 2;
109  qreal h2 = r.height() / 2;
110 
111  qreal angles[2] = { angle, angle + length };
112  QPointF *points[2] = { startPoint, endPoint };
113 
114  for (int i = 0; i < 2; ++i) {
115  if (!points[i])
116  continue;
117 
118  qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
119  qreal t = theta / 90;
120  // truncate
121  int quadrant = int(t);
122  t -= quadrant;
123 
124  t = qt_t_for_arc_angle(90 * t);
125 
126  // swap x and y?
127  if (quadrant & 1)
128  t = 1 - t;
129 
130  qreal a, b, c, d;
131  QBezier::coefficients(t, a, b, c, d);
132  QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
133 
134  // left quadrants
135  if (quadrant == 1 || quadrant == 2)
136  p.rx() = -p.x();
137 
138  // top quadrants
139  if (quadrant == 0 || quadrant == 1)
140  p.ry() = -p.y();
141 
142  *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
143  }
144 }
145 
146 #ifdef QPP_DEBUG
147 static void qt_debug_path(const QPainterPath &path)
148 {
149  const char *names[] = {
150  "MoveTo ",
151  "LineTo ",
152  "CurveTo ",
153  "CurveToData"
154  };
155 
156  printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
157  for (int i=0; i<path.elementCount(); ++i) {
158  const QPainterPath::Element &e = path.elementAt(i);
160  printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
161  }
162 }
163 #endif
164 
550 /*###
551  \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
552 
553  Appends the \a other painter path to this painter path and returns a
554  reference to the result.
555 */
556 
561  : d_ptr(0)
562 {
563 }
564 
576  : d_ptr(other.d_ptr.data())
577 {
578  if (d_ptr)
579  d_ptr->ref.ref();
580 }
581 
588  : d_ptr(new QPainterPathData)
589 {
590  Element e = { startPoint.x(), startPoint.y(), MoveToElement };
591  d_func()->elements << e;
592 }
593 
598 {
600  d_ptr.reset(data);
601 }
602 
607 {
609  data->elements.reserve(16);
611  data->elements << e;
612  d_ptr.reset(data);
613  Q_ASSERT(d_ptr != 0);
614 }
615 
627 {
628  if (other.d_func() != d_func()) {
629  QPainterPathPrivate *data = other.d_func();
630  if (data)
631  data->ref.ref();
632  d_ptr.reset(data);
633  }
634  return *this;
635 }
636 
652 {
653 }
654 
667 {
668 #ifdef QPP_DEBUG
669  printf("QPainterPath::closeSubpath()\n");
670 #endif
671  if (isEmpty())
672  return;
673  detach();
674 
675  d_func()->close();
676 }
677 
703 {
704 #ifdef QPP_DEBUG
705  printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
706 #endif
707 
708  if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
709 #ifndef QT_NO_DEBUG
710  qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
711 #endif
712  return;
713  }
714 
715  ensureData();
716  detach();
717 
719  Q_ASSERT(!d->elements.isEmpty());
720 
721  d->require_moveTo = false;
722 
723  if (d->elements.last().type == MoveToElement) {
724  d->elements.last().x = p.x();
725  d->elements.last().y = p.y();
726  } else {
727  Element elm = { p.x(), p.y(), MoveToElement };
728  d->elements.append(elm);
729  }
730  d->cStart = d->elements.size() - 1;
731 }
732 
759 {
760 #ifdef QPP_DEBUG
761  printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
762 #endif
763 
764  if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
765 #ifndef QT_NO_DEBUG
766  qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
767 #endif
768  return;
769  }
770 
771  ensureData();
772  detach();
773 
775  Q_ASSERT(!d->elements.isEmpty());
776  d->maybeMoveTo();
777  if (p == QPointF(d->elements.last()))
778  return;
779  Element elm = { p.x(), p.y(), LineToElement };
780  d->elements.append(elm);
781 
782  d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
783 }
784 
821 void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
822 {
823 #ifdef QPP_DEBUG
824  printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
825  c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
826 #endif
827 
828  if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y())
829  || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
830 #ifndef QT_NO_DEBUG
831  qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call");
832 #endif
833  return;
834  }
835 
836  ensureData();
837  detach();
838 
840  Q_ASSERT(!d->elements.isEmpty());
841 
842 
843  // Abort on empty curve as a stroker cannot handle this and the
844  // curve is irrelevant anyway.
845  if (d->elements.last() == c1 && c1 == c2 && c2 == e)
846  return;
847 
848  d->maybeMoveTo();
849 
850  Element ce1 = { c1.x(), c1.y(), CurveToElement };
851  Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
852  Element ee = { e.x(), e.y(), CurveToDataElement };
853  d->elements << ce1 << ce2 << ee;
854 }
855 
884 void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
885 {
886 #ifdef QPP_DEBUG
887  printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
888  c.x(), c.y(), e.x(), e.y());
889 #endif
890 
891  if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
892 #ifndef QT_NO_DEBUG
893  qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call");
894 #endif
895  return;
896  }
897 
898  ensureData();
899  detach();
900 
901  Q_D(QPainterPath);
902  Q_ASSERT(!d->elements.isEmpty());
903  const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
904  QPointF prev(elm.x, elm.y);
905 
906  // Abort on empty curve as a stroker cannot handle this and the
907  // curve is irrelevant anyway.
908  if (prev == c && c == e)
909  return;
910 
911  QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
912  QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
913  cubicTo(c1, c2, e);
914 }
915 
960 void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
961 {
962 #ifdef QPP_DEBUG
963  printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
964  rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
965 #endif
966 
967  if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height())
968  || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) {
969 #ifndef QT_NO_DEBUG
970  qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call");
971 #endif
972  return;
973  }
974 
975  if (rect.isNull())
976  return;
977 
978  ensureData();
979  detach();
980 
981  int point_count;
982  QPointF pts[15];
983  QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
984 
985  lineTo(curve_start);
986  for (int i=0; i<point_count; i+=3) {
987  cubicTo(pts[i].x(), pts[i].y(),
988  pts[i+1].x(), pts[i+1].y(),
989  pts[i+2].x(), pts[i+2].y());
990  }
991 
992 }
993 
994 
1025 {
1026  if (rect.isNull())
1027  return;
1028 
1029  QPointF pt;
1030  qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
1031  moveTo(pt);
1032 }
1033 
1034 
1035 
1045 {
1046  return !d_ptr || d_func()->elements.isEmpty()
1047  ? QPointF()
1048  : QPointF(d_func()->elements.last().x, d_func()->elements.last().y);
1049 }
1050 
1051 
1086 {
1087  if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) {
1088 #ifndef QT_NO_DEBUG
1089  qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call");
1090 #endif
1091  return;
1092  }
1093 
1094  if (r.isNull())
1095  return;
1096 
1097  ensureData();
1098  detach();
1099 
1100  bool first = d_func()->elements.size() < 2;
1101 
1102  d_func()->elements.reserve(d_func()->elements.size() + 5);
1103  moveTo(r.x(), r.y());
1104 
1105  Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1106  Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1107  Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1108  Element l4 = { r.x(), r.y(), LineToElement };
1109 
1110  d_func()->elements << l1 << l2 << l3 << l4;
1111  d_func()->require_moveTo = true;
1112  d_func()->convex = first;
1113 }
1114 
1132 {
1133  if (polygon.isEmpty())
1134  return;
1135 
1136  ensureData();
1137  detach();
1138 
1139  d_func()->elements.reserve(d_func()->elements.size() + polygon.size());
1140 
1141  moveTo(polygon.first());
1142  for (int i=1; i<polygon.size(); ++i) {
1143  Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1144  d_func()->elements << elm;
1145  }
1146 }
1147 
1170 {
1171  if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y())
1172  || !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) {
1173 #ifndef QT_NO_DEBUG
1174  qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call");
1175 #endif
1176  return;
1177  }
1178 
1179  if (boundingRect.isNull())
1180  return;
1181 
1182  ensureData();
1183  detach();
1184 
1185  Q_D(QPainterPath);
1186  bool first = d_func()->elements.size() < 2;
1187  d->elements.reserve(d->elements.size() + 13);
1188 
1189  QPointF pts[12];
1190  int point_count;
1191  QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1192 
1193  moveTo(start);
1194  cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1195  cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1196  cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1197  cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1198  d_func()->require_moveTo = true;
1199 
1200  d_func()->convex = first;
1201 }
1202 
1223 void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1224 {
1225  if (text.isEmpty())
1226  return;
1227 
1228  ensureData();
1229  detach();
1230 
1231  QTextLayout layout(text, f);
1232  layout.setCacheEnabled(true);
1233  QTextEngine *eng = layout.engine();
1234  layout.beginLayout();
1235  QTextLine line = layout.createLine();
1236  Q_UNUSED(line);
1237  layout.endLayout();
1238  const QScriptLine &sl = eng->lines[0];
1239  if (!sl.length || !eng->layoutData)
1240  return;
1241 
1242  int nItems = eng->layoutData->items.size();
1243 
1244  qreal x(point.x());
1245  qreal y(point.y());
1246 
1247  QVarLengthArray<int> visualOrder(nItems);
1248  QVarLengthArray<uchar> levels(nItems);
1249  for (int i = 0; i < nItems; ++i)
1250  levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
1251  QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1252 
1253  for (int i = 0; i < nItems; ++i) {
1254  int item = visualOrder[i];
1255  QScriptItem &si = eng->layoutData->items[item];
1256 
1258  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1260  Q_ASSERT(fe);
1261  fe->addOutlineToPath(x, y, glyphs, this,
1262  si.analysis.bidiLevel % 2
1263  ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1264  : QTextItem::RenderFlags(0));
1265 
1266  const qreal lw = fe->lineThickness().toReal();
1267  if (f.d->underline) {
1268  qreal pos = fe->underlinePosition().toReal();
1269  addRect(x, y + pos, si.width.toReal(), lw);
1270  }
1271  if (f.d->overline) {
1272  qreal pos = fe->ascent().toReal() + 1;
1273  addRect(x, y - pos, si.width.toReal(), lw);
1274  }
1275  if (f.d->strikeOut) {
1276  qreal pos = fe->ascent().toReal() / 3;
1277  addRect(x, y - pos, si.width.toReal(), lw);
1278  }
1279  }
1280  x += si.width.toReal();
1281  }
1282 }
1283 
1296 {
1297  if (other.isEmpty())
1298  return;
1299 
1300  ensureData();
1301  detach();
1302 
1303  QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1304  // Remove last moveto so we don't get multiple moveto's
1305  if (d->elements.last().type == MoveToElement)
1306  d->elements.remove(d->elements.size()-1);
1307 
1308  // Locate where our own current subpath will start after the other path is added.
1309  int cStart = d->elements.size() + other.d_func()->cStart;
1310  d->elements += other.d_func()->elements;
1311  d->cStart = cStart;
1312 
1313  d->require_moveTo = other.d_func()->isClosed();
1314 }
1315 
1316 
1330 {
1331  if (other.isEmpty())
1332  return;
1333 
1334  ensureData();
1335  detach();
1336 
1337  QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1338  // Remove last moveto so we don't get multiple moveto's
1339  if (d->elements.last().type == MoveToElement)
1340  d->elements.remove(d->elements.size()-1);
1341 
1342  // Locate where our own current subpath will start after the other path is added.
1343  int cStart = d->elements.size() + other.d_func()->cStart;
1344  int first = d->elements.size();
1345  d->elements += other.d_func()->elements;
1346 
1347  if (first != 0)
1348  d->elements[first].type = LineToElement;
1349 
1350  // avoid duplicate points
1351  if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
1352  d->elements.remove(first--);
1353  --cStart;
1354  }
1355 
1356  if (cStart != first)
1357  d->cStart = cStart;
1358 }
1359 
1368 {
1369  ensureData();
1370  detach();
1371 
1372  QVector<QRect> rects = region.rects();
1373  d_func()->elements.reserve(rects.size() * 5);
1374  for (int i=0; i<rects.size(); ++i)
1375  addRect(rects.at(i));
1376 }
1377 
1378 
1385 {
1386  return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1387 }
1388 
1410 {
1411  ensureData();
1412  if (d_func()->fillRule == fillRule)
1413  return;
1414  detach();
1415 
1416  d_func()->fillRule = fillRule;
1417 }
1418 
1419 #define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1420  + 3*bezier.coord##2 \
1421  - 3*bezier.coord##3 \
1422  +bezier.coord##4)
1423 
1424 #define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1425  - 2*bezier.coord##2 \
1426  + bezier.coord##3)
1427 
1428 #define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1429  + bezier.coord##2)
1430 
1431 #define QT_BEZIER_CHECK_T(bezier, t) \
1432  if (t >= 0 && t <= 1) { \
1433  QPointF p(b.pointAt(t)); \
1434  if (p.x() < minx) minx = p.x(); \
1435  else if (p.x() > maxx) maxx = p.x(); \
1436  if (p.y() < miny) miny = p.y(); \
1437  else if (p.y() > maxy) maxy = p.y(); \
1438  }
1439 
1440 
1442 {
1443  qreal minx, miny, maxx, maxy;
1444 
1445  // initialize with end points
1446  if (b.x1 < b.x4) {
1447  minx = b.x1;
1448  maxx = b.x4;
1449  } else {
1450  minx = b.x4;
1451  maxx = b.x1;
1452  }
1453  if (b.y1 < b.y4) {
1454  miny = b.y1;
1455  maxy = b.y4;
1456  } else {
1457  miny = b.y4;
1458  maxy = b.y1;
1459  }
1460 
1461  // Update for the X extrema
1462  {
1463  qreal ax = QT_BEZIER_A(b, x);
1464  qreal bx = QT_BEZIER_B(b, x);
1465  qreal cx = QT_BEZIER_C(b, x);
1466  // specialcase quadratic curves to avoid div by zero
1467  if (qFuzzyIsNull(ax)) {
1468 
1469  // linear curves are covered by initialization.
1470  if (!qFuzzyIsNull(bx)) {
1471  qreal t = -cx / bx;
1472  QT_BEZIER_CHECK_T(b, t);
1473  }
1474 
1475  } else {
1476  const qreal tx = bx * bx - 4 * ax * cx;
1477 
1478  if (tx >= 0) {
1479  qreal temp = qSqrt(tx);
1480  qreal rcp = 1 / (2 * ax);
1481  qreal t1 = (-bx + temp) * rcp;
1482  QT_BEZIER_CHECK_T(b, t1);
1483 
1484  qreal t2 = (-bx - temp) * rcp;
1485  QT_BEZIER_CHECK_T(b, t2);
1486  }
1487  }
1488  }
1489 
1490  // Update for the Y extrema
1491  {
1492  qreal ay = QT_BEZIER_A(b, y);
1493  qreal by = QT_BEZIER_B(b, y);
1494  qreal cy = QT_BEZIER_C(b, y);
1495 
1496  // specialcase quadratic curves to avoid div by zero
1497  if (qFuzzyIsNull(ay)) {
1498 
1499  // linear curves are covered by initialization.
1500  if (!qFuzzyIsNull(by)) {
1501  qreal t = -cy / by;
1502  QT_BEZIER_CHECK_T(b, t);
1503  }
1504 
1505  } else {
1506  const qreal ty = by * by - 4 * ay * cy;
1507 
1508  if (ty > 0) {
1509  qreal temp = qSqrt(ty);
1510  qreal rcp = 1 / (2 * ay);
1511  qreal t1 = (-by + temp) * rcp;
1512  QT_BEZIER_CHECK_T(b, t1);
1513 
1514  qreal t2 = (-by - temp) * rcp;
1515  QT_BEZIER_CHECK_T(b, t2);
1516  }
1517  }
1518  }
1519  return QRectF(minx, miny, maxx - minx, maxy - miny);
1520 }
1521 
1529 {
1530  if (!d_ptr)
1531  return QRectF();
1532  QPainterPathData *d = d_func();
1533 
1534  if (d->dirtyBounds)
1536  return d->bounds;
1537 }
1538 
1550 {
1551  if (!d_ptr)
1552  return QRectF();
1553  QPainterPathData *d = d_func();
1554 
1555  if (d->dirtyControlBounds)
1557  return d->controlBounds;
1558 }
1559 
1560 
1582 {
1583  Q_D(const QPainterPath);
1584  QPainterPath rev;
1585 
1586  if (isEmpty()) {
1587  rev = *this;
1588  return rev;
1589  }
1590 
1591  rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1592 
1593  for (int i=d->elements.size()-1; i>=1; --i) {
1594  const QPainterPath::Element &elm = d->elements.at(i);
1595  const QPainterPath::Element &prev = d->elements.at(i-1);
1596  switch (elm.type) {
1597  case LineToElement:
1598  rev.lineTo(prev.x, prev.y);
1599  break;
1600  case MoveToElement:
1601  rev.moveTo(prev.x, prev.y);
1602  break;
1603  case CurveToDataElement:
1604  {
1605  Q_ASSERT(i>=3);
1606  const QPainterPath::Element &cp1 = d->elements.at(i-2);
1607  const QPainterPath::Element &sp = d->elements.at(i-3);
1608  Q_ASSERT(prev.type == CurveToDataElement);
1609  Q_ASSERT(cp1.type == CurveToElement);
1610  rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1611  i -= 2;
1612  break;
1613  }
1614  default:
1615  Q_ASSERT(!"qt_reversed_path");
1616  break;
1617  }
1618  }
1619  //qt_debug_path(rev);
1620  return rev;
1621 }
1622 
1636 {
1637 
1638  Q_D(const QPainterPath);
1639  QList<QPolygonF> flatCurves;
1640  if (isEmpty())
1641  return flatCurves;
1642 
1643  QPolygonF current;
1644  for (int i=0; i<elementCount(); ++i) {
1645  const QPainterPath::Element &e = d->elements.at(i);
1646  switch (e.type) {
1648  if (current.size() > 1)
1649  flatCurves += current;
1650  current.clear();
1651  current.reserve(16);
1652  current += QPointF(e.x, e.y) * matrix;
1653  break;
1655  current += QPointF(e.x, e.y) * matrix;
1656  break;
1658  Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1659  Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1660  QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1661  QPointF(e.x, e.y) * matrix,
1662  QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1663  QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1664  bezier.addToPolygon(&current);
1665  i+=2;
1666  break;
1667  }
1669  Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1670  break;
1671  }
1672  }
1673 
1674  if (current.size()>1)
1675  flatCurves += current;
1676 
1677  return flatCurves;
1678 }
1679 
1684 {
1685  return toSubpathPolygons(QTransform(matrix));
1686 }
1687 
1711 {
1712 
1713  QList<QPolygonF> polys;
1714 
1715  QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1716  int count = subpaths.size();
1717 
1718  if (count == 0)
1719  return polys;
1720 
1721  QList<QRectF> bounds;
1722  for (int i=0; i<count; ++i)
1723  bounds += subpaths.at(i).boundingRect();
1724 
1725 #ifdef QPP_FILLPOLYGONS_DEBUG
1726  printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1727  for (int i=0; i<bounds.size(); ++i)
1728  qDebug() << " bounds" << i << bounds.at(i);
1729 #endif
1730 
1731  QVector< QList<int> > isects;
1732  isects.resize(count);
1733 
1734  // find all intersections
1735  for (int j=0; j<count; ++j) {
1736  if (subpaths.at(j).size() <= 2)
1737  continue;
1738  QRectF cbounds = bounds.at(j);
1739  for (int i=0; i<count; ++i) {
1740  if (cbounds.intersects(bounds.at(i))) {
1741  isects[j] << i;
1742  }
1743  }
1744  }
1745 
1746 #ifdef QPP_FILLPOLYGONS_DEBUG
1747  printf("Intersections before flattening:\n");
1748  for (int i = 0; i < count; ++i) {
1749  printf("%d: ", i);
1750  for (int j = 0; j < isects[i].size(); ++j) {
1751  printf("%d ", isects[i][j]);
1752  }
1753  printf("\n");
1754  }
1755 #endif
1756 
1757  // flatten the sets of intersections
1758  for (int i=0; i<count; ++i) {
1759  const QList<int> &current_isects = isects.at(i);
1760  for (int j=0; j<current_isects.size(); ++j) {
1761  int isect_j = current_isects.at(j);
1762  if (isect_j == i)
1763  continue;
1764  for (int k=0; k<isects[isect_j].size(); ++k) {
1765  int isect_k = isects[isect_j][k];
1766  if (isect_k != i && !isects.at(i).contains(isect_k)) {
1767  isects[i] += isect_k;
1768  }
1769  }
1770  isects[isect_j].clear();
1771  }
1772  }
1773 
1774 #ifdef QPP_FILLPOLYGONS_DEBUG
1775  printf("Intersections after flattening:\n");
1776  for (int i = 0; i < count; ++i) {
1777  printf("%d: ", i);
1778  for (int j = 0; j < isects[i].size(); ++j) {
1779  printf("%d ", isects[i][j]);
1780  }
1781  printf("\n");
1782  }
1783 #endif
1784 
1785  // Join the intersected subpaths as rewinded polygons
1786  for (int i=0; i<count; ++i) {
1787  const QList<int> &subpath_list = isects[i];
1788  if (!subpath_list.isEmpty()) {
1789  QPolygonF buildUp;
1790  for (int j=0; j<subpath_list.size(); ++j) {
1791  const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1792  buildUp += subpath;
1793  if (!subpath.isClosed())
1794  buildUp += subpath.first();
1795  if (!buildUp.isClosed())
1796  buildUp += buildUp.first();
1797  }
1798  polys += buildUp;
1799  }
1800  }
1801 
1802  return polys;
1803 }
1804 
1809 {
1810  return toFillPolygons(QTransform(matrix));
1811 }
1812 
1813 //same as qt_polygon_isect_line in qpolygon.cpp
1814 static void qt_painterpath_isect_line(const QPointF &p1,
1815  const QPointF &p2,
1816  const QPointF &pos,
1817  int *winding)
1818 {
1819  qreal x1 = p1.x();
1820  qreal y1 = p1.y();
1821  qreal x2 = p2.x();
1822  qreal y2 = p2.y();
1823  qreal y = pos.y();
1824 
1825  int dir = 1;
1826 
1827  if (qFuzzyCompare(y1, y2)) {
1828  // ignore horizontal lines according to scan conversion rule
1829  return;
1830  } else if (y2 < y1) {
1831  qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1832  qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1833  dir = -1;
1834  }
1835 
1836  if (y >= y1 && y < y2) {
1837  qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1838 
1839  // count up the winding number if we're
1840  if (x<=pos.x()) {
1841  (*winding) += dir;
1842  }
1843  }
1844 }
1845 
1846 static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1847  int *winding, int depth = 0)
1848 {
1849  qreal y = pt.y();
1850  qreal x = pt.x();
1851  QRectF bounds = bezier.bounds();
1852 
1853  // potential intersection, divide and try again...
1854  // Please note that a sideeffect of the bottom exclusion is that
1855  // horizontal lines are dropped, but this is correct according to
1856  // scan conversion rules.
1857  if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1858 
1859  // hit lower limit... This is a rough threshold, but its a
1860  // tradeoff between speed and precision.
1861  const qreal lower_bound = qreal(.001);
1862  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1863  // We make the assumption here that the curve starts to
1864  // approximate a line after while (i.e. that it doesn't
1865  // change direction drastically during its slope)
1866  if (bezier.pt1().x() <= x) {
1867  (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1868  }
1869  return;
1870  }
1871 
1872  // split curve and try again...
1873  QBezier first_half, second_half;
1874  bezier.split(&first_half, &second_half);
1875  qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
1876  qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
1877  }
1878 }
1879 
1891 bool QPainterPath::contains(const QPointF &pt) const
1892 {
1893  if (isEmpty() || !controlPointRect().contains(pt))
1894  return false;
1895 
1896  QPainterPathData *d = d_func();
1897 
1898  int winding_number = 0;
1899 
1900  QPointF last_pt;
1901  QPointF last_start;
1902  for (int i=0; i<d->elements.size(); ++i) {
1903  const Element &e = d->elements.at(i);
1904 
1905  switch (e.type) {
1906 
1907  case MoveToElement:
1908  if (i > 0) // implicitly close all paths.
1909  qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1910  last_start = last_pt = e;
1911  break;
1912 
1913  case LineToElement:
1914  qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1915  last_pt = e;
1916  break;
1917 
1918  case CurveToElement:
1919  {
1920  const QPainterPath::Element &cp2 = d->elements.at(++i);
1921  const QPainterPath::Element &ep = d->elements.at(++i);
1922  qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1923  pt, &winding_number);
1924  last_pt = ep;
1925 
1926  }
1927  break;
1928 
1929  default:
1930  break;
1931  }
1932  }
1933 
1934  // implicitly close last subpath
1935  if (last_pt != last_start)
1936  qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1937 
1938  return (d->fillRule == Qt::WindingFill
1939  ? (winding_number != 0)
1940  : ((winding_number % 2) != 0));
1941 }
1942 
1944  const QRectF &rect)
1945 {
1946  qreal left = rect.left();
1947  qreal right = rect.right();
1948  qreal top = rect.top();
1949  qreal bottom = rect.bottom();
1950 
1951  enum { Left, Right, Top, Bottom };
1952  // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1953  int p1 = ((x1 < left) << Left)
1954  | ((x1 > right) << Right)
1955  | ((y1 < top) << Top)
1956  | ((y1 > bottom) << Bottom);
1957  int p2 = ((x2 < left) << Left)
1958  | ((x2 > right) << Right)
1959  | ((y2 < top) << Top)
1960  | ((y2 > bottom) << Bottom);
1961 
1962  if (p1 & p2)
1963  // completely inside
1964  return false;
1965 
1966  if (p1 | p2) {
1967  qreal dx = x2 - x1;
1968  qreal dy = y2 - y1;
1969 
1970  // clip x coordinates
1971  if (x1 < left) {
1972  y1 += dy/dx * (left - x1);
1973  x1 = left;
1974  } else if (x1 > right) {
1975  y1 -= dy/dx * (x1 - right);
1976  x1 = right;
1977  }
1978  if (x2 < left) {
1979  y2 += dy/dx * (left - x2);
1980  x2 = left;
1981  } else if (x2 > right) {
1982  y2 -= dy/dx * (x2 - right);
1983  x2 = right;
1984  }
1985 
1986  p1 = ((y1 < top) << Top)
1987  | ((y1 > bottom) << Bottom);
1988  p2 = ((y2 < top) << Top)
1989  | ((y2 > bottom) << Bottom);
1990 
1991  if (p1 & p2)
1992  return false;
1993 
1994  // clip y coordinates
1995  if (y1 < top) {
1996  x1 += dx/dy * (top - y1);
1997  y1 = top;
1998  } else if (y1 > bottom) {
1999  x1 -= dx/dy * (y1 - bottom);
2000  y1 = bottom;
2001  }
2002  if (y2 < top) {
2003  x2 += dx/dy * (top - y2);
2004  y2 = top;
2005  } else if (y2 > bottom) {
2006  x2 -= dx/dy * (y2 - bottom);
2007  y2 = bottom;
2008  }
2009 
2010  p1 = ((x1 < left) << Left)
2011  | ((x1 > right) << Right);
2012  p2 = ((x2 < left) << Left)
2013  | ((x2 > right) << Right);
2014 
2015  if (p1 & p2)
2016  return false;
2017 
2018  return true;
2019  }
2020  return false;
2021 }
2022 
2023 static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
2024 {
2025  QRectF bounds = bezier.bounds();
2026 
2027  if (y >= bounds.top() && y < bounds.bottom()
2028  && bounds.right() >= x1 && bounds.left() < x2) {
2029  const qreal lower_bound = qreal(.01);
2030  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
2031  return true;
2032 
2033  QBezier first_half, second_half;
2034  bezier.split(&first_half, &second_half);
2035  if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1)
2036  || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1))
2037  return true;
2038  }
2039  return false;
2040 }
2041 
2042 static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
2043 {
2044  QRectF bounds = bezier.bounds();
2045 
2046  if (x >= bounds.left() && x < bounds.right()
2047  && bounds.bottom() >= y1 && bounds.top() < y2) {
2048  const qreal lower_bound = qreal(.01);
2049  if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
2050  return true;
2051 
2052  QBezier first_half, second_half;
2053  bezier.split(&first_half, &second_half);
2054  if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1)
2055  || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1))
2056  return true;
2057  }
2058  return false;
2059 }
2060 
2061 /*
2062  Returns true if any lines or curves cross the four edges in of rect
2063 */
2064 static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
2065 {
2066  QPointF last_pt;
2067  QPointF last_start;
2068  for (int i=0; i<path->elementCount(); ++i) {
2069  const QPainterPath::Element &e = path->elementAt(i);
2070 
2071  switch (e.type) {
2072 
2074  if (i > 0
2075  && qFuzzyCompare(last_pt.x(), last_start.x())
2076  && qFuzzyCompare(last_pt.y(), last_start.y())
2077  && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2078  last_start.x(), last_start.y(), rect))
2079  return true;
2080  last_start = last_pt = e;
2081  break;
2082 
2084  if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2085  return true;
2086  last_pt = e;
2087  break;
2088 
2090  {
2091  QPointF cp2 = path->elementAt(++i);
2092  QPointF ep = path->elementAt(++i);
2093  QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2094  if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2095  || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2096  || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2097  || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2098  return true;
2099  last_pt = ep;
2100  }
2101  break;
2102 
2103  default:
2104  break;
2105  }
2106  }
2107 
2108  // implicitly close last subpath
2109  if (last_pt != last_start
2110  && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2111  last_start.x(), last_start.y(), rect))
2112  return true;
2113 
2114  return false;
2115 }
2116 
2134 bool QPainterPath::intersects(const QRectF &rect) const
2135 {
2136  if (elementCount() == 1 && rect.contains(elementAt(0)))
2137  return true;
2138 
2139  if (isEmpty())
2140  return false;
2141 
2142  QRectF cp = controlPointRect();
2143  QRectF rn = rect.normalized();
2144 
2145  // QRectF::intersects returns false if one of the rects is a null rect
2146  // which would happen for a painter path consisting of a vertical or
2147  // horizontal line
2148  if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2149  || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2150  return false;
2151 
2152  // If any path element cross the rect its bound to be an intersection
2153  if (qt_painterpath_check_crossing(this, rect))
2154  return true;
2155 
2156  if (contains(rect.center()))
2157  return true;
2158 
2159  Q_D(QPainterPath);
2160 
2161  // Check if the rectangle surounds any subpath...
2162  for (int i=0; i<d->elements.size(); ++i) {
2163  const Element &e = d->elements.at(i);
2164  if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2165  return true;
2166  }
2167 
2168  return false;
2169 }
2170 
2178 {
2179  if (!d_ptr || (dx == 0 && dy == 0))
2180  return;
2181 
2182  int elementsLeft = d_ptr->elements.size();
2183  if (elementsLeft <= 0)
2184  return;
2185 
2186  detach();
2187  QPainterPath::Element *element = d_func()->elements.data();
2188  Q_ASSERT(element);
2189  while (elementsLeft--) {
2190  element->x += dx;
2191  element->y += dy;
2192  ++element;
2193  }
2194 }
2195 
2216 {
2217  QPainterPath copy(*this);
2218  copy.translate(dx, dy);
2219  return copy;
2220 }
2221 
2244 bool QPainterPath::contains(const QRectF &rect) const
2245 {
2246  Q_D(QPainterPath);
2247 
2248  // the path is empty or the control point rect doesn't completely
2249  // cover the rectangle we abort stratight away.
2250  if (isEmpty() || !controlPointRect().contains(rect))
2251  return false;
2252 
2253  // if there are intersections, chances are that the rect is not
2254  // contained, except if we have winding rule, in which case it
2255  // still might.
2256  if (qt_painterpath_check_crossing(this, rect)) {
2257  if (fillRule() == Qt::OddEvenFill) {
2258  return false;
2259  } else {
2260  // Do some wague sampling in the winding case. This is not
2261  // precise but it should mostly be good enough.
2262  if (!contains(rect.topLeft()) ||
2263  !contains(rect.topRight()) ||
2264  !contains(rect.bottomRight()) ||
2265  !contains(rect.bottomLeft()))
2266  return false;
2267  }
2268  }
2269 
2270  // If there exists a point inside that is not part of the path its
2271  // because: rectangle lies completely outside path or a subpath
2272  // excludes parts of the rectangle. Both cases mean that the rect
2273  // is not contained
2274  if (!contains(rect.center()))
2275  return false;
2276 
2277  // If there are any subpaths inside this rectangle we need to
2278  // check if they are still contained as a result of the fill
2279  // rule. This can only be the case for WindingFill though. For
2280  // OddEvenFill the rect will never be contained if it surrounds a
2281  // subpath. (the case where two subpaths are completely identical
2282  // can be argued but we choose to neglect it).
2283  for (int i=0; i<d->elements.size(); ++i) {
2284  const Element &e = d->elements.at(i);
2285  if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2286  if (fillRule() == Qt::OddEvenFill)
2287  return false;
2288 
2289  bool stop = false;
2290  for (; !stop && i<d->elements.size(); ++i) {
2291  const Element &el = d->elements.at(i);
2292  switch (el.type) {
2293  case MoveToElement:
2294  stop = true;
2295  break;
2296  case LineToElement:
2297  if (!contains(el))
2298  return false;
2299  break;
2300  case CurveToElement:
2301  if (!contains(d->elements.at(i+2)))
2302  return false;
2303  i += 2;
2304  break;
2305  default:
2306  break;
2307  }
2308  }
2309 
2310  // compensate for the last ++i in the inner for
2311  --i;
2312  }
2313  }
2314 
2315  return true;
2316 }
2317 
2318 static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2319 {
2320  return qAbs(a.x() - b.x()) <= epsilon.width()
2321  && qAbs(a.y() - b.y()) <= epsilon.height();
2322 }
2323 
2334 {
2335  QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2336  if (path.d_func() == d)
2337  return true;
2338  else if (!d || !path.d_func())
2339  return false;
2340  else if (d->fillRule != path.d_func()->fillRule)
2341  return false;
2342  else if (d->elements.size() != path.d_func()->elements.size())
2343  return false;
2344 
2345  const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2346 
2347  QSizeF epsilon = boundingRect().size();
2348  epsilon.rwidth() *= qt_epsilon;
2349  epsilon.rheight() *= qt_epsilon;
2350 
2351  for (int i = 0; i < d->elements.size(); ++i)
2352  if (d->elements.at(i).type != path.d_func()->elements.at(i).type
2353  || !epsilonCompare(d->elements.at(i), path.d_func()->elements.at(i), epsilon))
2354  return false;
2355 
2356  return true;
2357 }
2358 
2369 {
2370  return !(*this==path);
2371 }
2372 
2384 {
2385  return intersected(other);
2386 }
2387 
2399 {
2400  return united(other);
2401 }
2402 
2415 {
2416  return united(other);
2417 }
2418 
2430 {
2431  return subtracted(other);
2432 }
2433 
2445 {
2446  return *this = (*this & other);
2447 }
2448 
2460 {
2461  return *this = (*this | other);
2462 }
2463 
2476 {
2477  return *this = (*this + other);
2478 }
2479 
2492 {
2493  return *this = (*this - other);
2494 }
2495 
2496 #ifndef QT_NO_DATASTREAM
2497 
2510 {
2511  if (p.isEmpty()) {
2512  s << 0;
2513  return s;
2514  }
2515 
2516  s << p.elementCount();
2517  for (int i=0; i < p.d_func()->elements.size(); ++i) {
2518  const QPainterPath::Element &e = p.d_func()->elements.at(i);
2519  s << int(e.type);
2520  s << double(e.x) << double(e.y);
2521  }
2522  s << p.d_func()->cStart;
2523  s << int(p.d_func()->fillRule);
2524  return s;
2525 }
2526 
2540 {
2541  int size;
2542  s >> size;
2543 
2544  if (size == 0)
2545  return s;
2546 
2547  p.ensureData(); // in case if p.d_func() == 0
2548  if (p.d_func()->elements.size() == 1) {
2549  Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2550  p.d_func()->elements.clear();
2551  }
2552  p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
2553  for (int i=0; i<size; ++i) {
2554  int type;
2555  double x, y;
2556  s >> type;
2557  s >> x;
2558  s >> y;
2559  Q_ASSERT(type >= 0 && type <= 3);
2560  if (!qt_is_finite(x) || !qt_is_finite(y)) {
2561 #ifndef QT_NO_DEBUG
2562  qWarning("QDataStream::operator>>: NaN or Inf element found in path, skipping it");
2563 #endif
2564  continue;
2565  }
2567  p.d_func()->elements.append(elm);
2568  }
2569  s >> p.d_func()->cStart;
2570  int fillRule;
2571  s >> fillRule;
2572  Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
2573  p.d_func()->fillRule = Qt::FillRule(fillRule);
2574  p.d_func()->dirtyBounds = true;
2575  p.d_func()->dirtyControlBounds = true;
2576  return s;
2577 }
2578 #endif // QT_NO_DATASTREAM
2579 
2580 
2581 /*******************************************************************************
2582  * class QPainterPathStroker
2583  */
2584 
2586 {
2587  ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2588 }
2589 
2591 {
2592  ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2593 }
2594 
2596  qfixed c2x, qfixed c2y,
2597  qfixed ex, qfixed ey,
2598  void *data)
2599 {
2600  ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2603 }
2604 
2659  : dashOffset(0)
2660 {
2664 }
2665 
2670  : d_ptr(new QPainterPathStrokerPrivate)
2671 {
2672 }
2673 
2678 {
2679 }
2680 
2681 
2696 {
2697  QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2698  QPainterPath stroke;
2699  if (path.isEmpty())
2700  return path;
2701  if (d->dashPattern.isEmpty()) {
2702  d->stroker.strokePath(path, &stroke, QTransform());
2703  } else {
2704  QDashStroker dashStroker(&d->stroker);
2705  dashStroker.setDashPattern(d->dashPattern);
2706  dashStroker.setDashOffset(d->dashOffset);
2707  dashStroker.setClipRect(d->stroker.clipRect());
2708  dashStroker.strokePath(path, &stroke, QTransform());
2709  }
2710  stroke.setFillRule(Qt::WindingFill);
2711  return stroke;
2712 }
2713 
2721 {
2723  if (width <= 0)
2724  width = 1;
2725  d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2726 }
2727 
2732 {
2733  return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2734 }
2735 
2736 
2743 {
2744  d_func()->stroker.setCapStyle(style);
2745 }
2746 
2747 
2752 {
2753  return d_func()->stroker.capStyle();
2754 }
2755 
2760 {
2761  d_func()->stroker.setJoinStyle(style);
2762 }
2763 
2768 {
2769  return d_func()->stroker.joinStyle();
2770 }
2771 
2783 {
2784  d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2785 }
2786 
2791 {
2792  return qt_fixed_to_real(d_func()->stroker.miterLimit());
2793 }
2794 
2795 
2805 {
2806  d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2807 }
2808 
2814 {
2815  return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2816 }
2817 
2822 {
2823  d_func()->dashPattern = QDashStroker::patternForStyle(style);
2824 }
2825 
2846 {
2847  d_func()->dashPattern.clear();
2848  for (int i=0; i<dashPattern.size(); ++i)
2849  d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2850 }
2851 
2856 {
2857  return d_func()->dashPattern;
2858 }
2859 
2864 {
2865  return d_func()->dashOffset;
2866 }
2867 
2875 {
2876  d_func()->dashOffset = offset;
2877 }
2878 
2895 {
2896 
2897  QList<QPolygonF> flats = toSubpathPolygons(matrix);
2898  QPolygonF polygon;
2899  if (flats.isEmpty())
2900  return polygon;
2901  QPointF first = flats.first().first();
2902  for (int i=0; i<flats.size(); ++i) {
2903  polygon += flats.at(i);
2904  if (!flats.at(i).isClosed())
2905  polygon += flats.at(i).first();
2906  if (i > 0)
2907  polygon += first;
2908  }
2909  return polygon;
2910 }
2911 
2916 {
2917  return toFillPolygon(QTransform(matrix));
2918 }
2919 
2920 
2921 //derivative of the equation
2922 static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2923 {
2924  return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2925 }
2926 
2931 {
2932  Q_D(QPainterPath);
2933  if (isEmpty())
2934  return 0;
2935 
2936  qreal len = 0;
2937  for (int i=1; i<d->elements.size(); ++i) {
2938  const Element &e = d->elements.at(i);
2939 
2940  switch (e.type) {
2941  case MoveToElement:
2942  break;
2943  case LineToElement:
2944  {
2945  len += QLineF(d->elements.at(i-1), e).length();
2946  break;
2947  }
2948  case CurveToElement:
2949  {
2950  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2951  e,
2952  d->elements.at(i+1),
2953  d->elements.at(i+2));
2954  len += b.length();
2955  i += 2;
2956  break;
2957  }
2958  default:
2959  break;
2960  }
2961  }
2962  return len;
2963 }
2964 
2974 {
2975  Q_D(QPainterPath);
2976  if (isEmpty() || len <= 0)
2977  return 0;
2978 
2979  qreal totalLength = length();
2980  if (len > totalLength)
2981  return 1;
2982 
2983  qreal curLen = 0;
2984  for (int i=1; i<d->elements.size(); ++i) {
2985  const Element &e = d->elements.at(i);
2986 
2987  switch (e.type) {
2988  case MoveToElement:
2989  break;
2990  case LineToElement:
2991  {
2992  QLineF line(d->elements.at(i-1), e);
2993  qreal llen = line.length();
2994  curLen += llen;
2995  if (curLen >= len) {
2996  return len/totalLength ;
2997  }
2998 
2999  break;
3000  }
3001  case CurveToElement:
3002  {
3003  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3004  e,
3005  d->elements.at(i+1),
3006  d->elements.at(i+2));
3007  qreal blen = b.length();
3008  qreal prevLen = curLen;
3009  curLen += blen;
3010 
3011  if (curLen >= len) {
3012  qreal res = b.tAtLength(len - prevLen);
3013  return (res * blen + prevLen)/totalLength;
3014  }
3015 
3016  i += 2;
3017  break;
3018  }
3019  default:
3020  break;
3021  }
3022  }
3023 
3024  return 0;
3025 }
3026 
3027 static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
3028 {
3029  *startingLength = 0;
3030  if (t > 1)
3031  return QBezier();
3032 
3033  qreal curLen = 0;
3034  qreal totalLength = path.length();
3035 
3036  const int lastElement = path.elementCount() - 1;
3037  for (int i=0; i <= lastElement; ++i) {
3038  const QPainterPath::Element &e = path.elementAt(i);
3039 
3040  switch (e.type) {
3042  break;
3044  {
3045  QLineF line(path.elementAt(i-1), e);
3046  qreal llen = line.length();
3047  curLen += llen;
3048  if (i == lastElement || curLen/totalLength >= t) {
3049  *bezierLength = llen;
3050  QPointF a = path.elementAt(i-1);
3051  QPointF delta = e - a;
3052  return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
3053  }
3054  break;
3055  }
3057  {
3058  QBezier b = QBezier::fromPoints(path.elementAt(i-1),
3059  e,
3060  path.elementAt(i+1),
3061  path.elementAt(i+2));
3062  qreal blen = b.length();
3063  curLen += blen;
3064 
3065  if (i + 2 == lastElement || curLen/totalLength >= t) {
3066  *bezierLength = blen;
3067  return b;
3068  }
3069 
3070  i += 2;
3071  break;
3072  }
3073  default:
3074  break;
3075  }
3076  *startingLength = curLen;
3077  }
3078  return QBezier();
3079 }
3080 
3091 {
3092  if (t < 0 || t > 1) {
3093  qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
3094  return QPointF();
3095  }
3096 
3097  if (!d_ptr || d_ptr->elements.size() == 0)
3098  return QPointF();
3099 
3100  if (d_ptr->elements.size() == 1)
3101  return d_ptr->elements.at(0);
3102 
3103  qreal totalLength = length();
3104  qreal curLen = 0;
3105  qreal bezierLen = 0;
3106  QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
3107  qreal realT = (totalLength * t - curLen) / bezierLen;
3108 
3109  return b.pointAt(qBound(qreal(0), realT, qreal(1)));
3110 }
3111 
3125 {
3126  if (t < 0 || t > 1) {
3127  qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
3128  return 0;
3129  }
3130 
3131  qreal totalLength = length();
3132  qreal curLen = 0;
3133  qreal bezierLen = 0;
3134  QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3135  qreal realT = (totalLength * t - curLen) / bezierLen;
3136 
3137  qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3138  qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3139 
3140  return QLineF(0, 0, m1, m2).angle();
3141 }
3142 
3143 #if defined(Q_WS_WINCE)
3144 #pragma warning( disable : 4056 4756 )
3145 #endif
3146 
3157 {
3158  if (t < 0 || t > 1) {
3159  qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3160  return 0;
3161  }
3162 
3163  qreal totalLength = length();
3164  qreal curLen = 0;
3165  qreal bezierLen = 0;
3166  QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3167  qreal realT = (totalLength * t - curLen) / bezierLen;
3168 
3169  qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3170  qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3171  //tangent line
3172  qreal slope = 0;
3173 
3174 #define SIGN(x) ((x < 0)?-1:1)
3175  if (m1)
3176  slope = m2/m1;
3177  else {
3178  //windows doesn't define INFINITY :(
3179 #ifdef INFINITY
3180  slope = INFINITY*SIGN(m2);
3181 #else
3182  if (sizeof(qreal) == sizeof(double)) {
3183  return 1.79769313486231570e+308;
3184  } else {
3185  return ((qreal)3.40282346638528860e+38);
3186  }
3187 #endif
3188  }
3189 
3190  return slope;
3191 }
3192 
3209 void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
3210  Qt::SizeMode mode)
3211 {
3212  QRectF r = rect.normalized();
3213 
3214  if (r.isNull())
3215  return;
3216 
3217  if (mode == Qt::AbsoluteSize) {
3218  qreal w = r.width() / 2;
3219  qreal h = r.height() / 2;
3220 
3221  if (w == 0) {
3222  xRadius = 0;
3223  } else {
3224  xRadius = 100 * qMin(xRadius, w) / w;
3225  }
3226  if (h == 0) {
3227  yRadius = 0;
3228  } else {
3229  yRadius = 100 * qMin(yRadius, h) / h;
3230  }
3231  } else {
3232  if (xRadius > 100) // fix ranges
3233  xRadius = 100;
3234 
3235  if (yRadius > 100)
3236  yRadius = 100;
3237  }
3238 
3239  if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3240  addRect(r);
3241  return;
3242  }
3243 
3244  qreal x = r.x();
3245  qreal y = r.y();
3246  qreal w = r.width();
3247  qreal h = r.height();
3248  qreal rxx2 = w*xRadius/100;
3249  qreal ryy2 = h*yRadius/100;
3250 
3251  ensureData();
3252  detach();
3253 
3254  bool first = d_func()->elements.size() < 2;
3255 
3256  arcMoveTo(x, y, rxx2, ryy2, 180);
3257  arcTo(x, y, rxx2, ryy2, 180, -90);
3258  arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3259  arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3260  arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3261  closeSubpath();
3262 
3263  d_func()->require_moveTo = true;
3264  d_func()->convex = first;
3265 }
3266 
3291 void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3292 {
3293  if(xRnd >= 100) // fix ranges
3294  xRnd = 99;
3295  if(yRnd >= 100)
3296  yRnd = 99;
3297  if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3298  addRect(r);
3299  return;
3300  }
3301 
3302  QRectF rect = r.normalized();
3303 
3304  if (rect.isNull())
3305  return;
3306 
3307  qreal x = rect.x();
3308  qreal y = rect.y();
3309  qreal w = rect.width();
3310  qreal h = rect.height();
3311  qreal rxx2 = w*xRnd/100;
3312  qreal ryy2 = h*yRnd/100;
3313 
3314  ensureData();
3315  detach();
3316 
3317  bool first = d_func()->elements.size() < 2;
3318 
3319  arcMoveTo(x, y, rxx2, ryy2, 180);
3320  arcTo(x, y, rxx2, ryy2, 180, -90);
3321  arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3322  arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3323  arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3324  closeSubpath();
3325 
3326  d_func()->require_moveTo = true;
3327  d_func()->convex = first;
3328 }
3329 
3408 {
3409  if (isEmpty() || p.isEmpty())
3410  return isEmpty() ? p : *this;
3411  QPathClipper clipper(*this, p);
3412  return clipper.clip(QPathClipper::BoolOr);
3413 }
3414 
3426 {
3427  if (isEmpty() || p.isEmpty())
3428  return QPainterPath();
3429  QPathClipper clipper(*this, p);
3430  return clipper.clip(QPathClipper::BoolAnd);
3431 }
3432 
3447 {
3448  if (isEmpty() || p.isEmpty())
3449  return *this;
3450  QPathClipper clipper(*this, p);
3451  return clipper.clip(QPathClipper::BoolSub);
3452 }
3453 
3466 {
3467  return p.subtracted(*this);
3468 }
3469 
3483 {
3484  if(isEmpty())
3485  return *this;
3486  QPathClipper clipper(*this, QPainterPath());
3487  return clipper.clip(QPathClipper::Simplify);
3488 }
3489 
3505 {
3506  if (p.elementCount() == 1)
3507  return contains(p.elementAt(0));
3508  if (isEmpty() || p.isEmpty())
3509  return false;
3510  QPathClipper clipper(*this, p);
3511  return clipper.intersect();
3512 }
3513 
3530 {
3531  if (p.elementCount() == 1)
3532  return contains(p.elementAt(0));
3533  if (isEmpty() || p.isEmpty())
3534  return false;
3535  QPathClipper clipper(*this, p);
3536  return clipper.contains();
3537 }
3538 
3539 void QPainterPath::setDirty(bool dirty)
3540 {
3541  d_func()->dirtyBounds = dirty;
3542  d_func()->dirtyControlBounds = dirty;
3543  delete d_func()->pathConverter;
3544  d_func()->pathConverter = 0;
3545  d_func()->convex = false;
3546 }
3547 
3549 {
3550  QPainterPathData *d = d_func();
3551  d->dirtyBounds = false;
3552  if (!d_ptr) {
3553  d->bounds = QRect();
3554  return;
3555  }
3556 
3557  qreal minx, maxx, miny, maxy;
3558  minx = maxx = d->elements.at(0).x;
3559  miny = maxy = d->elements.at(0).y;
3560  for (int i=1; i<d->elements.size(); ++i) {
3561  const Element &e = d->elements.at(i);
3562 
3563  switch (e.type) {
3564  case MoveToElement:
3565  case LineToElement:
3566  if (e.x > maxx) maxx = e.x;
3567  else if (e.x < minx) minx = e.x;
3568  if (e.y > maxy) maxy = e.y;
3569  else if (e.y < miny) miny = e.y;
3570  break;
3571  case CurveToElement:
3572  {
3573  QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3574  e,
3575  d->elements.at(i+1),
3576  d->elements.at(i+2));
3578  qreal right = r.right();
3579  qreal bottom = r.bottom();
3580  if (r.x() < minx) minx = r.x();
3581  if (right > maxx) maxx = right;
3582  if (r.y() < miny) miny = r.y();
3583  if (bottom > maxy) maxy = bottom;
3584  i += 2;
3585  }
3586  break;
3587  default:
3588  break;
3589  }
3590  }
3591  d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3592 }
3593 
3594 
3596 {
3597  QPainterPathData *d = d_func();
3598  d->dirtyControlBounds = false;
3599  if (!d_ptr) {
3600  d->controlBounds = QRect();
3601  return;
3602  }
3603 
3604  qreal minx, maxx, miny, maxy;
3605  minx = maxx = d->elements.at(0).x;
3606  miny = maxy = d->elements.at(0).y;
3607  for (int i=1; i<d->elements.size(); ++i) {
3608  const Element &e = d->elements.at(i);
3609  if (e.x > maxx) maxx = e.x;
3610  else if (e.x < minx) minx = e.x;
3611  if (e.y > maxy) maxy = e.y;
3612  else if (e.y < miny) miny = e.y;
3613  }
3614  d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3615 }
3616 
3617 #ifndef QT_NO_DEBUG_STREAM
3619 {
3620  s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl;
3621  const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3622  for (int i=0; i<p.elementCount(); ++i) {
3623  s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl;
3624 
3625  }
3626  return s;
3627 }
3628 #endif
3629 
ElementType type
the type of element
Definition: qpainterpath.h:81
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:62
virtual QFixed lineThickness() const
void setDashOffset(qreal offset)
Sets the dash offset for the generated outlines to offset.
double d
Definition: qnumeric_p.h:62
QPointF bottomRight() const
Returns the position of the rectangle&#39;s bottom-right corner.
Definition: qrect.h:540
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:77
QTextEngine * engine() const
Definition: qtextlayout.h:180
QPointF pt4() const
Definition: qbezier_p.h:97
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
Definition: qpainterpath.h:392
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
Definition: qpainterpath.h:70
void setClipRect(const QRectF &clip)
Definition: qstroker_p.h:165
void addRoundRect(const QRectF &rect, int xRnd, int yRnd)
Adds a rectangle r with rounded corners to the path.
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
qreal right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:527
#define qt_real_to_fixed(real)
Definition: qstroker_p.h:101
void addPath(const QPainterPath &path)
Adds the given path to this path as a closed subpath.
int type
Definition: qmetatype.cpp:239
static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth=0)
static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect)
qreal miterLimit() const
Returns the miter limit for the generated outlines.
double qreal
Definition: qglobal.h:1193
#define QT_BEZIER_B(bezier, coord)
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void addRegion(const QRegion &region)
Adds the given region to the path by adding each rectangle in the region as a separate closed subpath...
static QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, int *winding, int depth=0)
void translate(qreal dx, qreal dy)
Translates all elements in the path by ({dx}, {dy}).
qreal length() const
Returns the length of the line.
Definition: qline.cpp:698
QPainterPath & operator|=(const QPainterPath &other)
Unites this path with other and returns a reference to this path.
static qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
The QMatrix class specifies 2D transformations of a coordinate system.
Definition: qmatrix.h:61
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
void setDashOffset(qreal offset)
Definition: qstroker_p.h:265
QDebug & nospace()
Clears the stream&#39;s internal flag that records whether the last character was a space and returns a r...
Definition: qdebug.h:92
int qFloor(qreal v)
Definition: qmath.h:73
qreal width() const
Returns the width.
Definition: qsize.h:284
qreal x2
Definition: qbezier_p.h:116
void addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
Adds the given rectangle rect with rounded corners to the path.
T & first()
Returns a reference to the first item in the vector.
Definition: qvector.h:260
qreal width() const
Returns the width of the generated outlines.
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
qreal height() const
Returns the height.
Definition: qsize.h:287
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
FillRule
Definition: qnamespace.h:1485
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
The QTextLine class represents a line of text inside a QTextLayout.
Definition: qtextlayout.h:197
QPainterPath subtracted(const QPainterPath &r) const
Returns a path which is p&#39;s fill area subtracted from this path&#39;s fill area.
QPainterPath operator|(const QPainterPath &other) const
Returns the union of this path and the other path.
QPainterPath intersected(const QPainterPath &r) const
Returns a path which is the intersection of this path&#39;s fill area and p&#39;s fill area.
QPointF topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:539
static void coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal &d)
Definition: qbezier_p.h:152
QScriptItemArray items
static Q_DECL_CONSTEXPR bool qFuzzyCompare(double p1, double p2)
Definition: qglobal.h:2030
qreal dashOffset() const
Returns the dash offset for the generated outlines.
#define QT_PATH_KAPPA
Definition: qstroker_p.h:113
long ASN1_INTEGER_get ASN1_INTEGER * a
QPointF pointAt(qreal t) const
Definition: qbezier_p.h:163
bool intersects(const QRectF &rect) const
Returns true if any point in the given rectangle intersects the path; otherwise returns false...
QPointF bottomLeft() const
Returns the position of the rectangle&#39;s bottom-left corner.
Definition: qrect.h:542
bool ref()
Atomically increments the value of this QAtomicInt.
void addPolygon(const QPolygonF &polygon)
Adds the given polygon to the path as an (unclosed) subpath.
bool intersects(const QRectF &r) const
Returns true if this rectangle intersects with the given rectangle (i.
Definition: qrect.cpp:2744
LayoutData * layoutData
qreal y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
QPointF pt1() const
Definition: qbezier_p.h:94
void setDashPattern(const QVector< qfixed > &dashPattern)
Definition: qstroker_p.h:262
void computeBoundingRect() const
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
QRectF boundingRect() const
Returns the bounding rectangle of the polygon, or QRectF(0,0,0,0) if the polygon is empty...
Definition: qpolygon.cpp:742
static void qt_painterpath_isect_line(const QPointF &p1, const QPointF &p2, const QPointF &pos, int *winding)
qreal length(qreal error=0.01) const
Definition: qbezier.cpp:529
#define Q_D(Class)
Definition: qglobal.h:2482
qreal slopeAtPercent(qreal t) const
Returns the slope of the path at the percentage t.
The QSizeF class defines the size of a two-dimensional object using floating point precision...
Definition: qsize.h:202
void detach_helper()
void arcMoveTo(const QRectF &rect, qreal angle)
Creates a move to that lies on the arc that occupies the given rectangle at angle.
void setMiterLimit(qreal length)
Sets the miter limit of the generated outlines to limit.
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
PenStyle
Definition: qnamespace.h:1134
QList< QPolygonF > toFillPolygons(const QMatrix &matrix=QMatrix()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal y2
Definition: qbezier_p.h:116
#define QT_BEZIER_CHECK_T(bezier, t)
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition: qstroker_p.h:150
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
qreal x4
Definition: qbezier_p.h:116
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
PenCapStyle
Definition: qnamespace.h:1147
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision...
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
QPainterPathStroker()
Creates a new stroker.
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
QPainterPath & operator+=(const QPainterPath &other)
Unites this path with other, and returns a reference to this path.
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
Q_CORE_EXPORT void qDebug(const char *,...)
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
uint overline
Definition: qfont_p.h:189
bool contains(const QPointF &p) const
Returns true if the given point is inside or on the edge of the rectangle; otherwise returns false...
Definition: qrect.cpp:2349
QVector< qfixed > dashPattern
static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition: qbezier.cpp:71
uint underline
Definition: qfont_p.h:188
#define QT_BEZIER_A(bezier, coord)
qreal qt_t_for_arc_angle(qreal angle)
Definition: qstroker.cpp:796
QTextStream & right(QTextStream &stream)
Calls QTextStream::setFieldAlignment(QTextStream::AlignRight) on stream and returns stream...
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
qreal & rx()
Returns a reference to the x coordinate of this point.
Definition: qpoint.h:302
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
void strokePath(const QPainterPath &path, void *data, const QTransform &matrix)
Convenience function that decomposes path into begin(), moveTo(), lineTo(), curevTo() and end() calls...
Definition: qstroker.cpp:242
void ensureData()
Definition: qpainterpath.h:213
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path...
static bool isEmpty(const char *str)
bool operator!=(const QPainterPath &other) const
Returns true if this painter path differs from the given path.
QPainterPath()
Constructs an empty QPainterPath object.
QPainterPathData * d_func() const
Definition: qpainterpath.h:221
QPolygonF toFillPolygon(const QMatrix &matrix=QMatrix()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
friend class QPainterPathData
Definition: qpainterpath.h:223
~QPainterPath()
Destroys this QPainterPath object.
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
void setCurveThreshold(qreal threshold)
Specifies the curve flattening threshold, controlling the granularity with which the generated outlin...
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
QRectF clipRect() const
Definition: qstroker_p.h:164
void connectPath(const QPainterPath &path)
Connects the given path to this path by adding a line from the last element of this path to the first...
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
friend Q_GUI_EXPORT QDataStream & operator>>(QDataStream &, QPainterPath &)
Reads a painter path from the given stream into the specified path, and returns a reference to the st...
QGlyphLayout shapedGlyphs(const QScriptItem *si) const
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
bool deref()
Atomically decrements the value of this QAtomicInt.
virtual QFixed ascent() const =0
const char * layout
unsigned short bidiLevel
The QPolygonF class provides a vector of points using floating point precision.
Definition: qpolygon.h:134
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
QPainterPath operator &(const QPainterPath &other) const
qreal percentAtLength(qreal t) const
Returns percentage of the whole path at the specified length len.
QPainterPath & operator=(const QPainterPath &other)
Assigns the given path to this painter path.
Q_CORE_EXPORT void qWarning(const char *,...)
qreal angle() const
Returns the angle of the line in degrees.
Definition: qline.cpp:719
static void cleanup(QPainterPathPrivate *d)
qreal angleAtPercent(qreal t) const
Returns the angle of the path tangent at the percentage t.
static const char * data(const QByteArray &arr)
QPointF pointAtPercent(qreal t) const
Returns the point at at the percentage t of the current path.
friend class QTransform
Definition: qpainterpath.h:227
QScopedPointer< QPainterPathStrokerPrivate > d_ptr
Definition: qpainterpath.h:300
static bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
The QRegion class specifies a clip region for a painter.
Definition: qregion.h:68
The QPainterPathStroker class is used to generate fillable outlines for a given painter path...
Definition: qpainterpath.h:264
qreal tAtLength(qreal len) const
Definition: qbezier.cpp:654
PenJoinStyle
Definition: qnamespace.h:1154
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.
QScriptLineArray lines
void setDirty(bool)
QPainterPath simplified() const
Returns a simplified version of this path.
qreal y4
Definition: qbezier_p.h:116
void reset(T *other=0)
Deletes the existing object it is pointing to if any, and sets its pointer to other.
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
QFontEngine * engineForScript(int script) const
Definition: qfont.cpp:294
#define qt_fixed_to_real(fixed)
Definition: qstroker_p.h:102
unsigned short flags
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
friend Q_GUI_EXPORT QDataStream & operator<<(QDataStream &, const QPainterPath &)
Writes the given painter path to the given stream, and returns a reference to the stream...
~QPainterPathStroker()
Destroys the stroker.
QPainterPath operator-(const QPainterPath &other) const
Subtracts the other path from a copy of this path, and returns the copy.
QRectF bounds() const
Definition: qbezier.cpp:223
qreal angle(const QPointF &p1, const QPointF &p2)
The QTextLayout class is used to lay out and render text.
Definition: qtextlayout.h:105
unsigned short script
Qt::FillRule fillRule
QVector< qreal > dashPattern() const
Returns the dash pattern for the generated outlines.
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
static const struct @32 types[]
void ensureData_helper()
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
QPainterPath united(const QPainterPath &r) const
Returns a path which is the union of this path&#39;s fill area and p&#39;s fill area.
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
void arcTo(const QRectF &rect, qreal startAngle, qreal arcLength)
Creates an arc that occupies the given rectangle, beginning at the specified startAngle and extending...
void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)
void addText(const QPointF &point, const QFont &f, const QString &text)
Adds the given text to this path as a set of closed subpaths created from the font supplied...
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
QExplicitlySharedDataPointer< QFontPrivate > d
Definition: qfont.h:343
QVector< QRect > rects() const
Returns an array of non-overlapping rectangles that make up the region.
Definition: qregion.cpp:4412
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
qreal length() const
Returns the length of the current path.
qreal x3
Definition: qbezier_p.h:116
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
Qt::PenJoinStyle joinStyle() const
Returns the join style of the generated outlines.
QVector< QPainterPath::Element > elements
Definition: qpainterpath.h:254
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QDataStream & operator<<(QDataStream &s, const QPainterPath &p)
qreal x1
Definition: qbezier_p.h:116
qreal toReal() const
Definition: qfixed_p.h:77
QPainterPath toReversed() const
Creates and returns a reversed copy of the path.
void split(QBezier *firstHalf, QBezier *secondHalf) const
Definition: qbezier_p.h:224
QSizeF size() const
Returns the size of the rectangle.
Definition: qrect.h:713
qreal & ry()
Returns a reference to the y coordinate of this point.
Definition: qpoint.h:307
signed int length
void quadTo(const QPointF &ctrlPt, const QPointF &endPt)
Adds a quadratic Bezier curve between the current position and the given endPoint with the control po...
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
static const QTextHtmlElement elements[Html_NumElements]
qreal y1
Definition: qbezier_p.h:116
QPainterPath & operator &=(const QPainterPath &other)
QList< QPolygonF > toSubpathPolygons(const QMatrix &matrix=QMatrix()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
void setLineToHook(qStrokerLineToHook lineToHook)
Definition: qstroker_p.h:149
QPainterPath operator+(const QPainterPath &other) const
Returns the union of this path and the other path.
bool isEmpty() const
Returns true if the vector has size 0; otherwise returns false.
Definition: qvector.h:139
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:71
void setCacheEnabled(bool enable)
Enables caching of the complete layout information if enable is true; otherwise disables layout cachi...
void reserve(int size)
Attempts to allocate memory for at least size elements.
Definition: qvector.h:339
bool isClosed() const
Returns true if the polygon is closed; otherwise returns false.
Definition: qpolygon.h:154
SizeMode
Definition: qnamespace.h:1187
void endLayout()
Ends the layout process.
qreal bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:528
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Creates a number of curves for a given arc definition.
Definition: qstroker.cpp:859
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition: qstroker_p.h:148
bool isClosed() const
Qt::PenCapStyle capStyle() const
Returns the cap style of the generated outlines.
QPointF topRight() const
Returns the position of the rectangle&#39;s top-right corner.
Definition: qrect.h:541
QRectF normalized() const
Returns a normalized rectangle; i.e., a rectangle that has a non-negative width and height...
Definition: qrect.cpp:1822
qreal & rheight()
Returns a reference to the height.
Definition: qsize.h:302
QPointF currentPosition() const
Returns the current position of the path.
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
QPointF center() const
Returns the center point of the rectangle.
Definition: qrect.h:686
qreal y3
Definition: qbezier_p.h:116
QPainterPath subtractedInverted(const QPainterPath &r) const
Use subtracted() instead.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
qreal qSqrt(qreal v)
Definition: qmath.h:205
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:655
qreal qfixed
Definition: qstroker_p.h:100
#define SIGN(x)
bool operator==(const QPainterPath &other) const
Returns true if this painterpath is equal to the given path.
qreal & rwidth()
Returns a reference to the width.
Definition: qsize.h:299
QPainterPath & operator-=(const QPainterPath &other)
Subtracts other from this path, and returns a reference to this path.
virtual QFixed underlinePosition() const
static bool qt_is_finite(double d)
Definition: qnumeric_p.h:197
static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth=0)
void beginLayout()
Begins the layout process.
QPainterPath clip(Operation op=BoolAnd)
QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount)
uint strikeOut
Definition: qfont_p.h:190
void addEllipse(const QRectF &rect)
Creates an ellipse within the specified boundingRectangle and adds it to the painter path as a closed...
#define text
Definition: qobjectdefs.h:80
#define QT_BEZIER_C(bezier, coord)
QScopedPointer< QPainterPathPrivate, QPainterPathPrivateDeleter > d_ptr
Definition: qpainterpath.h:211
void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
void computeControlPointRect() const
static QVector< qfixed > patternForStyle(Qt::PenStyle style)
Definition: qstroker.cpp:1034
QPainterPath translated(qreal dx, qreal dy) const
Returns a copy of the path that is translated by ({dx}, {dy}).
QScriptAnalysis analysis
qreal curveThreshold() const
Returns the curve flattening threshold for the generated outlines.
Q_CORE_EXPORT QTextStream & endl(QTextStream &s)