Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpainterpath.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpainterpath.h"
5#include "qpainterpath_p.h"
6
7#include <qbitmap.h>
8#include <qdebug.h>
9#include <qiodevice.h>
10#include <qlist.h>
11#include <qpen.h>
12#include <qpolygon.h>
13#include <qtextlayout.h>
14#include <qvarlengtharray.h>
15#include <qmath.h>
16
17#include <private/qbezier_p.h>
18#include <private/qfontengine_p.h>
19#include <private/qnumeric_p.h>
20#include <private/qobject_p.h>
21#include <private/qpathclipper_p.h>
22#include <private/qstroker_p.h>
23#include <private/qtextengine_p.h>
24
25#include <limits.h>
26
27#if 0
28#include <performance.h>
29#else
30#define PM_INIT
31#define PM_MEASURE(x)
32#define PM_DISPLAY
33#endif
34
36
37static inline bool isValidCoord(qreal c)
38{
39 if (sizeof(qreal) >= sizeof(double))
40 return qIsFinite(c) && fabs(c) < 1e128;
41 else
42 return qIsFinite(c) && fabsf(float(c)) < 1e16f;
43}
44
46{
47 return isValidCoord(p.x()) && isValidCoord(p.y());
48}
49
51{
52 return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
53}
54
55// This value is used to determine the length of control point vectors
56// when approximating arc segments as curves. The factor is multiplied
57// with the radius of the circle.
58
59// #define QPP_DEBUG
60// #define QPP_STROKE_DEBUG
61//#define QPP_FILLPOLYGONS_DEBUG
62
64
66 QPointF* startPoint, QPointF *endPoint)
67{
68 if (r.isNull()) {
69 if (startPoint)
70 *startPoint = QPointF();
71 if (endPoint)
72 *endPoint = QPointF();
73 return;
74 }
75
76 qreal w2 = r.width() / 2;
77 qreal h2 = r.height() / 2;
78
79 qreal angles[2] = { angle, angle + length };
80 QPointF *points[2] = { startPoint, endPoint };
81
82 for (int i = 0; i < 2; ++i) {
83 if (!points[i])
84 continue;
85
86 qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
87 qreal t = theta / 90;
88 // truncate
89 int quadrant = int(t);
90 t -= quadrant;
91
92 t = qt_t_for_arc_angle(90 * t);
93
94 // swap x and y?
95 if (quadrant & 1)
96 t = 1 - t;
97
98 qreal a, b, c, d;
101
102 // left quadrants
103 if (quadrant == 1 || quadrant == 2)
104 p.rx() = -p.x();
105
106 // top quadrants
107 if (quadrant == 0 || quadrant == 1)
108 p.ry() = -p.y();
109
110 *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
111 }
112}
113
114#ifdef QPP_DEBUG
115static void qt_debug_path(const QPainterPath &path)
116{
117 const char *names[] = {
118 "MoveTo ",
119 "LineTo ",
120 "CurveTo ",
121 "CurveToData"
122 };
123
124 printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
125 for (int i=0; i<path.elementCount(); ++i) {
126 const QPainterPath::Element &e = path.elementAt(i);
128 printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
129 }
130}
131#endif
132
452{
453 return d_ptr ? d_ptr->elements.size() : 0;
454}
455
465{
466 Q_ASSERT(d_ptr);
467 Q_ASSERT(i >= 0 && i < elementCount());
468 return d_ptr->elements.at(i);
469}
470
480{
481 Q_ASSERT(d_ptr);
482 Q_ASSERT(i >= 0 && i < elementCount());
483 detach();
484 QPainterPath::Element &e = d_ptr->elements[i];
485 e.x = x;
486 e.y = y;
487}
488
489
490/*###
491 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
492
493 Appends the \a other painter path to this painter path and returns a
494 reference to the result.
495*/
496
501 : d_ptr(nullptr)
502{
503}
504
513
520 : d_ptr(new QPainterPathPrivate(startPoint))
521{
522}
523
524void QPainterPath::detach()
525{
526 d_ptr.detach();
527 setDirty(true);
528}
529
533void QPainterPath::ensureData_helper()
534{
536 data->elements.reserve(16);
538 data->elements << e;
539 d_ptr.reset(data);
540 Q_ASSERT(d_ptr != nullptr);
541}
542
551{
553 swap(copy);
554 return *this;
555}
556
579
589{
590 if (!d_ptr)
591 return;
592
593 detach();
594 d_func()->clear();
595 d_func()->elements.append( {0, 0, MoveToElement} );
596}
597
607{
608 Q_D(QPainterPath);
609 if ((!d && size > 0) || (d && d->elements.capacity() < size)) {
610 ensureData();
611 detach();
612 d_func()->elements.reserve(size);
613 }
614}
615
623{
624 Q_D(QPainterPath);
625 if (d)
626 return d->elements.capacity();
627
628 return 0;
629}
630
643{
644#ifdef QPP_DEBUG
645 printf("QPainterPath::closeSubpath()\n");
646#endif
647 if (isEmpty())
648 return;
649 detach();
650
651 d_func()->close();
652}
653
673{
674#ifdef QPP_DEBUG
675 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
676#endif
677
678 if (!hasValidCoords(p)) {
679#ifndef QT_NO_DEBUG
680 qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call");
681#endif
682 return;
683 }
684
685 ensureData();
686 detach();
687
688 QPainterPathPrivate *d = d_func();
689 Q_ASSERT(!d->elements.isEmpty());
690
691 d->require_moveTo = false;
692
693 if (d->elements.constLast().type == MoveToElement) {
694 d->elements.last().x = p.x();
695 d->elements.last().y = p.y();
696 } else {
697 Element elm = { p.x(), p.y(), MoveToElement };
698 d->elements.append(elm);
699 }
700 d->cStart = d->elements.size() - 1;
701}
702
723{
724#ifdef QPP_DEBUG
725 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
726#endif
727
728 if (!hasValidCoords(p)) {
729#ifndef QT_NO_DEBUG
730 qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call");
731#endif
732 return;
733 }
734
735 ensureData();
736 detach();
737
738 QPainterPathPrivate *d = d_func();
739 Q_ASSERT(!d->elements.isEmpty());
740 d->maybeMoveTo();
741 if (p == QPointF(d->elements.constLast()))
742 return;
743 Element elm = { p.x(), p.y(), LineToElement };
744 d->elements.append(elm);
745
746 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
747}
748
780void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
781{
782#ifdef QPP_DEBUG
783 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
784 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
785#endif
786
787 if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) {
788#ifndef QT_NO_DEBUG
789 qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call");
790#endif
791 return;
792 }
793
794 ensureData();
795 detach();
796
797 QPainterPathPrivate *d = d_func();
798 Q_ASSERT(!d->elements.isEmpty());
799
800
801 // Abort on empty curve as a stroker cannot handle this and the
802 // curve is irrelevant anyway.
803 if (d->elements.constLast() == c1 && c1 == c2 && c2 == e)
804 return;
805
806 d->maybeMoveTo();
807
808 Element ce1 = { c1.x(), c1.y(), CurveToElement };
809 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
810 Element ee = { e.x(), e.y(), CurveToDataElement };
811 d->elements << ce1 << ce2 << ee;
812}
813
836void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
837{
838#ifdef QPP_DEBUG
839 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
840 c.x(), c.y(), e.x(), e.y());
841#endif
842
843 if (!hasValidCoords(c) || !hasValidCoords(e)) {
844#ifndef QT_NO_DEBUG
845 qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call");
846#endif
847 return;
848 }
849
850 ensureData();
851 detach();
852
853 Q_D(QPainterPath);
854 Q_ASSERT(!d->elements.isEmpty());
855 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
856 QPointF prev(elm.x, elm.y);
857
858 // Abort on empty curve as a stroker cannot handle this and the
859 // curve is irrelevant anyway.
860 if (prev == c && c == e)
861 return;
862
863 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
864 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
865 cubicTo(c1, c2, e);
866}
867
907void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
908{
909#ifdef QPP_DEBUG
910 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
911 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
912#endif
913
914 if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) {
915#ifndef QT_NO_DEBUG
916 qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call");
917#endif
918 return;
919 }
920
921 if (rect.isNull())
922 return;
923
924 ensureData();
925 detach();
926
927 int point_count;
928 QPointF pts[15];
929 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
930
931 lineTo(curve_start);
932 for (int i=0; i<point_count; i+=3) {
933 cubicTo(pts[i].x(), pts[i].y(),
934 pts[i+1].x(), pts[i+1].y(),
935 pts[i+2].x(), pts[i+2].y());
936 }
937
938}
939
940
965{
966 if (rect.isNull())
967 return;
968
969 QPointF pt;
970 qt_find_ellipse_coords(rect, angle, 0, &pt, nullptr);
971 moveTo(pt);
972}
973
974
975
982{
983 return !d_ptr || d_func()->elements.isEmpty()
984 ? QPointF()
985 : QPointF(d_func()->elements.constLast().x, d_func()->elements.constLast().y);
986}
987
988
1018{
1019 if (!hasValidCoords(r)) {
1020#ifndef QT_NO_DEBUG
1021 qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call");
1022#endif
1023 return;
1024 }
1025
1026 if (r.isNull())
1027 return;
1028
1029 ensureData();
1030 detach();
1031
1032 bool first = d_func()->elements.size() < 2;
1033
1034 moveTo(r.x(), r.y());
1035
1036 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1037 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1038 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1039 Element l4 = { r.x(), r.y(), LineToElement };
1040
1041 d_func()->elements << l1 << l2 << l3 << l4;
1042 d_func()->require_moveTo = true;
1043 d_func()->convex = first;
1044}
1045
1064{
1065 if (polygon.isEmpty())
1066 return;
1067
1068 ensureData();
1069 detach();
1070
1071 moveTo(polygon.constFirst());
1072 for (int i=1; i<polygon.size(); ++i) {
1073 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1074 d_func()->elements << elm;
1075 }
1076}
1077
1098{
1100#ifndef QT_NO_DEBUG
1101 qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call");
1102#endif
1103 return;
1104 }
1105
1106 if (boundingRect.isNull())
1107 return;
1108
1109 ensureData();
1110 detach();
1111
1112 bool first = d_func()->elements.size() < 2;
1113
1114 QPointF pts[12];
1115 int point_count;
1116 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1117
1118 moveTo(start);
1119 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1120 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1121 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1122 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1123 d_func()->require_moveTo = true;
1124
1125 d_func()->convex = first;
1126}
1127
1149void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1150{
1151 if (text.isEmpty())
1152 return;
1153
1154 ensureData();
1155 detach();
1156
1158 layout.setCacheEnabled(true);
1159
1160 QTextOption opt = layout.textOption();
1161 opt.setUseDesignMetrics(true);
1162 layout.setTextOption(opt);
1163
1164 QTextEngine *eng = layout.engine();
1165 layout.beginLayout();
1166 QTextLine line = layout.createLine();
1167 Q_UNUSED(line);
1168 layout.endLayout();
1169 const QScriptLine &sl = eng->lines[0];
1170 if (!sl.length || !eng->layoutData)
1171 return;
1172
1173 int nItems = eng->layoutData->items.size();
1174
1175 qreal x(point.x());
1176 qreal y(point.y());
1177
1178 QVarLengthArray<int> visualOrder(nItems);
1179 QVarLengthArray<uchar> levels(nItems);
1180 for (int i = 0; i < nItems; ++i)
1182 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1183
1184 for (int i = 0; i < nItems; ++i) {
1185 int item = visualOrder[i];
1186 const QScriptItem &si = eng->layoutData->items.at(item);
1187
1189 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1190 QFontEngine *fe = eng->fontEngine(si);
1191 Q_ASSERT(fe);
1192 fe->addOutlineToPath(x, y, glyphs, this,
1193 si.analysis.bidiLevel % 2
1194 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1195 : QTextItem::RenderFlags{});
1196
1197 const qreal lw = fe->lineThickness().toReal();
1198 if (f.d->underline) {
1199 qreal pos = fe->underlinePosition().toReal();
1200 addRect(x, y + pos, si.width.toReal(), lw);
1201 }
1202 if (f.d->overline) {
1203 qreal pos = fe->ascent().toReal() + 1;
1204 addRect(x, y - pos, si.width.toReal(), lw);
1205 }
1206 if (f.d->strikeOut) {
1207 qreal pos = fe->ascent().toReal() / 3;
1208 addRect(x, y - pos, si.width.toReal(), lw);
1209 }
1210 }
1211 x += si.width.toReal();
1212 }
1213}
1214
1224{
1225 if (other.isEmpty())
1226 return;
1227
1228 ensureData();
1229 detach();
1230
1231 QPainterPathPrivate *d = d_func();
1232 // Remove last moveto so we don't get multiple moveto's
1233 if (d->elements.constLast().type == MoveToElement)
1234 d->elements.remove(d->elements.size()-1);
1235
1236 // Locate where our own current subpath will start after the other path is added.
1237 int cStart = d->elements.size() + other.d_func()->cStart;
1238 d->elements += other.d_func()->elements;
1239 d->cStart = cStart;
1240
1241 d->require_moveTo = other.d_func()->isClosed();
1242}
1243
1244
1255{
1256 if (other.isEmpty())
1257 return;
1258
1259 ensureData();
1260 detach();
1261
1262 QPainterPathPrivate *d = d_func();
1263 // Remove last moveto so we don't get multiple moveto's
1264 if (d->elements.constLast().type == MoveToElement)
1265 d->elements.remove(d->elements.size()-1);
1266
1267 // Locate where our own current subpath will start after the other path is added.
1268 int cStart = d->elements.size() + other.d_func()->cStart;
1269 int first = d->elements.size();
1270 d->elements += other.d_func()->elements;
1271
1272 if (first != 0)
1273 d->elements[first].type = LineToElement;
1274
1275 // avoid duplicate points
1276 if (first > 0 && QPointF(d->elements.at(first)) == QPointF(d->elements.at(first - 1))) {
1277 d->elements.remove(first--);
1278 --cStart;
1279 }
1280
1281 if (cStart != first)
1282 d->cStart = cStart;
1283}
1284
1293{
1294 ensureData();
1295 detach();
1296
1297 for (const QRect &rect : region)
1298 addRect(rect);
1299}
1300
1301
1308{
1309 return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
1310}
1311
1330{
1331 ensureData();
1332 if (d_func()->fillRule == fillRule)
1333 return;
1334 detach();
1335
1336 d_func()->fillRule = fillRule;
1337}
1338
1339#define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1340 + 3*bezier.coord##2 \
1341 - 3*bezier.coord##3 \
1342 +bezier.coord##4)
1343
1344#define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1345 - 2*bezier.coord##2 \
1346 + bezier.coord##3)
1347
1348#define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1349 + bezier.coord##2)
1350
1351#define QT_BEZIER_CHECK_T(bezier, t) \
1352 if (t >= 0 && t <= 1) { \
1353 QPointF p(b.pointAt(t)); \
1354 if (p.x() < minx) minx = p.x(); \
1355 else if (p.x() > maxx) maxx = p.x(); \
1356 if (p.y() < miny) miny = p.y(); \
1357 else if (p.y() > maxy) maxy = p.y(); \
1358 }
1359
1360
1362{
1363 qreal minx, miny, maxx, maxy;
1364
1365 // initialize with end points
1366 if (b.x1 < b.x4) {
1367 minx = b.x1;
1368 maxx = b.x4;
1369 } else {
1370 minx = b.x4;
1371 maxx = b.x1;
1372 }
1373 if (b.y1 < b.y4) {
1374 miny = b.y1;
1375 maxy = b.y4;
1376 } else {
1377 miny = b.y4;
1378 maxy = b.y1;
1379 }
1380
1381 // Update for the X extrema
1382 {
1383 qreal ax = QT_BEZIER_A(b, x);
1384 qreal bx = QT_BEZIER_B(b, x);
1385 qreal cx = QT_BEZIER_C(b, x);
1386 // specialcase quadratic curves to avoid div by zero
1387 if (qFuzzyIsNull(ax)) {
1388
1389 // linear curves are covered by initialization.
1390 if (!qFuzzyIsNull(bx)) {
1391 qreal t = -cx / bx;
1393 }
1394
1395 } else {
1396 const qreal tx = bx * bx - 4 * ax * cx;
1397
1398 if (tx >= 0) {
1399 qreal temp = qSqrt(tx);
1400 qreal rcp = 1 / (2 * ax);
1401 qreal t1 = (-bx + temp) * rcp;
1403
1404 qreal t2 = (-bx - temp) * rcp;
1406 }
1407 }
1408 }
1409
1410 // Update for the Y extrema
1411 {
1412 qreal ay = QT_BEZIER_A(b, y);
1413 qreal by = QT_BEZIER_B(b, y);
1414 qreal cy = QT_BEZIER_C(b, y);
1415
1416 // specialcase quadratic curves to avoid div by zero
1417 if (qFuzzyIsNull(ay)) {
1418
1419 // linear curves are covered by initialization.
1420 if (!qFuzzyIsNull(by)) {
1421 qreal t = -cy / by;
1423 }
1424
1425 } else {
1426 const qreal ty = by * by - 4 * ay * cy;
1427
1428 if (ty > 0) {
1429 qreal temp = qSqrt(ty);
1430 qreal rcp = 1 / (2 * ay);
1431 qreal t1 = (-by + temp) * rcp;
1433
1434 qreal t2 = (-by - temp) * rcp;
1436 }
1437 }
1438 }
1439 return QRectF(minx, miny, maxx - minx, maxy - miny);
1440}
1441
1449{
1450 if (!d_ptr)
1451 return QRectF();
1452 QPainterPathPrivate *d = d_func();
1453
1454 if (d->dirtyBounds)
1455 computeBoundingRect();
1456 return d->bounds;
1457}
1458
1470{
1471 if (!d_ptr)
1472 return QRectF();
1473 QPainterPathPrivate *d = d_func();
1474
1475 if (d->dirtyControlBounds)
1476 computeControlPointRect();
1477 return d->controlBounds;
1478}
1479
1480
1491{
1492 return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.constFirst().type == MoveToElement);
1493}
1494
1504{
1505 Q_D(const QPainterPath);
1506 QPainterPath rev;
1507
1508 if (isEmpty()) {
1509 rev = *this;
1510 return rev;
1511 }
1512
1513 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1514
1515 for (int i=d->elements.size()-1; i>=1; --i) {
1516 const QPainterPath::Element &elm = d->elements.at(i);
1517 const QPainterPath::Element &prev = d->elements.at(i-1);
1518 switch (elm.type) {
1519 case LineToElement:
1520 rev.lineTo(prev.x, prev.y);
1521 break;
1522 case MoveToElement:
1523 rev.moveTo(prev.x, prev.y);
1524 break;
1525 case CurveToDataElement:
1526 {
1527 Q_ASSERT(i>=3);
1528 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1529 const QPainterPath::Element &sp = d->elements.at(i-3);
1531 Q_ASSERT(cp1.type == CurveToElement);
1532 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1533 i -= 2;
1534 break;
1535 }
1536 default:
1537 Q_ASSERT(!"qt_reversed_path");
1538 break;
1539 }
1540 }
1541 //qt_debug_path(rev);
1542 return rev;
1543}
1544
1558{
1559
1560 Q_D(const QPainterPath);
1561 QList<QPolygonF> flatCurves;
1562 if (isEmpty())
1563 return flatCurves;
1564
1565 QPolygonF current;
1566 for (int i=0; i<elementCount(); ++i) {
1567 const QPainterPath::Element &e = d->elements.at(i);
1568 switch (e.type) {
1570 if (current.size() > 1)
1571 flatCurves += current;
1572 current.clear();
1573 current.reserve(16);
1574 current += QPointF(e.x, e.y) * matrix;
1575 break;
1577 current += QPointF(e.x, e.y) * matrix;
1578 break;
1580 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1581 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1582 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1583 QPointF(e.x, e.y) * matrix,
1584 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1585 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1586 bezier.addToPolygon(&current);
1587 i+=2;
1588 break;
1589 }
1591 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1592 break;
1593 }
1594 }
1595
1596 if (current.size()>1)
1597 flatCurves += current;
1598
1599 return flatCurves;
1600}
1601
1624QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1625{
1626
1627 QList<QPolygonF> polys;
1628
1629 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1630 int count = subpaths.size();
1631
1632 if (count == 0)
1633 return polys;
1634
1635 QList<QRectF> bounds;
1636 bounds.reserve(count);
1637 for (int i=0; i<count; ++i)
1638 bounds += subpaths.at(i).boundingRect();
1639
1640#ifdef QPP_FILLPOLYGONS_DEBUG
1641 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1642 for (int i=0; i<bounds.size(); ++i)
1643 qDebug() << " bounds" << i << bounds.at(i);
1644#endif
1645
1646 QList< QList<int> > isects;
1647 isects.resize(count);
1648
1649 // find all intersections
1650 for (int j=0; j<count; ++j) {
1651 if (subpaths.at(j).size() <= 2)
1652 continue;
1653 QRectF cbounds = bounds.at(j);
1654 for (int i=0; i<count; ++i) {
1655 if (cbounds.intersects(bounds.at(i))) {
1656 isects[j] << i;
1657 }
1658 }
1659 }
1660
1661#ifdef QPP_FILLPOLYGONS_DEBUG
1662 printf("Intersections before flattening:\n");
1663 for (int i = 0; i < count; ++i) {
1664 printf("%d: ", i);
1665 for (int j = 0; j < isects[i].size(); ++j) {
1666 printf("%d ", isects[i][j]);
1667 }
1668 printf("\n");
1669 }
1670#endif
1671
1672 // flatten the sets of intersections
1673 for (int i=0; i<count; ++i) {
1674 const QList<int> &current_isects = isects.at(i);
1675 for (int j=0; j<current_isects.size(); ++j) {
1676 int isect_j = current_isects.at(j);
1677 if (isect_j == i)
1678 continue;
1679 const QList<int> &isects_j = isects.at(isect_j);
1680 for (int k = 0, size = isects_j.size(); k < size; ++k) {
1681 int isect_k = isects_j.at(k);
1682 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1683 isects[i] += isect_k;
1684 }
1685 }
1686 isects[isect_j].clear();
1687 }
1688 }
1689
1690#ifdef QPP_FILLPOLYGONS_DEBUG
1691 printf("Intersections after flattening:\n");
1692 for (int i = 0; i < count; ++i) {
1693 printf("%d: ", i);
1694 for (int j = 0; j < isects[i].size(); ++j) {
1695 printf("%d ", isects[i][j]);
1696 }
1697 printf("\n");
1698 }
1699#endif
1700
1701 // Join the intersected subpaths as rewinded polygons
1702 for (int i=0; i<count; ++i) {
1703 const QList<int> &subpath_list = isects.at(i);
1704 if (!subpath_list.isEmpty()) {
1705 QPolygonF buildUp;
1706 for (int j=0; j<subpath_list.size(); ++j) {
1707 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1708 buildUp += subpath;
1709 if (!subpath.isClosed())
1710 buildUp += subpath.first();
1711 if (!buildUp.isClosed())
1712 buildUp += buildUp.constFirst();
1713 }
1714 polys += buildUp;
1715 }
1716 }
1717
1718 return polys;
1719}
1720
1721//same as qt_polygon_isect_line in qpolygon.cpp
1723 const QPointF &p2,
1724 const QPointF &pos,
1725 int *winding)
1726{
1727 qreal x1 = p1.x();
1728 qreal y1 = p1.y();
1729 qreal x2 = p2.x();
1730 qreal y2 = p2.y();
1731 qreal y = pos.y();
1732
1733 int dir = 1;
1734
1735 if (qFuzzyCompare(y1, y2)) {
1736 // ignore horizontal lines according to scan conversion rule
1737 return;
1738 } else if (y2 < y1) {
1739 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1740 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1741 dir = -1;
1742 }
1743
1744 if (y >= y1 && y < y2) {
1745 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1746
1747 // count up the winding number if we're
1748 if (x<=pos.x()) {
1749 (*winding) += dir;
1750 }
1751 }
1752}
1753
1754static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1755 int *winding, int depth = 0)
1756{
1757 qreal y = pt.y();
1758 qreal x = pt.x();
1759 QRectF bounds = bezier.bounds();
1760
1761 // potential intersection, divide and try again...
1762 // Please note that a sideeffect of the bottom exclusion is that
1763 // horizontal lines are dropped, but this is correct according to
1764 // scan conversion rules.
1765 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1766
1767 // hit lower limit... This is a rough threshold, but its a
1768 // tradeoff between speed and precision.
1769 const qreal lower_bound = qreal(.001);
1770 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1771 // We make the assumption here that the curve starts to
1772 // approximate a line after while (i.e. that it doesn't
1773 // change direction drastically during its slope)
1774 if (bezier.pt1().x() <= x) {
1775 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1776 }
1777 return;
1778 }
1779
1780 // split curve and try again...
1781 const auto halves = bezier.split();
1782 qt_painterpath_isect_curve(halves.first, pt, winding, depth + 1);
1783 qt_painterpath_isect_curve(halves.second, pt, winding, depth + 1);
1784 }
1785}
1786
1795bool QPainterPath::contains(const QPointF &pt) const
1796{
1797 if (isEmpty() || !controlPointRect().contains(pt))
1798 return false;
1799
1800 QPainterPathPrivate *d = d_func();
1801
1802 int winding_number = 0;
1803
1804 QPointF last_pt;
1805 QPointF last_start;
1806 for (int i=0; i<d->elements.size(); ++i) {
1807 const Element &e = d->elements.at(i);
1808
1809 switch (e.type) {
1810
1811 case MoveToElement:
1812 if (i > 0) // implicitly close all paths.
1813 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1814 last_start = last_pt = e;
1815 break;
1816
1817 case LineToElement:
1818 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1819 last_pt = e;
1820 break;
1821
1822 case CurveToElement:
1823 {
1824 const QPainterPath::Element &cp2 = d->elements.at(++i);
1825 const QPainterPath::Element &ep = d->elements.at(++i);
1827 pt, &winding_number);
1828 last_pt = ep;
1829
1830 }
1831 break;
1832
1833 default:
1834 break;
1835 }
1836 }
1837
1838 // implicitly close last subpath
1839 if (last_pt != last_start)
1840 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1841
1842 return (d->fillRule == Qt::WindingFill
1843 ? (winding_number != 0)
1844 : ((winding_number % 2) != 0));
1845}
1846
1848
1850 const QRectF &rect)
1851{
1852 qreal left = rect.left();
1853 qreal right = rect.right();
1854 qreal top = rect.top();
1855 qreal bottom = rect.bottom();
1856
1857 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1858 int p1 = ((x1 < left) << Left)
1859 | ((x1 > right) << Right)
1860 | ((y1 < top) << Top)
1861 | ((y1 > bottom) << Bottom);
1862 int p2 = ((x2 < left) << Left)
1863 | ((x2 > right) << Right)
1864 | ((y2 < top) << Top)
1865 | ((y2 > bottom) << Bottom);
1866
1867 if (p1 & p2)
1868 // completely inside
1869 return false;
1870
1871 if (p1 | p2) {
1872 qreal dx = x2 - x1;
1873 qreal dy = y2 - y1;
1874
1875 // clip x coordinates
1876 if (x1 < left) {
1877 y1 += dy/dx * (left - x1);
1878 x1 = left;
1879 } else if (x1 > right) {
1880 y1 -= dy/dx * (x1 - right);
1881 x1 = right;
1882 }
1883 if (x2 < left) {
1884 y2 += dy/dx * (left - x2);
1885 x2 = left;
1886 } else if (x2 > right) {
1887 y2 -= dy/dx * (x2 - right);
1888 x2 = right;
1889 }
1890
1891 p1 = ((y1 < top) << Top)
1892 | ((y1 > bottom) << Bottom);
1893 p2 = ((y2 < top) << Top)
1894 | ((y2 > bottom) << Bottom);
1895
1896 if (p1 & p2)
1897 return false;
1898
1899 // clip y coordinates
1900 if (y1 < top) {
1901 x1 += dx/dy * (top - y1);
1902 y1 = top;
1903 } else if (y1 > bottom) {
1904 x1 -= dx/dy * (y1 - bottom);
1905 y1 = bottom;
1906 }
1907 if (y2 < top) {
1908 x2 += dx/dy * (top - y2);
1909 y2 = top;
1910 } else if (y2 > bottom) {
1911 x2 -= dx/dy * (y2 - bottom);
1912 y2 = bottom;
1913 }
1914
1915 p1 = ((x1 < left) << Left)
1916 | ((x1 > right) << Right);
1917 p2 = ((x2 < left) << Left)
1918 | ((x2 > right) << Right);
1919
1920 if (p1 & p2)
1921 return false;
1922
1923 return true;
1924 }
1925 return false;
1926}
1927
1928static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
1929{
1930 QRectF bounds = bezier.bounds();
1931
1932 if (y >= bounds.top() && y < bounds.bottom()
1933 && bounds.right() >= x1 && bounds.left() < x2) {
1934 const qreal lower_bound = qreal(.01);
1935 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1936 return true;
1937
1938 const auto halves = bezier.split();
1939 if (qt_isect_curve_horizontal(halves.first, y, x1, x2, depth + 1)
1940 || qt_isect_curve_horizontal(halves.second, y, x1, x2, depth + 1))
1941 return true;
1942 }
1943 return false;
1944}
1945
1946static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
1947{
1948 QRectF bounds = bezier.bounds();
1949
1950 if (x >= bounds.left() && x < bounds.right()
1951 && bounds.bottom() >= y1 && bounds.top() < y2) {
1952 const qreal lower_bound = qreal(.01);
1953 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1954 return true;
1955
1956 const auto halves = bezier.split();
1957 if (qt_isect_curve_vertical(halves.first, x, y1, y2, depth + 1)
1958 || qt_isect_curve_vertical(halves.second, x, y1, y2, depth + 1))
1959 return true;
1960 }
1961 return false;
1962}
1963
1964static bool pointOnEdge(const QRectF &rect, const QPointF &point)
1965{
1966 if ((point.x() == rect.left() || point.x() == rect.right()) &&
1967 (point.y() >= rect.top() && point.y() <= rect.bottom()))
1968 return true;
1969 if ((point.y() == rect.top() || point.y() == rect.bottom()) &&
1970 (point.x() >= rect.left() && point.x() <= rect.right()))
1971 return true;
1972 return false;
1973}
1974
1975/*
1976 Returns \c true if any lines or curves cross the four edges in of rect
1977*/
1979{
1980 QPointF last_pt;
1981 QPointF last_start;
1982 enum { OnRect, InsideRect, OutsideRect} edgeStatus = OnRect;
1983 for (int i=0; i<path->elementCount(); ++i) {
1984 const QPainterPath::Element &e = path->elementAt(i);
1985
1986 switch (e.type) {
1987
1989 if (i > 0
1990 && qFuzzyCompare(last_pt.x(), last_start.x())
1991 && qFuzzyCompare(last_pt.y(), last_start.y())
1992 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1993 last_start.x(), last_start.y(), rect))
1994 return true;
1995 last_start = last_pt = e;
1996 break;
1997
1999 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2000 return true;
2001 last_pt = e;
2002 break;
2003
2005 {
2006 QPointF cp2 = path->elementAt(++i);
2007 QPointF ep = path->elementAt(++i);
2008 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2009 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2010 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2011 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2012 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2013 return true;
2014 last_pt = ep;
2015 }
2016 break;
2017
2018 default:
2019 break;
2020 }
2021 // Handle crossing the edges of the rect at the end-points of individual sub-paths.
2022 // A point on on the edge itself is considered neither inside nor outside for this purpose.
2023 if (!pointOnEdge(rect, last_pt)) {
2024 bool contained = rect.contains(last_pt);
2025 switch (edgeStatus) {
2026 case OutsideRect:
2027 if (contained)
2028 return true;
2029 break;
2030 case InsideRect:
2031 if (!contained)
2032 return true;
2033 break;
2034 case OnRect:
2035 edgeStatus = contained ? InsideRect : OutsideRect;
2036 break;
2037 }
2038 } else {
2039 if (last_pt == last_start)
2040 edgeStatus = OnRect;
2041 }
2042 }
2043
2044 // implicitly close last subpath
2045 if (last_pt != last_start
2046 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2047 last_start.x(), last_start.y(), rect))
2048 return true;
2049
2050 return false;
2051}
2052
2068{
2069 if (elementCount() == 1 && rect.contains(elementAt(0)))
2070 return true;
2071
2072 if (isEmpty())
2073 return false;
2074
2075 QRectF cp = controlPointRect();
2076 QRectF rn = rect.normalized();
2077
2078 // QRectF::intersects returns false if one of the rects is a null rect
2079 // which would happen for a painter path consisting of a vertical or
2080 // horizontal line
2081 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2082 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2083 return false;
2084
2085 // If any path element cross the rect its bound to be an intersection
2087 return true;
2088
2089 if (contains(rect.center()))
2090 return true;
2091
2092 Q_D(QPainterPath);
2093
2094 // Check if the rectangle surrounds any subpath...
2095 for (int i=0; i<d->elements.size(); ++i) {
2096 const Element &e = d->elements.at(i);
2097 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2098 return true;
2099 }
2100
2101 return false;
2102}
2103
2111{
2112 if (!d_ptr || (dx == 0 && dy == 0))
2113 return;
2114
2115 int elementsLeft = d_ptr->elements.size();
2116 if (elementsLeft <= 0)
2117 return;
2118
2119 detach();
2120 QPainterPath::Element *element = d_func()->elements.data();
2121 Q_ASSERT(element);
2122 while (elementsLeft--) {
2123 element->x += dx;
2124 element->y += dy;
2125 ++element;
2126 }
2127}
2128
2146{
2147 QPainterPath copy(*this);
2148 copy.translate(dx, dy);
2149 return copy;
2150}
2151
2169{
2170 Q_D(QPainterPath);
2171
2172 // the path is empty or the control point rect doesn't completely
2173 // cover the rectangle we abort stratight away.
2175 return false;
2176
2177 // if there are intersections, chances are that the rect is not
2178 // contained, except if we have winding rule, in which case it
2179 // still might.
2181 if (fillRule() == Qt::OddEvenFill) {
2182 return false;
2183 } else {
2184 // Do some wague sampling in the winding case. This is not
2185 // precise but it should mostly be good enough.
2186 if (!contains(rect.topLeft()) ||
2187 !contains(rect.topRight()) ||
2188 !contains(rect.bottomRight()) ||
2189 !contains(rect.bottomLeft()))
2190 return false;
2191 }
2192 }
2193
2194 // If there exists a point inside that is not part of the path its
2195 // because: rectangle lies completely outside path or a subpath
2196 // excludes parts of the rectangle. Both cases mean that the rect
2197 // is not contained
2198 if (!contains(rect.center()))
2199 return false;
2200
2201 // If there are any subpaths inside this rectangle we need to
2202 // check if they are still contained as a result of the fill
2203 // rule. This can only be the case for WindingFill though. For
2204 // OddEvenFill the rect will never be contained if it surrounds a
2205 // subpath. (the case where two subpaths are completely identical
2206 // can be argued but we choose to neglect it).
2207 for (int i=0; i<d->elements.size(); ++i) {
2208 const Element &e = d->elements.at(i);
2209 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2210 if (fillRule() == Qt::OddEvenFill)
2211 return false;
2212
2213 bool stop = false;
2214 for (; !stop && i<d->elements.size(); ++i) {
2215 const Element &el = d->elements.at(i);
2216 switch (el.type) {
2217 case MoveToElement:
2218 stop = true;
2219 break;
2220 case LineToElement:
2221 if (!contains(el))
2222 return false;
2223 break;
2224 case CurveToElement:
2225 if (!contains(d->elements.at(i+2)))
2226 return false;
2227 i += 2;
2228 break;
2229 default:
2230 break;
2231 }
2232 }
2233
2234 // compensate for the last ++i in the inner for
2235 --i;
2236 }
2237 }
2238
2239 return true;
2240}
2241
2242static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2243{
2244 return qAbs(a.x() - b.x()) <= epsilon.width()
2245 && qAbs(a.y() - b.y()) <= epsilon.height();
2246}
2247
2258{
2259 QPainterPathPrivate *d = d_func();
2260 QPainterPathPrivate *other_d = path.d_func();
2261 if (other_d == d) {
2262 return true;
2263 } else if (!d || !other_d) {
2264 if (!other_d && isEmpty() && elementAt(0) == QPointF() && d->fillRule == Qt::OddEvenFill)
2265 return true;
2266 if (!d && path.isEmpty() && path.elementAt(0) == QPointF() && other_d->fillRule == Qt::OddEvenFill)
2267 return true;
2268 return false;
2269 }
2270 else if (d->fillRule != other_d->fillRule)
2271 return false;
2272 else if (d->elements.size() != other_d->elements.size())
2273 return false;
2274
2275 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2276
2278 epsilon.rwidth() *= qt_epsilon;
2279 epsilon.rheight() *= qt_epsilon;
2280
2281 for (int i = 0; i < d->elements.size(); ++i)
2282 if (d->elements.at(i).type != other_d->elements.at(i).type
2283 || !epsilonCompare(d->elements.at(i), other_d->elements.at(i), epsilon))
2284 return false;
2285
2286 return true;
2287}
2288
2299{
2300 return !(*this==path);
2301}
2302
2314
2323{
2324 return united(other);
2325}
2326
2336{
2337 return united(other);
2338}
2339
2351
2360{
2361 return *this = (*this & other);
2362}
2363
2372{
2373 return *this = (*this | other);
2374}
2375
2385{
2386 return *this = (*this + other);
2387}
2388
2398{
2399 return *this = (*this - other);
2400}
2401
2402#ifndef QT_NO_DATASTREAM
2413{
2414 if (p.isEmpty()) {
2415 s << 0;
2416 return s;
2417 }
2418
2419 s << p.elementCount();
2420 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2421 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2422 s << int(e.type);
2423 s << double(e.x) << double(e.y);
2424 }
2425 s << p.d_func()->cStart;
2426 s << int(p.d_func()->fillRule);
2427 return s;
2428}
2429
2440{
2441 bool errorDetected = false;
2442 int size;
2443 s >> size;
2444
2445 if (size == 0) {
2446 p = {};
2447 return s;
2448 }
2449
2450 p.ensureData(); // in case if p.d_func() == 0
2451 p.detach();
2452 p.d_func()->elements.clear();
2453 for (int i=0; i<size; ++i) {
2454 int type;
2455 double x, y;
2456 s >> type;
2457 s >> x;
2458 s >> y;
2459 Q_ASSERT(type >= 0 && type <= 3);
2460 if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) {
2461#ifndef QT_NO_DEBUG
2462 qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it");
2463#endif
2464 errorDetected = true;
2465 continue;
2466 }
2468 p.d_func()->elements.append(elm);
2469 }
2470 s >> p.d_func()->cStart;
2471 int fillRule;
2472 s >> fillRule;
2473 Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
2474 p.d_func()->fillRule = Qt::FillRule(fillRule);
2475 if (errorDetected || p.d_func()->elements.isEmpty())
2476 p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
2477 return s;
2478}
2479#endif // QT_NO_DATASTREAM
2480
2481
2482/*******************************************************************************
2483 * class QPainterPathStroker
2484 */
2485
2490
2495
2497 qfixed c2x, qfixed c2y,
2498 qfixed ex, qfixed ey,
2499 void *data)
2500{
2501 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2504}
2505
2564
2572
2579 : d_ptr(new QPainterPathStrokerPrivate)
2580{
2581 setWidth(pen.widthF());
2582 setCapStyle(pen.capStyle());
2583 setJoinStyle(pen.joinStyle());
2586
2587 if (pen.style() == Qt::CustomDashLine)
2589 else
2590 setDashPattern(pen.style());
2591}
2592
2599
2600
2615{
2616 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2617 QPainterPath stroke;
2618 if (path.isEmpty())
2619 return path;
2620 if (d->dashPattern.isEmpty()) {
2621 d->stroker.strokePath(path, &stroke, QTransform());
2622 } else {
2623 QDashStroker dashStroker(&d->stroker);
2624 dashStroker.setDashPattern(d->dashPattern);
2625 dashStroker.setDashOffset(d->dashOffset);
2626 dashStroker.setClipRect(d->stroker.clipRect());
2627 dashStroker.strokePath(path, &stroke, QTransform());
2628 }
2630 return stroke;
2631}
2632
2640{
2642 if (width <= 0)
2643 width = 1;
2644 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2645}
2646
2651{
2652 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2653}
2654
2655
2662{
2663 d_func()->stroker.setCapStyle(style);
2664}
2665
2666
2671{
2672 return d_func()->stroker.capStyle();
2673}
2674
2679{
2680 d_func()->stroker.setJoinStyle(style);
2681}
2682
2687{
2688 return d_func()->stroker.joinStyle();
2689}
2690
2702{
2703 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2704}
2705
2710{
2711 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2712}
2713
2714
2724{
2725 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2726}
2727
2733{
2734 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2735}
2736
2741{
2742 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2743}
2744
2761void QPainterPathStroker::setDashPattern(const QList<qreal> &dashPattern)
2762{
2763 d_func()->dashPattern.clear();
2764 for (int i=0; i<dashPattern.size(); ++i)
2765 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2766}
2767
2772{
2773 return d_func()->dashPattern;
2774}
2775
2780{
2781 return d_func()->dashOffset;
2782}
2783
2791{
2792 d_func()->dashOffset = offset;
2793}
2794
2811{
2812 const QList<QPolygonF> flats = toSubpathPolygons(matrix);
2814 if (flats.isEmpty())
2815 return polygon;
2816 QPointF first = flats.first().first();
2817 for (int i=0; i<flats.size(); ++i) {
2818 polygon += flats.at(i);
2819 if (!flats.at(i).isClosed())
2820 polygon += flats.at(i).first();
2821 if (i > 0)
2822 polygon += first;
2823 }
2824 return polygon;
2825}
2826
2827//derivative of the equation
2829{
2830 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2831}
2832
2837{
2838 Q_D(QPainterPath);
2839 if (isEmpty())
2840 return 0;
2841
2842 qreal len = 0;
2843 for (int i=1; i<d->elements.size(); ++i) {
2844 const Element &e = d->elements.at(i);
2845
2846 switch (e.type) {
2847 case MoveToElement:
2848 break;
2849 case LineToElement:
2850 {
2851 len += QLineF(d->elements.at(i-1), e).length();
2852 break;
2853 }
2854 case CurveToElement:
2855 {
2856 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2857 e,
2858 d->elements.at(i+1),
2859 d->elements.at(i+2));
2860 len += b.length();
2861 i += 2;
2862 break;
2863 }
2864 default:
2865 break;
2866 }
2867 }
2868 return len;
2869}
2870
2880{
2881 Q_D(QPainterPath);
2882 if (isEmpty() || len <= 0)
2883 return 0;
2884
2885 qreal totalLength = length();
2886 if (len > totalLength)
2887 return 1;
2888
2889 qreal curLen = 0;
2890 for (int i=1; i<d->elements.size(); ++i) {
2891 const Element &e = d->elements.at(i);
2892
2893 switch (e.type) {
2894 case MoveToElement:
2895 break;
2896 case LineToElement:
2897 {
2898 QLineF line(d->elements.at(i-1), e);
2899 qreal llen = line.length();
2900 curLen += llen;
2901 if (curLen >= len) {
2902 return len/totalLength ;
2903 }
2904
2905 break;
2906 }
2907 case CurveToElement:
2908 {
2909 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2910 e,
2911 d->elements.at(i+1),
2912 d->elements.at(i+2));
2913 qreal blen = b.length();
2914 qreal prevLen = curLen;
2915 curLen += blen;
2916
2917 if (curLen >= len) {
2918 qreal res = b.tAtLength(len - prevLen);
2919 return (res * blen + prevLen)/totalLength;
2920 }
2921
2922 i += 2;
2923 break;
2924 }
2925 default:
2926 break;
2927 }
2928 }
2929
2930 return 0;
2931}
2932
2933static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2934{
2935 *startingLength = 0;
2936 if (t > 1)
2937 return QBezier();
2938
2939 qreal curLen = 0;
2940 qreal totalLength = path.length();
2941
2942 const int lastElement = path.elementCount() - 1;
2943 for (int i=0; i <= lastElement; ++i) {
2944 const QPainterPath::Element &e = path.elementAt(i);
2945
2946 switch (e.type) {
2948 break;
2950 {
2951 QLineF line(path.elementAt(i-1), e);
2952 qreal llen = line.length();
2953 curLen += llen;
2954 if (i == lastElement || curLen/totalLength >= t) {
2955 *bezierLength = llen;
2956 QPointF a = path.elementAt(i-1);
2957 QPointF delta = e - a;
2958 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2959 }
2960 break;
2961 }
2963 {
2964 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2965 e,
2966 path.elementAt(i+1),
2967 path.elementAt(i+2));
2968 qreal blen = b.length();
2969 curLen += blen;
2970
2971 if (i + 2 == lastElement || curLen/totalLength >= t) {
2972 *bezierLength = blen;
2973 return b;
2974 }
2975
2976 i += 2;
2977 break;
2978 }
2979 default:
2980 break;
2981 }
2982 *startingLength = curLen;
2983 }
2984 return QBezier();
2985}
2986
2997{
2998 if (t < 0 || t > 1) {
2999 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
3000 return QPointF();
3001 }
3002
3003 if (!d_ptr || d_ptr->elements.size() == 0)
3004 return QPointF();
3005
3006 if (d_ptr->elements.size() == 1)
3007 return d_ptr->elements.at(0);
3008
3009 qreal totalLength = length();
3010 qreal curLen = 0;
3011 qreal bezierLen = 0;
3012 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
3013 qreal realT = (totalLength * t - curLen) / bezierLen;
3014
3015 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
3016}
3017
3031{
3032 if (t < 0 || t > 1) {
3033 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
3034 return 0;
3035 }
3036
3037 qreal totalLength = length();
3038 qreal curLen = 0;
3039 qreal bezierLen = 0;
3040 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3041 qreal realT = (totalLength * t - curLen) / bezierLen;
3042
3043 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3044 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3045
3046 return QLineF(0, 0, m1, m2).angle();
3047}
3048
3049
3060{
3061 if (t < 0 || t > 1) {
3062 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3063 return 0;
3064 }
3065
3066 qreal totalLength = length();
3067 qreal curLen = 0;
3068 qreal bezierLen = 0;
3069 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3070 qreal realT = (totalLength * t - curLen) / bezierLen;
3071
3072 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3073 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3074 //tangent line
3075 qreal slope = 0;
3076
3077 if (m1)
3078 slope = m2/m1;
3079 else {
3080 if (std::numeric_limits<qreal>::has_infinity) {
3081 slope = (m2 < 0) ? -std::numeric_limits<qreal>::infinity()
3082 : std::numeric_limits<qreal>::infinity();
3083 } else {
3084 if (sizeof(qreal) == sizeof(double)) {
3085 return 1.79769313486231570e+308;
3086 } else {
3087 return ((qreal)3.40282346638528860e+38);
3088 }
3089 }
3090 }
3091
3092 return slope;
3093}
3094
3110{
3111 QRectF r = rect.normalized();
3112
3113 if (r.isNull())
3114 return;
3115
3116 if (mode == Qt::AbsoluteSize) {
3117 qreal w = r.width() / 2;
3118 qreal h = r.height() / 2;
3119
3120 if (w == 0) {
3121 xRadius = 0;
3122 } else {
3123 xRadius = 100 * qMin(xRadius, w) / w;
3124 }
3125 if (h == 0) {
3126 yRadius = 0;
3127 } else {
3128 yRadius = 100 * qMin(yRadius, h) / h;
3129 }
3130 } else {
3131 if (xRadius > 100) // fix ranges
3132 xRadius = 100;
3133
3134 if (yRadius > 100)
3135 yRadius = 100;
3136 }
3137
3138 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3139 addRect(r);
3140 return;
3141 }
3142
3143 qreal x = r.x();
3144 qreal y = r.y();
3145 qreal w = r.width();
3146 qreal h = r.height();
3147 qreal rxx2 = w*xRadius/100;
3148 qreal ryy2 = h*yRadius/100;
3149
3150 ensureData();
3151 detach();
3152
3153 bool first = d_func()->elements.size() < 2;
3154
3155 arcMoveTo(x, y, rxx2, ryy2, 180);
3156 arcTo(x, y, rxx2, ryy2, 180, -90);
3157 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3158 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3159 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3160 closeSubpath();
3161
3162 d_func()->require_moveTo = true;
3163 d_func()->convex = first;
3164}
3165
3187{
3188 if (isEmpty() || p.isEmpty())
3189 return isEmpty() ? p : *this;
3190 QPathClipper clipper(*this, p);
3191 return clipper.clip(QPathClipper::BoolOr);
3192}
3193
3202{
3203 if (isEmpty() || p.isEmpty())
3204 return QPainterPath();
3205 QPathClipper clipper(*this, p);
3206 return clipper.clip(QPathClipper::BoolAnd);
3207}
3208
3220{
3221 if (isEmpty() || p.isEmpty())
3222 return *this;
3223 QPathClipper clipper(*this, p);
3224 return clipper.clip(QPathClipper::BoolSub);
3225}
3226
3237{
3238 if (isEmpty())
3239 return *this;
3240 QPathClipper clipper(*this, QPainterPath());
3241 return clipper.clip(QPathClipper::Simplify);
3242}
3243
3256{
3257 if (p.elementCount() == 1)
3258 return contains(p.elementAt(0));
3259 if (isEmpty() || p.isEmpty())
3260 return false;
3261 QPathClipper clipper(*this, p);
3262 return clipper.intersect();
3263}
3264
3278{
3279 if (p.elementCount() == 1)
3280 return contains(p.elementAt(0));
3281 if (isEmpty() || p.isEmpty())
3282 return false;
3283 QPathClipper clipper(*this, p);
3284 return clipper.contains();
3285}
3286
3287void QPainterPath::setDirty(bool dirty)
3288{
3289 d_func()->dirtyBounds = dirty;
3290 d_func()->dirtyControlBounds = dirty;
3291 d_func()->pathConverter.reset();
3292 d_func()->convex = false;
3293}
3294
3295void QPainterPath::computeBoundingRect() const
3296{
3297 QPainterPathPrivate *d = d_func();
3298 d->dirtyBounds = false;
3299 if (!d_ptr) {
3300 d->bounds = QRect();
3301 return;
3302 }
3303
3304 qreal minx, maxx, miny, maxy;
3305 minx = maxx = d->elements.at(0).x;
3306 miny = maxy = d->elements.at(0).y;
3307 for (int i=1; i<d->elements.size(); ++i) {
3308 const Element &e = d->elements.at(i);
3309
3310 switch (e.type) {
3311 case MoveToElement:
3312 case LineToElement:
3313 if (e.x > maxx) maxx = e.x;
3314 else if (e.x < minx) minx = e.x;
3315 if (e.y > maxy) maxy = e.y;
3316 else if (e.y < miny) miny = e.y;
3317 break;
3318 case CurveToElement:
3319 {
3320 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3321 e,
3322 d->elements.at(i+1),
3323 d->elements.at(i+2));
3325 qreal right = r.right();
3326 qreal bottom = r.bottom();
3327 if (r.x() < minx) minx = r.x();
3328 if (right > maxx) maxx = right;
3329 if (r.y() < miny) miny = r.y();
3330 if (bottom > maxy) maxy = bottom;
3331 i += 2;
3332 }
3333 break;
3334 default:
3335 break;
3336 }
3337 }
3338 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3339}
3340
3341
3342void QPainterPath::computeControlPointRect() const
3343{
3344 QPainterPathPrivate *d = d_func();
3345 d->dirtyControlBounds = false;
3346 if (!d_ptr) {
3347 d->controlBounds = QRect();
3348 return;
3349 }
3350
3351 qreal minx, maxx, miny, maxy;
3352 minx = maxx = d->elements.at(0).x;
3353 miny = maxy = d->elements.at(0).y;
3354 for (int i=1; i<d->elements.size(); ++i) {
3355 const Element &e = d->elements.at(i);
3356 if (e.x > maxx) maxx = e.x;
3357 else if (e.x < minx) minx = e.x;
3358 if (e.y > maxy) maxy = e.y;
3359 else if (e.y < miny) miny = e.y;
3360 }
3361 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3362}
3363
3364#ifndef QT_NO_DEBUG_STREAM
3366{
3367 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << Qt::endl;
3368 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3369 for (int i=0; i<p.elementCount(); ++i) {
3370 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << Qt::endl;
3371
3372 }
3373 return s;
3374}
3375#endif
3376
QPointF pt1() const
Definition qbezier_p.h:58
QRectF bounds() const
Definition qbezier.cpp:137
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:33
std::pair< QBezier, QBezier > split() const
Definition qbezier_p.h:188
static void coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal &d)
Definition qbezier_p.h:116
QPointF pt4() const
Definition qbezier_p.h:61
void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold=0.5) const
Definition qbezier.cpp:65
void setDashPattern(const QList< qfixed > &dashPattern)
Definition qstroker_p.h:237
void setDashOffset(qreal offset)
Definition qstroker_p.h:240
static QList< qfixed > patternForStyle(Qt::PenStyle style)
Definition qstroker.cpp:995
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
void reset(T *ptr=nullptr) noexcept
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
\reentrant
Definition qfont.h:22
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
qreal angle() const
Definition qline.cpp:564
qreal length() const
Returns the length of the line.
Definition qline.cpp:548
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const T & constFirst() const noexcept
Definition qlist.h:647
void reserve(qsizetype size)
Definition qlist.h:753
pointer data()
Definition qlist.h:431
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setCurveThreshold(qreal threshold)
Specifies the curve flattening threshold, controlling the granularity with which the generated outlin...
Qt::PenJoinStyle joinStyle() const
Returns the join style of the generated outlines.
QList< qreal > dashPattern() const
Returns the dash pattern for the generated outlines.
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
qreal miterLimit() const
Returns the miter limit for the generated outlines.
qreal curveThreshold() const
Returns the curve flattening threshold for the generated outlines.
Qt::PenCapStyle capStyle() const
Returns the cap style of the generated outlines.
~QPainterPathStroker()
Destroys the stroker.
qreal width() const
Returns the width of the generated outlines.
void setDashOffset(qreal offset)
Sets the dash offset for the generated outlines to offset.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path.
QPainterPathStroker()
Creates a new stroker.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
qreal dashOffset() const
Returns the dash offset for the generated outlines.
void setMiterLimit(qreal length)
Sets the miter limit of the generated outlines to limit.
\inmodule QtGui
\inmodule QtGui
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...
int capacity() const
Returns the number of elements allocated by the QPainterPath.
QPainterPath operator-(const QPainterPath &other) const
QPainterPath translated(qreal dx, qreal dy) const
Returns a copy of the path that is translated by ({dx}, {dy}).
void translate(qreal dx, qreal dy)
Translates all elements in the path by ({dx}, {dy}).
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
QList< QPolygonF > toSubpathPolygons(const QTransform &matrix=QTransform()) const
Converts the path into a list of polygons using the QTransform matrix, and returns the list.
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
~QPainterPath()
Destroys this QPainterPath object.
void addEllipse(const QRectF &rect)
Creates an ellipse within the specified boundingRectangle and adds it to the painter path as a closed...
qreal angleAtPercent(qreal t) const
Returns the angle of the path tangent at the percentage t.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
void setElementPositionAt(int i, qreal x, qreal y)
QPainterPath subtracted(const QPainterPath &r) const
QPainterPath & operator=(const QPainterPath &other)
Assigns the given path to this painter path.
QPainterPath operator+(const QPainterPath &other) const
QPainterPath::Element elementAt(int i) const
Returns the element at the given index in the painter path.
QPainterPath() noexcept
Constructs an empty QPainterPath object.
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...
int elementCount() const
Returns the number of path elements in the painter path.
void addPolygon(const QPolygonF &polygon)
Adds the given polygon to the path as an (unclosed) subpath.
QPainterPath & operator&=(const QPainterPath &other)
QPainterPath simplified() const
void addPath(const QPainterPath &path)
Adds the given path to this path as a closed subpath.
QPolygonF toFillPolygon(const QTransform &matrix=QTransform()) const
Converts the path into a polygon using the QTransform matrix, and returns the polygon.
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
QPainterPath & operator|=(const QPainterPath &other)
bool intersects(const QRectF &rect) const
Returns true if any point in the given rectangle intersects the path; otherwise returns false.
QList< QPolygonF > toFillPolygons(const QTransform &matrix=QTransform()) const
Converts the path into a list of polygons using the QTransform matrix, and returns the list.
void clear()
Clears the path elements stored.
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision.
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
bool operator!=(const QPainterPath &other) const
Returns true if this painter path differs from the given path.
Qt::FillRule fillRule() const
Returns the painter path's currently set fill rule.
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
QPointF pointAtPercent(qreal t) const
Returns the point at at the percentage t of the current path.
QPainterPath united(const QPainterPath &r) const
void addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
void reserve(int size)
Reserves a given amount of elements in QPainterPath's internal memory.
QPainterPath & operator-=(const QPainterPath &other)
void arcTo(const QRectF &rect, qreal startAngle, qreal arcLength)
Creates an arc that occupies the given rectangle, beginning at the specified startAngle and extending...
QPainterPath operator|(const QPainterPath &other) const
bool operator==(const QPainterPath &other) const
Returns true if this painterpath is equal to the given path.
QPainterPath intersected(const QPainterPath &r) const
qreal percentAtLength(qreal t) const
Returns percentage of the whole path at the specified length len.
QPainterPath toReversed() const
Creates and returns a reversed copy of the path.
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
QPainterPath & operator+=(const QPainterPath &other)
qreal slopeAtPercent(qreal t) const
Returns the slope of the path at the percentage t.
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
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 lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
QPointF currentPosition() const
Returns the current position of the path.
qreal length() const
Returns the length of the current path.
void swap(QPainterPath &other) noexcept
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...
void addRegion(const QRegion &region)
Adds the given region to the path by adding each rectangle in the region as a separate closed subpath...
QPainterPath operator&(const QPainterPath &other) const
void arcMoveTo(const QRectF &rect, qreal angle)
\inmodule QtGui
Definition qpen.h:28
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:572
QList< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition qpen.cpp:400
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:663
qreal miterLimit() const
Returns the miter limit of the pen.
Definition qpen.cpp:524
qreal dashOffset() const
Returns the dash offset for the pen.
Definition qpen.cpp:484
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:500
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
QRectF normalized() const noexcept
Returns a normalized rectangle; i.e., a rectangle that has a non-negative width and height.
Definition qrect.cpp:1522
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:658
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:735
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:498
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:499
\inmodule QtCore\reentrant
Definition qrect.h:30
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
\inmodule QtCore
Definition qsize.h:208
constexpr QChar at(qsizetype n) const noexcept
Returns the character at position n in this string view.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition qstroker_p.h:114
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition qstroker_p.h:112
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:200
void setLineToHook(qStrokerLineToHook lineToHook)
Definition qstroker_p.h:113
void setClipRect(const QRectF &clip)
Definition qstroker_p.h:129
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)
\reentrant
Definition qtextlayout.h:70
\reentrant
\reentrant
Definition qtextoption.h:18
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
int y
the y coordinate of the widget relative to its parent and including any window frame
Definition qwidget.h:110
int x
the x coordinate of the widget relative to its parent including any window frame
Definition qwidget.h:109
QPixmap p2
QPixmap p1
[0]
QString text
rect
[4]
QStyleOptionButton opt
Combined button and popup list for selecting options.
@ AbsoluteSize
@ CustomDashLine
PenJoinStyle
@ WindingFill
@ OddEvenFill
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
PenCapStyle
static jboolean copy(JNIEnv *, jobject)
bool qIsFinite(qfloat16 f) noexcept
Definition qfloat16.h:285
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
int qFloor(T v)
Definition qmath.h:42
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLsizei levels
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLint GLsizei width
GLint left
GLenum type
GLint GLint bottom
GLfloat angle
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLsizei dashCount
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLfixed GLfixed GLint GLint GLfixed points
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
GLuint res
const GLubyte * c
GLfixed GLfixed GLfixed y2
GLuint GLuint * names
GLint limit
GLuint GLenum matrix
GLfixed GLfixed x2
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
GLenum GLsizei len
GLbyte ty
GLbyte by
static const QRectF boundingRect(const QPointF *points, int pointCount)
static QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
static qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
QDataStream & operator<<(QDataStream &s, const QPainterPath &p)
static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth=0)
static void qt_painterpath_isect_line(const QPointF &p1, const QPointF &p2, const QPointF &pos, int *winding)
static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
#define QT_BEZIER_CHECK_T(bezier, t)
PainterDirections
@ Bottom
@ Top
@ Left
@ Right
static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect)
#define QT_BEZIER_C(bezier, coord)
void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
QDataStream & operator>>(QDataStream &s, QPainterPath &p)
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)
static bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
#define QT_BEZIER_B(bezier, coord)
static QT_BEGIN_NAMESPACE bool isValidCoord(qreal c)
static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, int *winding, int depth=0)
static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth=0)
static bool pointOnEdge(const QRectF &rect, const QPointF &point)
QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount)
static bool hasValidCoords(QPointF p)
void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
static const qreal epsilon
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
qreal qt_t_for_arc_angle(qreal angle)
Definition qstroker.cpp:756
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition qstroker.cpp:816
#define QT_PATH_KAPPA
Definition qstroker_p.h:77
#define qt_fixed_to_real(fixed)
Definition qstroker_p.h:65
#define qt_real_to_fixed(real)
Definition qstroker_p.h:64
QT_BEGIN_NAMESPACE typedef qreal qfixed
Definition qstroker_p.h:63
#define sp
#define t2
static const QTextHtmlElement elements[Html_NumElements]
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
QVBoxLayout * layout
MyCustomStruct c2
QSharedPointer< T > other(t)
[5]
QString dir
[11]
QGraphicsItem * item
QStringView el
constexpr qreal toReal() const
Definition qfixed_p.h:42
unsigned short flags
unsigned short bidiLevel
QScriptAnalysis analysis
QScriptItemArray items