| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 |  | 
| 32 | #include <qfile.h> | 
| 33 | #include <qpainterpath.h> | 
| 34 | #include <qpen.h> | 
| 35 | #include <qmath.h> | 
| 36 |  | 
| 37 | class tst_QPainterPath : public QObject | 
| 38 | { | 
| 39 |     Q_OBJECT | 
| 40 |  | 
| 41 | public: | 
| 42 | public slots: | 
| 43 |     void cleanupTestCase(); | 
| 44 | private slots: | 
| 45 |     void getSetCheck(); | 
| 46 |     void clear(); | 
| 47 |     void reserveAndCapacity(); | 
| 48 |     void swap(); | 
| 49 |  | 
| 50 |     void contains_QPointF_data(); | 
| 51 |     void contains_QPointF(); | 
| 52 |  | 
| 53 |     void contains_QRectF_data(); | 
| 54 |     void contains_QRectF(); | 
| 55 |  | 
| 56 |     void intersects_QRectF_data(); | 
| 57 |     void intersects_QRectF(); | 
| 58 |  | 
| 59 |     void testContainsAndIntersects_data(); | 
| 60 |     void testContainsAndIntersects(); | 
| 61 |  | 
| 62 |     void testSimplified_data(); | 
| 63 |     void testSimplified(); | 
| 64 |  | 
| 65 |     void testStroker_data(); | 
| 66 |     void testStroker(); | 
| 67 |  | 
| 68 |     void currentPosition(); | 
| 69 |  | 
| 70 |     void testOperatorEquals(); | 
| 71 |     void testOperatorEquals_fuzzy(); | 
| 72 |     void testOperatorDatastream(); | 
| 73 |  | 
| 74 |     void testArcMoveTo_data(); | 
| 75 |     void testArcMoveTo(); | 
| 76 |     void setElementPositionAt(); | 
| 77 |  | 
| 78 |     void testOnPath_data(); | 
| 79 |     void testOnPath(); | 
| 80 |  | 
| 81 |     void pointAtPercent_data(); | 
| 82 |     void pointAtPercent(); | 
| 83 |  | 
| 84 |     void angleAtPercent(); | 
| 85 |  | 
| 86 |     void arcWinding_data(); | 
| 87 |     void arcWinding(); | 
| 88 |  | 
| 89 |     void testToFillPolygons(); | 
| 90 |  | 
| 91 | #if QT_CONFIG(signaling_nan) | 
| 92 |     void testNaNandInfinites(); | 
| 93 | #endif | 
| 94 |  | 
| 95 |     void closing(); | 
| 96 |  | 
| 97 |     void operators_data(); | 
| 98 |     void operators(); | 
| 99 |  | 
| 100 |     void connectPathDuplicatePoint(); | 
| 101 |     void connectPathMoveTo(); | 
| 102 |  | 
| 103 |     void translate(); | 
| 104 |  | 
| 105 |     void lineWithinBounds(); | 
| 106 |  | 
| 107 |     void intersectionEquality(); | 
| 108 |     void intersectionPointOnEdge(); | 
| 109 | }; | 
| 110 |  | 
| 111 | void tst_QPainterPath::cleanupTestCase() | 
| 112 | { | 
| 113 |     QFile::remove(fileName: QLatin1String("data" )); | 
| 114 | } | 
| 115 |  | 
| 116 | // Testing get/set functions | 
| 117 | void tst_QPainterPath::getSetCheck() | 
| 118 | { | 
| 119 |     QPainterPathStroker obj1; | 
| 120 |     // qreal QPainterPathStroker::width() | 
| 121 |     // void QPainterPathStroker::setWidth(qreal) | 
| 122 |     obj1.setWidth(0.0); | 
| 123 |     QCOMPARE(qreal(1.0), obj1.width()); // Pathstroker sets with to 1 if <= 0 | 
| 124 |     obj1.setWidth(0.5); | 
| 125 |     QCOMPARE(qreal(0.5), obj1.width()); | 
| 126 |     obj1.setWidth(1.1); | 
| 127 |     QCOMPARE(qreal(1.1), obj1.width()); | 
| 128 |  | 
| 129 |     // qreal QPainterPathStroker::miterLimit() | 
| 130 |     // void QPainterPathStroker::setMiterLimit(qreal) | 
| 131 |     obj1.setMiterLimit(0.0); | 
| 132 |     QCOMPARE(qreal(0.0), obj1.miterLimit()); | 
| 133 |     obj1.setMiterLimit(1.1); | 
| 134 |     QCOMPARE(qreal(1.1), obj1.miterLimit()); | 
| 135 |  | 
| 136 |     // qreal QPainterPathStroker::curveThreshold() | 
| 137 |     // void QPainterPathStroker::setCurveThreshold(qreal) | 
| 138 |     obj1.setCurveThreshold(0.0); | 
| 139 |     QCOMPARE(qreal(0.0), obj1.curveThreshold()); | 
| 140 |     obj1.setCurveThreshold(1.1); | 
| 141 |     QCOMPARE(qreal(1.1), obj1.curveThreshold()); | 
| 142 | } | 
| 143 |  | 
| 144 | void tst_QPainterPath::swap() | 
| 145 | { | 
| 146 |     QPainterPath p1; | 
| 147 |     p1.addRect( x: 0, y: 0,w: 10,h: 10); | 
| 148 |     QPainterPath p2; | 
| 149 |     p2.addRect(x: 10,y: 10,w: 10,h: 10); | 
| 150 |     p1.swap(other&: p2); | 
| 151 |     QCOMPARE(p1.boundingRect().toRect(), QRect(10,10,10,10)); | 
| 152 |     QCOMPARE(p2.boundingRect().toRect(), QRect( 0, 0,10,10)); | 
| 153 | } | 
| 154 |  | 
| 155 | void tst_QPainterPath::clear() | 
| 156 | { | 
| 157 |     QPainterPath p1; | 
| 158 |     QPainterPath p2; | 
| 159 |     p1.clear(); | 
| 160 |     QCOMPARE(p1, p2); | 
| 161 |  | 
| 162 |     p1.addRect(x: 0, y: 0, w: 10, h: 10); | 
| 163 |     p1.clear(); | 
| 164 |     QCOMPARE(p1, p2); | 
| 165 |  | 
| 166 |     p1.lineTo(x: 50, y: 50); | 
| 167 |     QPainterPath p3; | 
| 168 |     QCOMPARE(p1.elementCount(), 2); | 
| 169 |     p3.lineTo(x: 50, y: 50); | 
| 170 |     QCOMPARE(p1, p3); | 
| 171 |  | 
| 172 |     QCOMPARE(p1.fillRule(), Qt::OddEvenFill); | 
| 173 |     p1.setFillRule(Qt::WindingFill); | 
| 174 |     QVERIFY(p1 != p3); | 
| 175 |     p1.clear(); | 
| 176 |     QVERIFY(p1 != p3); | 
| 177 |     p1.setFillRule(Qt::OddEvenFill); | 
| 178 |     QCOMPARE(p1, p2); | 
| 179 |  | 
| 180 |     QPainterPath p4; | 
| 181 |     QCOMPARE(p4.fillRule(), Qt::OddEvenFill); | 
| 182 |     p4.setFillRule(Qt::WindingFill); | 
| 183 |     QCOMPARE(p4.fillRule(), Qt::WindingFill); | 
| 184 |     p4.clear(); | 
| 185 |     QCOMPARE(p4.fillRule(), Qt::WindingFill); | 
| 186 |     p4 = QPainterPath(); | 
| 187 |     QCOMPARE(p4.fillRule(), Qt::OddEvenFill); | 
| 188 | } | 
| 189 |  | 
| 190 | void tst_QPainterPath::reserveAndCapacity() | 
| 191 | { | 
| 192 |     QPainterPath p; | 
| 193 |     QVERIFY(p.capacity() == 0); | 
| 194 |  | 
| 195 |     p.addRect(x: 0, y: 0, w: 10, h: 10); | 
| 196 |     QVERIFY(p.capacity() > 0); | 
| 197 |  | 
| 198 |     p.clear(); | 
| 199 |     QVERIFY(p.capacity() > 0); | 
| 200 |  | 
| 201 |     p = QPainterPath{}; | 
| 202 |     QVERIFY(p.capacity() == 0); | 
| 203 |  | 
| 204 |     p.moveTo(x: 100, y: 100); | 
| 205 |     QVERIFY(p.capacity() > 1); | 
| 206 |  | 
| 207 |     p.reserve(size: 1000); | 
| 208 |     QVERIFY(p.capacity() >= 1000); | 
| 209 |  | 
| 210 |     p.reserve(size: 0); | 
| 211 |     QVERIFY(p.capacity() >= 1000); | 
| 212 |  | 
| 213 |     QPainterPath p2; | 
| 214 |     p2.reserve(size: 10); | 
| 215 |     QVERIFY(p.capacity() >= 10); | 
| 216 | } | 
| 217 |  | 
| 218 | Q_DECLARE_METATYPE(QPainterPath) | 
| 219 |  | 
| 220 | void tst_QPainterPath::currentPosition() | 
| 221 | { | 
| 222 |     QPainterPath p; | 
| 223 |  | 
| 224 |     QCOMPARE(p.currentPosition(), QPointF()); | 
| 225 |  | 
| 226 |     p.moveTo(x: 100, y: 100); | 
| 227 |     QCOMPARE(p.currentPosition(), QPointF(100, 100)); | 
| 228 |  | 
| 229 |     p.lineTo(x: 200, y: 200); | 
| 230 |     QCOMPARE(p.currentPosition(), QPointF(200, 200)); | 
| 231 |  | 
| 232 |     p.cubicTo(ctrlPt1x: 300, ctrlPt1y: 200, ctrlPt2x: 200, ctrlPt2y: 300, endPtx: 500, endPty: 500); | 
| 233 |     QCOMPARE(p.currentPosition(), QPointF(500, 500)); | 
| 234 | } | 
| 235 |  | 
| 236 | void tst_QPainterPath::contains_QPointF_data() | 
| 237 | { | 
| 238 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 239 |     QTest::addColumn<QPointF>(name: "pt" ); | 
| 240 |     QTest::addColumn<bool>(name: "contained" ); | 
| 241 |  | 
| 242 |     QPainterPath path; | 
| 243 |     path.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 244 |  | 
| 245 |     // ##### | 
| 246 |     // #   # | 
| 247 |     // #   # | 
| 248 |     // #   # | 
| 249 |     // ##### | 
| 250 |  | 
| 251 |     QTest::newRow(dataTag: "[0,0] in [0,0,100,100]" ) << path << QPointF(0, 0) << true; | 
| 252 |  | 
| 253 |     QTest::newRow(dataTag: "[99,0] in [0,0,100,100]" ) << path << QPointF(99, 0) << true; | 
| 254 |     QTest::newRow(dataTag: "[0,99] in [0,0,100,100]" ) << path << QPointF(0, 99) << true; | 
| 255 |     QTest::newRow(dataTag: "[99,99] in [0,0,100,100]" ) << path << QPointF(99, 99) << true; | 
| 256 |  | 
| 257 |     QTest::newRow(dataTag: "[99.99,0] in [0,0,100,100]" ) << path << QPointF(99.99, 0) << true; | 
| 258 |     QTest::newRow(dataTag: "[0,99.99] in [0,0,100,100]" ) << path << QPointF(0, 99.99) << true; | 
| 259 |     QTest::newRow(dataTag: "[99.99,99.99] in [0,0,100,100]" ) << path << QPointF(99.99, 99.99) << true; | 
| 260 |  | 
| 261 |     QTest::newRow(dataTag: "[0.01,0.01] in [0,0,100,100]" ) << path << QPointF(0.01, 0.01) << true; | 
| 262 |     QTest::newRow(dataTag: "[0,0.01] in [0,0,100,100]" ) << path << QPointF(0, 0.01) << true; | 
| 263 |     QTest::newRow(dataTag: "[0.01,0] in [0,0,100,100]" ) << path << QPointF(0.01, 0) << true; | 
| 264 |  | 
| 265 |     QTest::newRow(dataTag: "[-0.01,-0.01] in [0,0,100,100]" ) << path << QPointF(-0.01, -0.01) << false; | 
| 266 |     QTest::newRow(dataTag: "[-0,-0.01] in [0,0,100,100]" ) << path << QPointF(0, -0.01) << false; | 
| 267 |     QTest::newRow(dataTag: "[-0.01,0] in [0,0,100,100]" ) << path << QPointF(-0.01, 0) << false; | 
| 268 |  | 
| 269 |  | 
| 270 |     QTest::newRow(dataTag: "[-10,0] in [0,0,100,100]" ) << path << QPointF(-10, 0) << false; | 
| 271 |     QTest::newRow(dataTag: "[100,0] in [0,0,100,100]" ) << path << QPointF(100, 0) << false; | 
| 272 |  | 
| 273 |     QTest::newRow(dataTag: "[0,-10] in [0,0,100,100]" ) << path << QPointF(0, -10) << false; | 
| 274 |     QTest::newRow(dataTag: "[0,100] in [0,0,100,100]" ) << path << QPointF(0, 100) << false; | 
| 275 |  | 
| 276 |     QTest::newRow(dataTag: "[100.1,0] in [0,0,100,100]" ) << path << QPointF(100.1, 0) << false; | 
| 277 |     QTest::newRow(dataTag: "[0,100.1] in [0,0,100,100]" ) << path << QPointF(0, 100.1) << false; | 
| 278 |  | 
| 279 |     path.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 280 |  | 
| 281 |     // ##### | 
| 282 |     // #   # | 
| 283 |     // # ##### | 
| 284 |     // # # # # | 
| 285 |     // ##### # | 
| 286 |     //   #   # | 
| 287 |     //   ##### | 
| 288 |  | 
| 289 |     QTest::newRow(dataTag: "[49,49] in 2 rects" ) << path << QPointF(49,49) << true; | 
| 290 |     QTest::newRow(dataTag: "[50,50] in 2 rects" ) << path << QPointF(50,50) << false; | 
| 291 |     QTest::newRow(dataTag: "[100,100] in 2 rects" ) << path << QPointF(100,100) << true; | 
| 292 |  | 
| 293 |     path.setFillRule(Qt::WindingFill); | 
| 294 |     QTest::newRow(dataTag: "[50,50] in 2 rects (winding)" ) << path << QPointF(50,50) << true; | 
| 295 |  | 
| 296 |     path.addEllipse(x: 0, y: 0, w: 150, h: 150); | 
| 297 |  | 
| 298 |     // ##### | 
| 299 |     // ##  ## | 
| 300 |     // # ##### | 
| 301 |     // # # # # | 
| 302 |     // ##### # | 
| 303 |     //  ##  ## | 
| 304 |     //   ##### | 
| 305 |  | 
| 306 |     QTest::newRow(dataTag: "[50,50] in complex (winding)" ) << path << QPointF(50, 50) << true; | 
| 307 |  | 
| 308 |     path.setFillRule(Qt::OddEvenFill); | 
| 309 |     QTest::newRow(dataTag: "[50,50] in complex (windinf)" ) << path << QPointF(50, 50) << true; | 
| 310 |     QTest::newRow(dataTag: "[49,49] in complex" ) << path << QPointF(49,49) << false; | 
| 311 |     QTest::newRow(dataTag: "[100,100] in complex" ) << path << QPointF(49,49) << false; | 
| 312 |  | 
| 313 |  | 
| 314 |     // unclosed triangle | 
| 315 |     path = QPainterPath(); | 
| 316 |     path.moveTo(x: 100, y: 100); | 
| 317 |     path.lineTo(x: 130, y: 70); | 
| 318 |     path.lineTo(x: 150, y: 110); | 
| 319 |  | 
| 320 |     QTest::newRow(dataTag: "[100,100] in triangle" ) << path << QPointF(100, 100) << true; | 
| 321 |     QTest::newRow(dataTag: "[140,100] in triangle" ) << path << QPointF(140, 100) << true; | 
| 322 |     QTest::newRow(dataTag: "[130,80] in triangle" ) << path << QPointF(130, 80) << true; | 
| 323 |  | 
| 324 |     QTest::newRow(dataTag: "[110,80] in triangle" ) << path << QPointF(110, 80) << false; | 
| 325 |     QTest::newRow(dataTag: "[150,100] in triangle" ) << path << QPointF(150, 100) << false; | 
| 326 |     QTest::newRow(dataTag: "[120,110] in triangle" ) << path << QPointF(120, 110) << false; | 
| 327 |  | 
| 328 |     QRectF base_rect(0, 0, 20, 20); | 
| 329 |  | 
| 330 |     path = QPainterPath(); | 
| 331 |     path.addEllipse(rect: base_rect); | 
| 332 |  | 
| 333 |     // not strictly precise, but good enougth to verify fair precision. | 
| 334 |     QPainterPath inside; | 
| 335 |     inside.addEllipse(rect: base_rect.adjusted(xp1: 5, yp1: 5, xp2: -5, yp2: -5)); | 
| 336 |     QPolygonF inside_poly = inside.toFillPolygon(); | 
| 337 |     for (int i=0; i<inside_poly.size(); ++i) | 
| 338 |         QTest::newRow(dataTag: ("inside_ellipse "  + QByteArray::number(i)).constData()) << path << inside_poly.at(i) << true; | 
| 339 |  | 
| 340 |     QPainterPath outside; | 
| 341 |     outside.addEllipse(rect: base_rect.adjusted(xp1: -5, yp1: -5, xp2: 5, yp2: 5)); | 
| 342 |     QPolygonF outside_poly = outside.toFillPolygon(); | 
| 343 |     for (int i=0; i<outside_poly.size(); ++i) | 
| 344 |         QTest::newRow(dataTag: ("outside_ellipse "  + QByteArray::number(i)).constData()) << path << outside_poly.at(i) << false; | 
| 345 |  | 
| 346 |     path = QPainterPath(); | 
| 347 |     base_rect = QRectF(50, 50, 200, 200); | 
| 348 |     path.addEllipse(rect: base_rect); | 
| 349 |     path.setFillRule(Qt::WindingFill); | 
| 350 |  | 
| 351 |     QTest::newRow(dataTag: "topleft outside ellipse" ) << path << base_rect.topLeft() << false; | 
| 352 |     QTest::newRow(dataTag: "topright outside ellipse" ) << path << base_rect.topRight() << false; | 
| 353 |     QTest::newRow(dataTag: "bottomright outside ellipse" ) << path << base_rect.bottomRight() << false; | 
| 354 |     QTest::newRow(dataTag: "bottomleft outside ellipse" ) << path << base_rect.bottomLeft() << false; | 
| 355 |  | 
| 356 |     // Test horizontal curve segment | 
| 357 |     path = QPainterPath(); | 
| 358 |     path.moveTo(x: 100, y: 100); | 
| 359 |     path.cubicTo(ctrlPt1x: 120, ctrlPt1y: 100, ctrlPt2x: 180, ctrlPt2y: 100, endPtx: 200, endPty: 100); | 
| 360 |     path.lineTo(x: 150, y: 200); | 
| 361 |     path.closeSubpath(); | 
| 362 |  | 
| 363 |     QTest::newRow(dataTag: "horizontal cubic, out left" ) << path << QPointF(0, 100) << false; | 
| 364 |     QTest::newRow(dataTag: "horizontal cubic, out right" ) << path << QPointF(300, 100) <<false; | 
| 365 |     QTest::newRow(dataTag: "horizontal cubic, in mid" ) << path << QPointF(150, 100) << true; | 
| 366 |  | 
| 367 |     path = QPainterPath(); | 
| 368 |     path.addEllipse(rect: QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0)); | 
| 369 |     QTest::newRow(dataTag: "huge ellipse, qreal=float crash" ) << path << QPointF(1100000.35, 1098000.2) << true; | 
| 370 |  | 
| 371 | } | 
| 372 |  | 
| 373 | void tst_QPainterPath::contains_QPointF() | 
| 374 | { | 
| 375 |     QFETCH(QPainterPath, path); | 
| 376 |     QFETCH(QPointF, pt); | 
| 377 |     QFETCH(bool, contained); | 
| 378 |  | 
| 379 |     QCOMPARE(path.contains(pt), contained); | 
| 380 | } | 
| 381 |  | 
| 382 | void tst_QPainterPath::contains_QRectF_data() | 
| 383 | { | 
| 384 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 385 |     QTest::addColumn<QRectF>(name: "rect" ); | 
| 386 |     QTest::addColumn<bool>(name: "contained" ); | 
| 387 |  | 
| 388 |     QPainterPath path; | 
| 389 |     path.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 390 |  | 
| 391 |     QTest::newRow(dataTag: "same rect" ) << path << QRectF(0.1, 0.1, 99, 99) << true; // ### | 
| 392 |     QTest::newRow(dataTag: "outside" ) << path << QRectF(-1, -1, 100, 100) << false; | 
| 393 |     QTest::newRow(dataTag: "covers" ) << path << QRectF(-1, -1, 102, 102) << false; | 
| 394 |     QTest::newRow(dataTag: "left" ) << path << QRectF(-10, 50, 5, 5) << false; | 
| 395 |     QTest::newRow(dataTag: "top" ) << path << QRectF(50, -10, 5, 5) << false; | 
| 396 |     QTest::newRow(dataTag: "right" ) << path << QRectF(110, 50, 5, 5) << false; | 
| 397 |     QTest::newRow(dataTag: "bottom" ) << path << QRectF(50, 110, 5, 5) << false; | 
| 398 |  | 
| 399 |     path.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 400 |  | 
| 401 |     QTest::newRow(dataTag: "r1 top" ) << path << QRectF(0.1, 0.1, 99, 49) << true; | 
| 402 |     QTest::newRow(dataTag: "r1 left" ) << path << QRectF(0.1, 0.1, 49, 99) << true; | 
| 403 |     QTest::newRow(dataTag: "r2 right" ) << path << QRectF(100.01, 50.1, 49, 99) << true; | 
| 404 |     QTest::newRow(dataTag: "r2 bottom" ) << path << QRectF(50.1, 100.1, 99, 49) << true; | 
| 405 |     QTest::newRow(dataTag: "inside 2 rects" ) << path << QRectF(51, 51, 48, 48) << false; | 
| 406 |     QTest::newRow(dataTag: "topRight 2 rects" ) << path << QRectF(100, 0, 49, 49) << false; | 
| 407 |     QTest::newRow(dataTag: "bottomLeft 2 rects" ) << path << QRectF(0, 100, 49, 49) << false; | 
| 408 |  | 
| 409 |     path.setFillRule(Qt::WindingFill); | 
| 410 |     QTest::newRow(dataTag: "inside 2 rects (winding)" ) << path << QRectF(51, 51, 48, 48) << true; | 
| 411 |  | 
| 412 |     path.addEllipse(x: 0, y: 0, w: 150, h: 150); | 
| 413 |     QTest::newRow(dataTag: "topRight 2 rects" ) << path << QRectF(100, 25, 24, 24) << true; | 
| 414 |     QTest::newRow(dataTag: "bottomLeft 2 rects" ) << path << QRectF(25, 100, 24, 24) << true; | 
| 415 |  | 
| 416 |     path.setFillRule(Qt::OddEvenFill); | 
| 417 |     QTest::newRow(dataTag: "inside 2 rects" ) << path << QRectF(50, 50, 49, 49) << false; | 
| 418 | } | 
| 419 |  | 
| 420 | void tst_QPainterPath::contains_QRectF() | 
| 421 | { | 
| 422 |     QFETCH(QPainterPath, path); | 
| 423 |     QFETCH(QRectF, rect); | 
| 424 |     QFETCH(bool, contained); | 
| 425 |  | 
| 426 |     QCOMPARE(path.contains(rect), contained); | 
| 427 | } | 
| 428 |  | 
| 429 | static inline QPainterPath rectPath(qreal x, qreal y, qreal w, qreal h) | 
| 430 | { | 
| 431 |     QPainterPath path; | 
| 432 |     path.addRect(x, y, w, h); | 
| 433 |     path.closeSubpath(); | 
| 434 |     return path; | 
| 435 | } | 
| 436 |  | 
| 437 | static inline QPainterPath ellipsePath(qreal x, qreal y, qreal w, qreal h) | 
| 438 | { | 
| 439 |     QPainterPath path; | 
| 440 |     path.addEllipse(x, y, w, h); | 
| 441 |     path.closeSubpath(); | 
| 442 |     return path; | 
| 443 | } | 
| 444 |  | 
| 445 | static inline QPainterPath linePath(qreal x1, qreal y1, qreal x2, qreal y2) | 
| 446 | { | 
| 447 |     QPainterPath path; | 
| 448 |     path.moveTo(x: x1, y: y1); | 
| 449 |     path.lineTo(x: x2, y: y2); | 
| 450 |     return path; | 
| 451 | } | 
| 452 |  | 
| 453 | void tst_QPainterPath::intersects_QRectF_data() | 
| 454 | { | 
| 455 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 456 |     QTest::addColumn<QRectF>(name: "rect" ); | 
| 457 |     QTest::addColumn<bool>(name: "intersects" ); | 
| 458 |  | 
| 459 |     QPainterPath path; | 
| 460 |     path.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 461 |  | 
| 462 |     QTest::newRow(dataTag: "same rect" ) << path << QRectF(0.1, 0.1, 99, 99) << true; // ### | 
| 463 |     QTest::newRow(dataTag: "outside" ) << path << QRectF(-1, -1, 100, 100) << true; | 
| 464 |     QTest::newRow(dataTag: "covers" ) << path << QRectF(-1, -1, 102, 102) << true; | 
| 465 |     QTest::newRow(dataTag: "left" ) << path << QRectF(-10, 50, 5, 5) << false; | 
| 466 |     QTest::newRow(dataTag: "top" ) << path << QRectF(50, -10, 5, 5) << false; | 
| 467 |     QTest::newRow(dataTag: "right" ) << path << QRectF(110, 50, 5, 5) << false; | 
| 468 |     QTest::newRow(dataTag: "bottom" ) << path << QRectF(50, 110, 5, 5) << false; | 
| 469 |  | 
| 470 |     path.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 471 |  | 
| 472 |     QTest::newRow(dataTag: "r1 top" ) << path << QRectF(0.1, 0.1, 99, 49) << true; | 
| 473 |     QTest::newRow(dataTag: "r1 left" ) << path << QRectF(0.1, 0.1, 49, 99) << true; | 
| 474 |     QTest::newRow(dataTag: "r2 right" ) << path << QRectF(100.01, 50.1, 49, 99) << true; | 
| 475 |     QTest::newRow(dataTag: "r2 bottom" ) << path << QRectF(50.1, 100.1, 99, 49) << true; | 
| 476 |     QTest::newRow(dataTag: "inside 2 rects" ) << path << QRectF(51, 51, 48, 48) << false; | 
| 477 |  | 
| 478 |     path.setFillRule(Qt::WindingFill); | 
| 479 |     QTest::newRow(dataTag: "inside 2 rects (winding)" ) << path << QRectF(51, 51, 48, 48) << true; | 
| 480 |  | 
| 481 |     path.addEllipse(x: 0, y: 0, w: 150, h: 150); | 
| 482 |     QTest::newRow(dataTag: "topRight 2 rects" ) << path << QRectF(100, 25, 24, 24) << true; | 
| 483 |     QTest::newRow(dataTag: "bottomLeft 2 rects" ) << path << QRectF(25, 100, 24, 24) << true; | 
| 484 |  | 
| 485 |     QTest::newRow(dataTag: "horizontal line" ) << linePath(x1: 0, y1: 0, x2: 10, y2: 0) << QRectF(1, -1, 2, 2) << true; | 
| 486 |     QTest::newRow(dataTag: "vertical line" ) << linePath(x1: 0, y1: 0, x2: 0, y2: 10) << QRectF(-1, 1, 2, 2) << true; | 
| 487 |  | 
| 488 |     path = QPainterPath(); | 
| 489 |     path.addEllipse(rect: QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0)); | 
| 490 |     QTest::newRow(dataTag: "huge ellipse, qreal=float crash" ) << path << QRectF(1100000.35, 1098000.2, 1500000.0, 1500000.0) << true; | 
| 491 | } | 
| 492 |  | 
| 493 | void tst_QPainterPath::intersects_QRectF() | 
| 494 | { | 
| 495 |     QFETCH(QPainterPath, path); | 
| 496 |     QFETCH(QRectF, rect); | 
| 497 |     QFETCH(bool, intersects); | 
| 498 |  | 
| 499 |     QCOMPARE(path.intersects(rect), intersects); | 
| 500 | } | 
| 501 |  | 
| 502 |  | 
| 503 | void tst_QPainterPath::testContainsAndIntersects_data() | 
| 504 | { | 
| 505 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 506 |     QTest::addColumn<QPainterPath>(name: "candidate" ); | 
| 507 |     QTest::addColumn<bool>(name: "contained" ); | 
| 508 |     QTest::addColumn<bool>(name: "intersects" ); | 
| 509 |  | 
| 510 |     QTest::newRow(dataTag: "rect vs small ellipse (upper left)" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 0, y: 0, w: 50, h: 50) << false << true; | 
| 511 |     QTest::newRow(dataTag: "rect vs small ellipse (upper right)" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 50, y: 0, w: 50, h: 50) << false << true; | 
| 512 |     QTest::newRow(dataTag: "rect vs small ellipse (lower right)" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 50, y: 50, w: 50, h: 50) << false << true; | 
| 513 |     QTest::newRow(dataTag: "rect vs small ellipse (lower left)" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 0, y: 50, w: 50, h: 50) << false << true; | 
| 514 |     QTest::newRow(dataTag: "rect vs small ellipse (centered)" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 25, y: 25, w: 50, h: 50) << true << true; | 
| 515 |     QTest::newRow(dataTag: "rect vs equal ellipse" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 0, y: 0, w: 100, h: 100) << false << true; | 
| 516 |     QTest::newRow(dataTag: "rect vs big ellipse" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: -10, y: -10, w: 120, h: 120) << false << true; | 
| 517 |  | 
| 518 |     QPainterPath twoEllipses = ellipsePath(x: 0, y: 0, w: 100, h: 100).united(r: ellipsePath(x: 200, y: 0, w: 100, h: 100)); | 
| 519 |  | 
| 520 |     QTest::newRow(dataTag: "rect vs two small ellipses" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 25, y: 25, w: 50, h: 50).united(r: ellipsePath(x: 225, y: 25, w: 50, h: 50)) << false << true; | 
| 521 |     QTest::newRow(dataTag: "rect vs two equal ellipses" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << twoEllipses << false << true; | 
| 522 |  | 
| 523 |     QTest::newRow(dataTag: "rect vs self" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << rectPath(x: 0, y: 0, w: 100, h: 100) << false << true; | 
| 524 |     QTest::newRow(dataTag: "ellipse vs self" ) << ellipsePath(x: 0, y: 0, w: 100, h: 100) << ellipsePath(x: 0, y: 0, w: 100, h: 100) << false << true; | 
| 525 |  | 
| 526 |     QPainterPath twoRects = rectPath(x: 0, y: 0, w: 100, h: 100).united(r: rectPath(x: 200, y: 0, w: 100, h: 100)); | 
| 527 |     QTest::newRow(dataTag: "two rects vs small ellipse (upper left)" ) << twoRects << ellipsePath(x: 0, y: 0, w: 50, h: 50) << false << true; | 
| 528 |     QTest::newRow(dataTag: "two rects vs small ellipse (upper right)" ) << twoRects << ellipsePath(x: 50, y: 0, w: 50, h: 50) << false << true; | 
| 529 |     QTest::newRow(dataTag: "two rects vs small ellipse (lower right)" ) << twoRects << ellipsePath(x: 50, y: 50, w: 50, h: 50) << false << true; | 
| 530 |     QTest::newRow(dataTag: "two rects vs small ellipse (lower left)" ) << twoRects << ellipsePath(x: 0, y: 50, w: 50, h: 50) << false << true; | 
| 531 |     QTest::newRow(dataTag: "two rects vs small ellipse (centered)" ) << twoRects << ellipsePath(x: 25, y: 25, w: 50, h: 50) << true << true; | 
| 532 |     QTest::newRow(dataTag: "two rects vs equal ellipse" ) << twoRects << ellipsePath(x: 0, y: 0, w: 100, h: 100) << false << true; | 
| 533 |     QTest::newRow(dataTag: "two rects vs big ellipse" ) << twoRects << ellipsePath(x: -10, y: -10, w: 120, h: 120) << false << true; | 
| 534 |  | 
| 535 |     QTest::newRow(dataTag: "two rects vs two small ellipses" ) << twoRects << ellipsePath(x: 25, y: 25, w: 50, h: 50).united(r: ellipsePath(x: 225, y: 25, w: 50, h: 50)) << true << true; | 
| 536 |     QTest::newRow(dataTag: "two rects vs two equal ellipses" ) << twoRects << ellipsePath(x: 0, y: 0, w: 100, h: 100).united(r: ellipsePath(x: 200, y: 0, w: 100, h: 100)) << false << true; | 
| 537 |  | 
| 538 |     QTest::newRow(dataTag: "two rects vs self" ) << twoRects << twoRects << false << true; | 
| 539 |     QTest::newRow(dataTag: "two ellipses vs self" ) << twoEllipses << twoEllipses << false << true; | 
| 540 |  | 
| 541 |     QPainterPath windingRect = rectPath(x: 0, y: 0, w: 100, h: 100); | 
| 542 |     windingRect.addRect(x: 25, y: 25, w: 100, h: 50); | 
| 543 |     windingRect.setFillRule(Qt::WindingFill); | 
| 544 |  | 
| 545 |     QTest::newRow(dataTag: "rect with winding rule vs tall rect" ) << windingRect << rectPath(x: 40, y: 20, w: 20, h: 60) << true << true; | 
| 546 |     QTest::newRow(dataTag: "rect with winding rule vs self" ) << windingRect << windingRect << false << true; | 
| 547 |  | 
| 548 |     QPainterPath thickFrame = rectPath(x: 0, y: 0, w: 100, h: 100).subtracted(r: rectPath(x: 25, y: 25, w: 50, h: 50)); | 
| 549 |     QPainterPath thinFrame = rectPath(x: 10, y: 10, w: 80, h: 80).subtracted(r: rectPath(x: 15, y: 15, w: 70, h: 70)); | 
| 550 |  | 
| 551 |     QTest::newRow(dataTag: "thin frame in thick frame" ) << thickFrame << thinFrame << true << true; | 
| 552 |     QTest::newRow(dataTag: "rect in thick frame" ) << thickFrame << rectPath(x: 40, y: 40, w: 20, h: 20) << false << false; | 
| 553 |     QTest::newRow(dataTag: "rect in thin frame" ) << thinFrame << rectPath(x: 40, y: 40, w: 20, h: 20) << false << false; | 
| 554 |  | 
| 555 |     QPainterPath ellipses; | 
| 556 |     ellipses.addEllipse(x: 0, y: 0, w: 10, h: 10); | 
| 557 |     ellipses.addEllipse(x: 4, y: 4, w: 2, h: 2); | 
| 558 |     ellipses.setFillRule(Qt::WindingFill); | 
| 559 |  | 
| 560 |     // the definition of QPainterPath::intersects() and contains() is fill-area based, | 
| 561 |     QTest::newRow(dataTag: "line in rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: 10, y1: 10, x2: 90, y2: 90) << true << true; | 
| 562 |     QTest::newRow(dataTag: "horizontal line in rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: 10, y1: 50, x2: 90, y2: 50) << true << true; | 
| 563 |     QTest::newRow(dataTag: "vertical line in rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: 50, y1: 10, x2: 50, y2: 90) << true << true; | 
| 564 |  | 
| 565 |     QTest::newRow(dataTag: "line through rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: -10, y1: -10, x2: 110, y2: 110) << false << true; | 
| 566 |     QTest::newRow(dataTag: "line through rect 2" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: -10, y1: 0, x2: 110, y2: 100) << false << true; | 
| 567 |     QTest::newRow(dataTag: "line through rect 3" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: 5, y1: 10, x2: 110, y2: 100) << false << true; | 
| 568 |     QTest::newRow(dataTag: "line through rect 4" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: -10, y1: 0, x2: 90, y2: 90) << false << true; | 
| 569 |  | 
| 570 |     QTest::newRow(dataTag: "horizontal line through rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: -10, y1: 50, x2: 110, y2: 50) << false << true; | 
| 571 |     QTest::newRow(dataTag: "vertical line through rect" ) << rectPath(x: 0, y: 0, w: 100, h: 100) << linePath(x1: 50, y1: -10, x2: 50, y2: 110) << false << true; | 
| 572 |  | 
| 573 |     QTest::newRow(dataTag: "line vs line" ) << linePath(x1: 0, y1: 0, x2: 10, y2: 10) << linePath(x1: 10, y1: 0, x2: 0, y2: 10) << false << true; | 
| 574 |  | 
| 575 |     QTest::newRow(dataTag: "line in rect with hole" ) << rectPath(x: 0, y: 0, w: 10, h: 10).subtracted(r: rectPath(x: 2, y: 2, w: 6, h: 6)) << linePath(x1: 4, y1: 4, x2: 6, y2: 6) << false << false; | 
| 576 |     QTest::newRow(dataTag: "line in ellipse" ) << ellipses << linePath(x1: 3, y1: 5, x2: 7, y2: 5) << false << true; | 
| 577 |     QTest::newRow(dataTag: "line in ellipse 2" ) << ellipses << linePath(x1: 4.5, y1: 5, x2: 5.5, y2: 5) << true << true; | 
| 578 |  | 
| 579 |     QTest::newRow(dataTag: "winding ellipse" ) << ellipses << ellipsePath(x: 4, y: 4, w: 2, h: 2) << false << true; | 
| 580 |     QTest::newRow(dataTag: "winding ellipse 2" ) << ellipses << ellipsePath(x: 4.5, y: 4.5, w: 1, h: 1) << true << true; | 
| 581 |     ellipses.setFillRule(Qt::OddEvenFill); | 
| 582 |     QTest::newRow(dataTag: "odd even ellipse" ) << ellipses << ellipsePath(x: 4, y: 4, w: 2, h: 2) << false << true; | 
| 583 |     QTest::newRow(dataTag: "odd even ellipse 2" ) << ellipses << ellipsePath(x: 4.5, y: 4.5, w: 1, h: 1) << false << false; | 
| 584 | } | 
| 585 |  | 
| 586 | void tst_QPainterPath::testContainsAndIntersects() | 
| 587 | { | 
| 588 |     QFETCH(QPainterPath, path); | 
| 589 |     QFETCH(QPainterPath, candidate); | 
| 590 |     QFETCH(bool, contained); | 
| 591 |     QFETCH(bool, intersects); | 
| 592 |  | 
| 593 |     QCOMPARE(path.intersects(candidate), intersects); | 
| 594 |     QCOMPARE(path.contains(candidate), contained); | 
| 595 | } | 
| 596 |  | 
| 597 | void tst_QPainterPath::testSimplified_data() | 
| 598 | { | 
| 599 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 600 |     QTest::addColumn<int>(name: "elements" ); | 
| 601 |  | 
| 602 |     QTest::newRow(dataTag: "rect" ) << rectPath(x: 0, y: 0, w: 10, h: 10) << 5; | 
| 603 |  | 
| 604 |     QPainterPath twoRects = rectPath(x: 0, y: 0, w: 10, h: 10); | 
| 605 |     twoRects.addPath(path: rectPath(x: 5, y: 0, w: 10, h: 10)); | 
| 606 |     QTest::newRow(dataTag: "two rects (odd)" ) << twoRects << 10; | 
| 607 |  | 
| 608 |     twoRects.setFillRule(Qt::WindingFill); | 
| 609 |     QTest::newRow(dataTag: "two rects (winding)" ) << twoRects << 5; | 
| 610 |  | 
| 611 |     QPainterPath threeSteps = rectPath(x: 0, y: 0, w: 10, h: 10); | 
| 612 |     threeSteps.addPath(path: rectPath(x: 0, y: 10, w: 20, h: 10)); | 
| 613 |     threeSteps.addPath(path: rectPath(x: 0, y: 20, w: 30, h: 10)); | 
| 614 |  | 
| 615 |     QTest::newRow(dataTag: "three rects (steps)" ) << threeSteps << 9; | 
| 616 | } | 
| 617 |  | 
| 618 | void tst_QPainterPath::testSimplified() | 
| 619 | { | 
| 620 |     QFETCH(QPainterPath, path); | 
| 621 |     QFETCH(int, elements); | 
| 622 |  | 
| 623 |     QPainterPath simplified = path.simplified(); | 
| 624 |  | 
| 625 |     QCOMPARE(simplified.elementCount(), elements); | 
| 626 |  | 
| 627 |     QVERIFY(simplified.subtracted(path).isEmpty()); | 
| 628 |     QVERIFY(path.subtracted(simplified).isEmpty()); | 
| 629 | } | 
| 630 |  | 
| 631 | void tst_QPainterPath::testStroker_data() | 
| 632 | { | 
| 633 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 634 |     QTest::addColumn<QPen>(name: "pen" ); | 
| 635 |     QTest::addColumn<QPainterPath>(name: "stroke" ); | 
| 636 |  | 
| 637 |     QTest::newRow(dataTag: "line 1" ) << linePath(x1: 2, y1: 2, x2: 10, y2: 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::FlatCap) << rectPath(x: 2, y: 1, w: 8, h: 2); | 
| 638 |     QTest::newRow(dataTag: "line 2" ) << linePath(x1: 2, y1: 2, x2: 10, y2: 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap) << rectPath(x: 1, y: 1, w: 10, h: 2); | 
| 639 |  | 
| 640 |     QTest::newRow(dataTag: "rect" ) << rectPath(x: 1, y: 1, w: 8, h: 8) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) << rectPath(x: 0, y: 0, w: 10, h: 10).subtracted(r: rectPath(x: 2, y: 2, w: 6, h: 6)); | 
| 641 |  | 
| 642 |     QTest::newRow(dataTag: "dotted line" ) << linePath(x1: 0, y1: 0, x2: 10, y2: 0) << QPen(Qt::black, 2, Qt::DotLine) << rectPath(x: -1, y: -1, w: 4, h: 2).united(r: rectPath(x: 5, y: -1, w: 4, h: 2)); | 
| 643 | } | 
| 644 |  | 
| 645 | void tst_QPainterPath::testStroker() | 
| 646 | { | 
| 647 |     QFETCH(QPainterPath, path); | 
| 648 |     QFETCH(QPen, pen); | 
| 649 |     QFETCH(QPainterPath, stroke); | 
| 650 |  | 
| 651 |     QPainterPathStroker stroker; | 
| 652 |     stroker.setWidth(pen.widthF()); | 
| 653 |     stroker.setCapStyle(pen.capStyle()); | 
| 654 |     stroker.setJoinStyle(pen.joinStyle()); | 
| 655 |     stroker.setMiterLimit(pen.miterLimit()); | 
| 656 |     stroker.setDashPattern(pen.style()); | 
| 657 |     stroker.setDashOffset(pen.dashOffset()); | 
| 658 |  | 
| 659 |     QPainterPath result = stroker.createStroke(path); | 
| 660 |  | 
| 661 |     // check if stroke == result | 
| 662 |     QVERIFY(result.subtracted(stroke).isEmpty()); | 
| 663 |     QVERIFY(stroke.subtracted(result).isEmpty()); | 
| 664 | } | 
| 665 |  | 
| 666 | void tst_QPainterPath::testOperatorEquals() | 
| 667 | { | 
| 668 |     QPainterPath empty1; | 
| 669 |     QPainterPath empty2; | 
| 670 |     QCOMPARE(empty1, empty2); | 
| 671 |  | 
| 672 |     QPainterPath rect1; | 
| 673 |     rect1.addRect(x: 100, y: 100, w: 100, h: 100); | 
| 674 |     QCOMPARE(rect1, rect1); | 
| 675 |     QVERIFY(rect1 != empty1); | 
| 676 |  | 
| 677 |     QPainterPath rect2; | 
| 678 |     rect2.addRect(x: 100, y: 100, w: 100, h: 100); | 
| 679 |     QCOMPARE(rect1, rect2); | 
| 680 |  | 
| 681 |     rect2.setFillRule(Qt::WindingFill); | 
| 682 |     QVERIFY(rect1 != rect2); | 
| 683 |  | 
| 684 |     QPainterPath ellipse1; | 
| 685 |     ellipse1.addEllipse(x: 50, y: 50, w: 100, h: 100); | 
| 686 |     QVERIFY(rect1 != ellipse1); | 
| 687 |  | 
| 688 |     QPainterPath ellipse2; | 
| 689 |     ellipse2.addEllipse(x: 50, y: 50, w: 100, h: 100); | 
| 690 |     QCOMPARE(ellipse1, ellipse2); | 
| 691 | } | 
| 692 |  | 
| 693 | void tst_QPainterPath::testOperatorEquals_fuzzy() | 
| 694 | { | 
| 695 |     // if operator== returns true for two paths it should | 
| 696 |     // also return true when the same transform is applied to both paths | 
| 697 |     { | 
| 698 |         QRectF a(100, 100, 100, 50); | 
| 699 |         QRectF b = a.translated(dx: 1e-14, dy: 1e-14); | 
| 700 |  | 
| 701 |         QPainterPath pa; | 
| 702 |         pa.addRect(rect: a); | 
| 703 |         QPainterPath pb; | 
| 704 |         pb.addRect(rect: b); | 
| 705 |  | 
| 706 |         QCOMPARE(pa, pb); | 
| 707 |  | 
| 708 |         QTransform transform; | 
| 709 |         transform.translate(dx: -100, dy: -100); | 
| 710 |  | 
| 711 |         QCOMPARE(transform.map(pa), transform.map(pb)); | 
| 712 |     } | 
| 713 |  | 
| 714 |     // higher tolerance for error when path's bounding rect is big | 
| 715 |     { | 
| 716 |         QRectF a(1, 1, 1e6, 0.5e6); | 
| 717 |         QRectF b = a.translated(dx: 1e-7, dy: 1e-7); | 
| 718 |  | 
| 719 |         QPainterPath pa; | 
| 720 |         pa.addRect(rect: a); | 
| 721 |         QPainterPath pb; | 
| 722 |         pb.addRect(rect: b); | 
| 723 |  | 
| 724 |         QCOMPARE(pa, pb); | 
| 725 |  | 
| 726 |         QTransform transform; | 
| 727 |         transform.translate(dx: -1, dy: -1); | 
| 728 |  | 
| 729 |         QCOMPARE(transform.map(pa), transform.map(pb)); | 
| 730 |     } | 
| 731 |  | 
| 732 |     // operator== should return true for a path that has | 
| 733 |     // been transformed and then inverse transformed | 
| 734 |     { | 
| 735 |         QPainterPath a; | 
| 736 |         a.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 737 |  | 
| 738 |         QTransform transform; | 
| 739 |         transform.translate(dx: 100, dy: 20); | 
| 740 |         transform.scale(sx: 1.5, sy: 1.5); | 
| 741 |  | 
| 742 |         QPainterPath b = transform.inverted().map(p: transform.map(p: a)); | 
| 743 |  | 
| 744 |         QCOMPARE(a, b); | 
| 745 |     } | 
| 746 |  | 
| 747 |     { | 
| 748 |         QPainterPath a; | 
| 749 |         a.lineTo(x: 10, y: 0); | 
| 750 |         a.lineTo(x: 10, y: 10); | 
| 751 |         a.lineTo(x: 0, y: 10); | 
| 752 |  | 
| 753 |         QPainterPath b; | 
| 754 |         b.lineTo(x: 10, y: 0); | 
| 755 |         b.moveTo(x: 10, y: 10); | 
| 756 |         b.lineTo(x: 0, y: 10); | 
| 757 |  | 
| 758 |         QVERIFY(a != b); | 
| 759 |     } | 
| 760 | } | 
| 761 |  | 
| 762 | void tst_QPainterPath::testOperatorDatastream() | 
| 763 | { | 
| 764 |     QPainterPath path; | 
| 765 |     path.addEllipse(x: 0, y: 0, w: 100, h: 100); | 
| 766 |     path.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 767 |     path.setFillRule(Qt::WindingFill); | 
| 768 |  | 
| 769 |     QTemporaryDir tempDir(QDir::tempPath() + "/tst_qpainterpath.XXXXXX" ); | 
| 770 |     QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); | 
| 771 |     // Write out | 
| 772 |     { | 
| 773 |         QFile data(tempDir.path() + "/data" ); | 
| 774 |         bool ok = data.open(flags: QFile::WriteOnly); | 
| 775 |         QVERIFY(ok); | 
| 776 |         QDataStream stream(&data); | 
| 777 |         stream << path; | 
| 778 |     } | 
| 779 |  | 
| 780 |     QPainterPath other; | 
| 781 |     // Read in | 
| 782 |     { | 
| 783 |         QFile data(tempDir.path() + "/data" ); | 
| 784 |         bool ok = data.open(flags: QFile::ReadOnly); | 
| 785 |         QVERIFY(ok); | 
| 786 |         QDataStream stream(&data); | 
| 787 |         stream >> other; | 
| 788 |     } | 
| 789 |  | 
| 790 |     QCOMPARE(other, path); | 
| 791 | } | 
| 792 |  | 
| 793 | void tst_QPainterPath::closing() | 
| 794 | { | 
| 795 |     // lineto's | 
| 796 |     { | 
| 797 |         QPainterPath triangle(QPoint(100, 100)); | 
| 798 |  | 
| 799 |         triangle.lineTo(x: 200, y: 100); | 
| 800 |         triangle.lineTo(x: 200, y: 200); | 
| 801 |         QCOMPARE(triangle.elementCount(), 3); | 
| 802 |  | 
| 803 |         //add this line to make sure closeSubpath() also calls detach() and detached properly | 
| 804 |         QPainterPath copied = triangle; | 
| 805 |         triangle.closeSubpath(); | 
| 806 |         QCOMPARE(copied.elementCount(), 3); | 
| 807 |  | 
| 808 |         QCOMPARE(triangle.elementCount(), 4); | 
| 809 |         QCOMPARE(triangle.elementAt(3).type, QPainterPath::LineToElement); | 
| 810 |  | 
| 811 |         triangle.moveTo(x: 300, y: 300); | 
| 812 |         QCOMPARE(triangle.elementCount(), 5); | 
| 813 |         QCOMPARE(triangle.elementAt(4).type, QPainterPath::MoveToElement); | 
| 814 |  | 
| 815 |         triangle.lineTo(x: 400, y: 300); | 
| 816 |         triangle.lineTo(x: 400, y: 400); | 
| 817 |         QCOMPARE(triangle.elementCount(), 7); | 
| 818 |  | 
| 819 |         triangle.closeSubpath(); | 
| 820 |         QCOMPARE(triangle.elementCount(), 8); | 
| 821 |  | 
| 822 |         // this will should trigger implicit moveto... | 
| 823 |         triangle.lineTo(x: 600, y: 300); | 
| 824 |         QCOMPARE(triangle.elementCount(), 10); | 
| 825 |         QCOMPARE(triangle.elementAt(8).type, QPainterPath::MoveToElement); | 
| 826 |         QCOMPARE(triangle.elementAt(9).type, QPainterPath::LineToElement); | 
| 827 |  | 
| 828 |         triangle.lineTo(x: 600, y: 700); | 
| 829 |         QCOMPARE(triangle.elementCount(), 11); | 
| 830 |     } | 
| 831 |  | 
| 832 |     // curveto's | 
| 833 |     { | 
| 834 |         QPainterPath curves(QPoint(100, 100)); | 
| 835 |  | 
| 836 |         curves.cubicTo(ctrlPt1x: 200, ctrlPt1y: 100, ctrlPt2x: 100, ctrlPt2y: 200, endPtx: 200, endPty: 200); | 
| 837 |         QCOMPARE(curves.elementCount(), 4); | 
| 838 |  | 
| 839 |         curves.closeSubpath(); | 
| 840 |         QCOMPARE(curves.elementCount(), 5); | 
| 841 |         QCOMPARE(curves.elementAt(4).type, QPainterPath::LineToElement); | 
| 842 |  | 
| 843 |         curves.moveTo(x: 300, y: 300); | 
| 844 |         QCOMPARE(curves.elementCount(), 6); | 
| 845 |         QCOMPARE(curves.elementAt(5).type, QPainterPath::MoveToElement); | 
| 846 |  | 
| 847 |         curves.cubicTo(ctrlPt1x: 400, ctrlPt1y: 300, ctrlPt2x: 300, ctrlPt2y: 400, endPtx: 400, endPty: 400); | 
| 848 |         QCOMPARE(curves.elementCount(), 9); | 
| 849 |  | 
| 850 |         curves.closeSubpath(); | 
| 851 |         QCOMPARE(curves.elementCount(), 10); | 
| 852 |  | 
| 853 |         // should trigger implicit moveto.. | 
| 854 |         curves.cubicTo(ctrlPt1x: 100, ctrlPt1y: 800, ctrlPt2x: 800, ctrlPt2y: 100, endPtx: 800, endPty: 800); | 
| 855 |         QCOMPARE(curves.elementCount(), 14); | 
| 856 |         QCOMPARE(curves.elementAt(10).type, QPainterPath::MoveToElement); | 
| 857 |         QCOMPARE(curves.elementAt(11).type, QPainterPath::CurveToElement); | 
| 858 |     } | 
| 859 |  | 
| 860 |     { | 
| 861 |         QPainterPath rects; | 
| 862 |         rects.addRect(x: 100, y: 100, w: 100, h: 100); | 
| 863 |  | 
| 864 |         QCOMPARE(rects.elementCount(), 5); | 
| 865 |         QCOMPARE(rects.elementAt(0).type, QPainterPath::MoveToElement); | 
| 866 |         QCOMPARE(rects.elementAt(4).type, QPainterPath::LineToElement); | 
| 867 |  | 
| 868 |         rects.addRect(x: 300, y: 100, w: 100,h: 100); | 
| 869 |         QCOMPARE(rects.elementCount(), 10); | 
| 870 |         QCOMPARE(rects.elementAt(5).type, QPainterPath::MoveToElement); | 
| 871 |         QCOMPARE(rects.elementAt(9).type, QPainterPath::LineToElement); | 
| 872 |  | 
| 873 |         rects.lineTo(x: 0, y: 0); | 
| 874 |         QCOMPARE(rects.elementCount(), 12); | 
| 875 |         QCOMPARE(rects.elementAt(10).type, QPainterPath::MoveToElement); | 
| 876 |         QCOMPARE(rects.elementAt(11).type, QPainterPath::LineToElement); | 
| 877 |     } | 
| 878 |  | 
| 879 |     { | 
| 880 |         QPainterPath ellipses; | 
| 881 |         ellipses.addEllipse(x: 100, y: 100, w: 100, h: 100); | 
| 882 |  | 
| 883 |         QCOMPARE(ellipses.elementCount(), 13); | 
| 884 |         QCOMPARE(ellipses.elementAt(0).type, QPainterPath::MoveToElement); | 
| 885 |         QCOMPARE(ellipses.elementAt(10).type, QPainterPath::CurveToElement); | 
| 886 |  | 
| 887 |         ellipses.addEllipse(x: 300, y: 100, w: 100,h: 100); | 
| 888 |         QCOMPARE(ellipses.elementCount(), 26); | 
| 889 |         QCOMPARE(ellipses.elementAt(13).type, QPainterPath::MoveToElement); | 
| 890 |         QCOMPARE(ellipses.elementAt(23).type, QPainterPath::CurveToElement); | 
| 891 |  | 
| 892 |         ellipses.lineTo(x: 0, y: 0); | 
| 893 |         QCOMPARE(ellipses.elementCount(), 28); | 
| 894 |         QCOMPARE(ellipses.elementAt(26).type, QPainterPath::MoveToElement); | 
| 895 |         QCOMPARE(ellipses.elementAt(27).type, QPainterPath::LineToElement); | 
| 896 |     } | 
| 897 |  | 
| 898 |     { | 
| 899 |         QPainterPath path; | 
| 900 |         path.moveTo(x: 10, y: 10); | 
| 901 |         path.lineTo(x: 40, y: 10); | 
| 902 |         path.lineTo(x: 25, y: 20); | 
| 903 |         path.lineTo(x: 10 + 1e-13, y: 10 + 1e-13); | 
| 904 |         QCOMPARE(path.elementCount(), 4); | 
| 905 |         path.closeSubpath(); | 
| 906 |         QCOMPARE(path.elementCount(), 4); | 
| 907 |     } | 
| 908 | } | 
| 909 |  | 
| 910 | void tst_QPainterPath::testArcMoveTo_data() | 
| 911 | { | 
| 912 |     QTest::addColumn<QRectF>(name: "rect" ); | 
| 913 |     QTest::addColumn<qreal>(name: "angle" ); | 
| 914 |  | 
| 915 |     static Q_CONSTEXPR QRectF rects[] = { | 
| 916 |         QRectF(100, 100, 100, 100), | 
| 917 |         QRectF(100, 100, -100, 100), | 
| 918 |         QRectF(100, 100, 100, -100), | 
| 919 |         QRectF(100, 100, -100, -100), | 
| 920 |     }; | 
| 921 |  | 
| 922 |     for (uint domain = 0; domain < sizeof rects / sizeof *rects; ++domain) { | 
| 923 |         const QByteArray dB = QByteArray::number(domain); | 
| 924 |         for (int i=-360; i<=360; ++i) { | 
| 925 |             QTest::newRow(dataTag: ("test "  + dB + ' ' + QByteArray::number(i)).constData()) | 
| 926 |                 << rects[domain] << (qreal) i; | 
| 927 |         } | 
| 928 |  | 
| 929 |         // test low angles | 
| 930 |         QTest::newRow(dataTag: "low angles 1" ) << rects[domain] << (qreal) 1e-10; | 
| 931 |         QTest::newRow(dataTag: "low angles 2" ) << rects[domain] << (qreal)-1e-10; | 
| 932 |     } | 
| 933 | } | 
| 934 |  | 
| 935 | void tst_QPainterPath::operators_data() | 
| 936 | { | 
| 937 |     QTest::addColumn<QPainterPath>(name: "test" ); | 
| 938 |     QTest::addColumn<QPainterPath>(name: "expected" ); | 
| 939 |  | 
| 940 |     QPainterPath a; | 
| 941 |     QPainterPath b; | 
| 942 |     a.addRect(x: 0, y: 0, w: 100, h: 100); | 
| 943 |     b.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 944 |  | 
| 945 |     QTest::newRow(dataTag: "a & b" ) << (a & b) << a.intersected(r: b); | 
| 946 |     QTest::newRow(dataTag: "a | b" ) << (a | b) << a.united(r: b); | 
| 947 |     QTest::newRow(dataTag: "a + b" ) << (a + b) << a.united(r: b); | 
| 948 |     QTest::newRow(dataTag: "a - b" ) << (a - b) << a.subtracted(r: b); | 
| 949 |  | 
| 950 |     QPainterPath c = a; | 
| 951 |     QTest::newRow(dataTag: "a &= b" ) << (a &= b) << a.intersected(r: b); | 
| 952 |     c = a; | 
| 953 |     QTest::newRow(dataTag: "a |= b" ) << (a |= b) << a.united(r: b); | 
| 954 |     c = a; | 
| 955 |     QTest::newRow(dataTag: "a += b" ) << (a += b) << a.united(r: b); | 
| 956 |     c = a; | 
| 957 |     QTest::newRow(dataTag: "a -= b" ) << (a -= b) << a.subtracted(r: b); | 
| 958 | } | 
| 959 |  | 
| 960 | void tst_QPainterPath::operators() | 
| 961 | { | 
| 962 |     QFETCH(QPainterPath, test); | 
| 963 |     QFETCH(QPainterPath, expected); | 
| 964 |  | 
| 965 |     QCOMPARE(test, expected); | 
| 966 | } | 
| 967 |  | 
| 968 | static inline bool pathFuzzyCompare(double p1, double p2) | 
| 969 | { | 
| 970 |     return qAbs(t: p1 - p2) < 0.001; | 
| 971 | } | 
| 972 |  | 
| 973 |  | 
| 974 | static inline bool pathFuzzyCompare(float p1, float p2) | 
| 975 | { | 
| 976 |     return qAbs(t: p1 - p2) < 0.001; | 
| 977 | } | 
| 978 |  | 
| 979 |  | 
| 980 | void tst_QPainterPath::testArcMoveTo() | 
| 981 | { | 
| 982 |     QFETCH(QRectF, rect); | 
| 983 |     QFETCH(qreal, angle); | 
| 984 |  | 
| 985 |     QPainterPath path; | 
| 986 |     path.arcMoveTo(rect, angle); | 
| 987 |     path.arcTo(rect, startAngle: angle, arcLength: 30); | 
| 988 |     path.arcTo(rect, startAngle: angle + 30, arcLength: 30); | 
| 989 |  | 
| 990 |     QPointF pos = path.elementAt(i: 0); | 
| 991 |  | 
| 992 |     QVERIFY((path.elementCount()-1) % 3 == 0); | 
| 993 |  | 
| 994 |     qreal x_radius = rect.width() / 2.0; | 
| 995 |     qreal y_radius = rect.height() / 2.0; | 
| 996 |  | 
| 997 |     QPointF shouldBe = rect.center() | 
| 998 |                        + QPointF(x_radius * qCos(v: qDegreesToRadians(degrees: angle)), -y_radius * qSin(v: qDegreesToRadians(degrees: angle))); | 
| 999 |  | 
| 1000 |     qreal iw = 1 / rect.width(); | 
| 1001 |     qreal ih = 1 / rect.height(); | 
| 1002 |  | 
| 1003 |     QVERIFY(pathFuzzyCompare(pos.x() * iw, shouldBe.x() * iw)); | 
| 1004 |     QVERIFY(pathFuzzyCompare(pos.y() * ih, shouldBe.y() * ih)); | 
| 1005 | } | 
| 1006 |  | 
| 1007 | void tst_QPainterPath::testOnPath_data() | 
| 1008 | { | 
| 1009 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 1010 |     QTest::addColumn<qreal>(name: "start" ); | 
| 1011 |     QTest::addColumn<qreal>(name: "middle" ); | 
| 1012 |     QTest::addColumn<qreal>(name: "end" ); | 
| 1013 |  | 
| 1014 |     QPainterPath path = QPainterPath(QPointF(153, 199)); | 
| 1015 |     path.cubicTo(ctrlPt1: QPointF(147, 61), ctrlPt2: QPointF(414, 18), | 
| 1016 |                  endPt: QPointF(355, 201)); | 
| 1017 |  | 
| 1018 |     QTest::newRow(dataTag: "First case" ) << path | 
| 1019 |                                 << qreal(93.0) | 
| 1020 |                                 << qreal(4.0) | 
| 1021 |                                 << qreal(252.13); | 
| 1022 |  | 
| 1023 |     path = QPainterPath(QPointF(328, 197)); | 
| 1024 |     path.cubicTo(ctrlPt1: QPointF(150, 50), ctrlPt2: QPointF(401, 50), | 
| 1025 |                  endPt: QPointF(225, 197)); | 
| 1026 |     QTest::newRow(dataTag: "Second case" ) << path | 
| 1027 |                                  << qreal(140.0) | 
| 1028 |                                  << qreal(0.0) | 
| 1029 |                                  << qreal(220.0); | 
| 1030 |  | 
| 1031 |     path = QPainterPath(QPointF(328, 197)); | 
| 1032 |     path.cubicTo(ctrlPt1: QPointF(101 , 153), ctrlPt2: QPointF(596, 151), | 
| 1033 |                  endPt: QPointF(353, 197)); | 
| 1034 |     QTest::newRow(dataTag: "Third case" ) << path | 
| 1035 |                                 << qreal(169.0) | 
| 1036 |                                 << qreal(0.22) | 
| 1037 |                                 <<  qreal(191.0); | 
| 1038 |  | 
| 1039 |     path = QPainterPath(QPointF(153, 199)); | 
| 1040 |     path.cubicTo(ctrlPt1: QPointF(59, 53), ctrlPt2: QPointF(597, 218), | 
| 1041 |                   endPt: QPointF(355, 201)); | 
| 1042 |     QTest::newRow(dataTag: "Fourth case" ) << path | 
| 1043 |                                  << qreal(122.0) | 
| 1044 |                                  <<  qreal(348.0) | 
| 1045 |                                  << qreal(175.0); | 
| 1046 |  | 
| 1047 | } | 
| 1048 |  | 
| 1049 | #define SIGN(x) ((x < 0)?-1:1) | 
| 1050 | void tst_QPainterPath::testOnPath() | 
| 1051 | { | 
| 1052 |     QFETCH(QPainterPath, path); | 
| 1053 |     QFETCH(qreal, start); | 
| 1054 |     QFETCH(qreal, middle); | 
| 1055 |     QFETCH(qreal, end); | 
| 1056 |  | 
| 1057 |     int signStart = SIGN(start); | 
| 1058 |     int signMid   = SIGN(middle); | 
| 1059 |     int signEnd   = SIGN(end); | 
| 1060 |  | 
| 1061 |     static const qreal diff = 3; | 
| 1062 |  | 
| 1063 |     qreal angle = path.angleAtPercent(t: 0); | 
| 1064 |     QCOMPARE(SIGN(angle), signStart); | 
| 1065 |     QVERIFY(qAbs(angle-start) < diff); | 
| 1066 |  | 
| 1067 |     angle = path.angleAtPercent(t: 0.5); | 
| 1068 |     QCOMPARE(SIGN(angle), signMid); | 
| 1069 |     QVERIFY(qAbs(angle-middle) < diff); | 
| 1070 |  | 
| 1071 |     angle = path.angleAtPercent(t: 1); | 
| 1072 |     QCOMPARE(SIGN(angle), signEnd); | 
| 1073 |     QVERIFY(qAbs(angle-end) < diff); | 
| 1074 | } | 
| 1075 |  | 
| 1076 | void tst_QPainterPath::pointAtPercent_data() | 
| 1077 | { | 
| 1078 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 1079 |     QTest::addColumn<qreal>(name: "percent" ); | 
| 1080 |     QTest::addColumn<QPointF>(name: "point" ); | 
| 1081 |  | 
| 1082 |     QPainterPath path; | 
| 1083 |     path.lineTo(x: 100, y: 0); | 
| 1084 |  | 
| 1085 |     QTest::newRow(dataTag: "Case 1" ) << path << qreal(0.2) << QPointF(20, 0); | 
| 1086 |     QTest::newRow(dataTag: "Case 2" ) << path << qreal(0.5) << QPointF(50, 0); | 
| 1087 |     QTest::newRow(dataTag: "Case 3" ) << path << qreal(0.0) << QPointF(0, 0); | 
| 1088 |     QTest::newRow(dataTag: "Case 4" ) << path << qreal(1.0) << QPointF(100, 0); | 
| 1089 |  | 
| 1090 |     path = QPainterPath(); | 
| 1091 |     path.lineTo(x: 0, y: 100); | 
| 1092 |  | 
| 1093 |     QTest::newRow(dataTag: "Case 5" ) << path << qreal(0.2) << QPointF(0, 20); | 
| 1094 |     QTest::newRow(dataTag: "Case 6" ) << path << qreal(0.5) << QPointF(0, 50); | 
| 1095 |     QTest::newRow(dataTag: "Case 7" ) << path << qreal(0.0) << QPointF(0, 0); | 
| 1096 |     QTest::newRow(dataTag: "Case 8" ) << path << qreal(1.0) << QPointF(0, 100); | 
| 1097 |  | 
| 1098 |     path.lineTo(x: 300, y: 100); | 
| 1099 |  | 
| 1100 |     QTest::newRow(dataTag: "Case 9" )  << path << qreal(0.25) << QPointF(0, 100); | 
| 1101 |     QTest::newRow(dataTag: "Case 10" ) << path << qreal(0.5) << QPointF(100, 100); | 
| 1102 |     QTest::newRow(dataTag: "Case 11" ) << path << qreal(0.75) << QPointF(200, 100); | 
| 1103 |  | 
| 1104 |     path = QPainterPath(); | 
| 1105 |     path.addEllipse(x: 0, y: 0, w: 100, h: 100); | 
| 1106 |  | 
| 1107 |     QTest::newRow(dataTag: "Case 12" ) << path << qreal(0.0)  << QPointF(100, 50); | 
| 1108 |     QTest::newRow(dataTag: "Case 13" ) << path << qreal(0.25) << QPointF(50, 100); | 
| 1109 |     QTest::newRow(dataTag: "Case 14" ) << path << qreal(0.5)  << QPointF(0, 50); | 
| 1110 |     QTest::newRow(dataTag: "Case 15" ) << path << qreal(0.75) << QPointF(50, 0); | 
| 1111 |     QTest::newRow(dataTag: "Case 16" ) << path << qreal(1.0)  << QPointF(100, 50); | 
| 1112 |  | 
| 1113 |     path = QPainterPath(); | 
| 1114 |     QRectF rect(241, 273, 185, 228); | 
| 1115 |     path.addEllipse(rect); | 
| 1116 |     QTest::newRow(dataTag: "Case 17" ) << path << qreal(1.0) << QPointF(rect.right(), qreal(0.5) * (rect.top() + rect.bottom())); | 
| 1117 |  | 
| 1118 |     path = QPainterPath(); | 
| 1119 |     path.moveTo(x: 100, y: 100); | 
| 1120 |     QTest::newRow(dataTag: "Case 18" ) << path << qreal(0.0) << QPointF(100, 100); | 
| 1121 |     QTest::newRow(dataTag: "Case 19" ) << path << qreal(1.0) << QPointF(100, 100); | 
| 1122 | } | 
| 1123 |  | 
| 1124 | void tst_QPainterPath::pointAtPercent() | 
| 1125 | { | 
| 1126 |     QFETCH(QPainterPath, path); | 
| 1127 |     QFETCH(qreal, percent); | 
| 1128 |     QFETCH(QPointF, point); | 
| 1129 |  | 
| 1130 |     QPointF result = path.pointAtPercent(t: percent); | 
| 1131 |     QVERIFY(pathFuzzyCompare(point.x() , result.x())); | 
| 1132 |     QVERIFY(pathFuzzyCompare(point.y() , result.y())); | 
| 1133 | } | 
| 1134 |  | 
| 1135 | void tst_QPainterPath::setElementPositionAt() | 
| 1136 | { | 
| 1137 |     QPainterPath path(QPointF(42., 42.)); | 
| 1138 |     QCOMPARE(path.elementCount(), 1); | 
| 1139 |     QCOMPARE(path.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1140 |     QCOMPARE(path.elementAt(0).x, qreal(42.)); | 
| 1141 |     QCOMPARE(path.elementAt(0).y, qreal(42.)); | 
| 1142 |  | 
| 1143 |     QPainterPath copy = path; | 
| 1144 |     copy.setElementPositionAt(i: 0, x: qreal(0), y: qreal(0)); | 
| 1145 |     QCOMPARE(copy.elementCount(), 1); | 
| 1146 |     QCOMPARE(copy.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1147 |     QCOMPARE(copy.elementAt(0).x, qreal(0)); | 
| 1148 |     QCOMPARE(copy.elementAt(0).y, qreal(0)); | 
| 1149 |  | 
| 1150 |     QCOMPARE(path.elementCount(), 1); | 
| 1151 |     QCOMPARE(path.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1152 |     QCOMPARE(path.elementAt(0).x, qreal(42.)); | 
| 1153 |     QCOMPARE(path.elementAt(0).y, qreal(42.)); | 
| 1154 | } | 
| 1155 |  | 
| 1156 | void tst_QPainterPath::angleAtPercent() | 
| 1157 | { | 
| 1158 |     for (int angle = 0; angle < 360; ++angle) { | 
| 1159 |         QLineF line = QLineF::fromPolar(length: 100, angle); | 
| 1160 |         QPainterPath path; | 
| 1161 |         path.moveTo(p: line.p1()); | 
| 1162 |         path.lineTo(p: line.p2()); | 
| 1163 |  | 
| 1164 |         QCOMPARE(path.angleAtPercent(0.5), line.angle()); | 
| 1165 |     } | 
| 1166 | } | 
| 1167 |  | 
| 1168 | void tst_QPainterPath::arcWinding_data() | 
| 1169 | { | 
| 1170 |     QTest::addColumn<QPainterPath>(name: "path" ); | 
| 1171 |     QTest::addColumn<QPointF>(name: "point" ); | 
| 1172 |     QTest::addColumn<bool>(name: "inside" ); | 
| 1173 |  | 
| 1174 |     QPainterPath a; | 
| 1175 |     a.addEllipse(x: 0, y: 0, w: 100, h: 100); | 
| 1176 |     a.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 1177 |  | 
| 1178 |     QTest::newRow(dataTag: "Case A (oddeven)" ) << a << QPointF(55, 55) << false; | 
| 1179 |     a.setFillRule(Qt::WindingFill); | 
| 1180 |     QTest::newRow(dataTag: "Case A (winding)" ) << a << QPointF(55, 55) << true; | 
| 1181 |  | 
| 1182 |     QPainterPath b; | 
| 1183 |     b.arcMoveTo(x: 0, y: 0, w: 100, h: 100, angle: 10); | 
| 1184 |     b.arcTo(x: 0, y: 0, w: 100, h: 100, startAngle: 10, arcLength: 360); | 
| 1185 |     b.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 1186 |  | 
| 1187 |     QTest::newRow(dataTag: "Case B (oddeven)" ) << b << QPointF(55, 55) << false; | 
| 1188 |     b.setFillRule(Qt::WindingFill); | 
| 1189 |     QTest::newRow(dataTag: "Case B (winding)" ) << b << QPointF(55, 55) << false; | 
| 1190 |  | 
| 1191 |     QPainterPath c; | 
| 1192 |     c.arcMoveTo(x: 0, y: 0, w: 100, h: 100, angle: 0); | 
| 1193 |     c.arcTo(x: 0, y: 0, w: 100, h: 100, startAngle: 0, arcLength: 360); | 
| 1194 |     c.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 1195 |  | 
| 1196 |     QTest::newRow(dataTag: "Case C (oddeven)" ) << c << QPointF(55, 55) << false; | 
| 1197 |     c.setFillRule(Qt::WindingFill); | 
| 1198 |     QTest::newRow(dataTag: "Case C (winding)" ) << c << QPointF(55, 55) << false; | 
| 1199 |  | 
| 1200 |     QPainterPath d; | 
| 1201 |     d.arcMoveTo(x: 0, y: 0, w: 100, h: 100, angle: 10); | 
| 1202 |     d.arcTo(x: 0, y: 0, w: 100, h: 100, startAngle: 10, arcLength: -360); | 
| 1203 |     d.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 1204 |  | 
| 1205 |     QTest::newRow(dataTag: "Case D (oddeven)" ) << d << QPointF(55, 55) << false; | 
| 1206 |     d.setFillRule(Qt::WindingFill); | 
| 1207 |     QTest::newRow(dataTag: "Case D (winding)" ) << d << QPointF(55, 55) << true; | 
| 1208 |  | 
| 1209 |     QPainterPath e; | 
| 1210 |     e.arcMoveTo(x: 0, y: 0, w: 100, h: 100, angle: 0); | 
| 1211 |     e.arcTo(x: 0, y: 0, w: 100, h: 100, startAngle: 0, arcLength: -360); | 
| 1212 |     e.addRect(x: 50, y: 50, w: 100, h: 100); | 
| 1213 |  | 
| 1214 |     QTest::newRow(dataTag: "Case E (oddeven)" ) << e << QPointF(55, 55) << false; | 
| 1215 |     e.setFillRule(Qt::WindingFill); | 
| 1216 |     QTest::newRow(dataTag: "Case E (winding)" ) << e << QPointF(55, 55) << true; | 
| 1217 | } | 
| 1218 |  | 
| 1219 | void tst_QPainterPath::arcWinding() | 
| 1220 | { | 
| 1221 |     QFETCH(QPainterPath, path); | 
| 1222 |     QFETCH(QPointF, point); | 
| 1223 |     QFETCH(bool, inside); | 
| 1224 |  | 
| 1225 |     QCOMPARE(path.contains(point), inside); | 
| 1226 | } | 
| 1227 |  | 
| 1228 | void tst_QPainterPath::testToFillPolygons() | 
| 1229 | { | 
| 1230 |     QPainterPath path; | 
| 1231 |     path.lineTo(p: QPointF(0, 50)); | 
| 1232 |     path.lineTo(p: QPointF(50, 50)); | 
| 1233 |  | 
| 1234 |     path.moveTo(p: QPointF(70, 50)); | 
| 1235 |     path.lineTo(p: QPointF(70, 100)); | 
| 1236 |     path.lineTo(p: QPointF(40, 100)); | 
| 1237 |  | 
| 1238 |     const QList<QPolygonF> polygons = path.toFillPolygons(); | 
| 1239 |     QCOMPARE(polygons.size(), 2); | 
| 1240 |     QCOMPARE(polygons.first().count(QPointF(70, 50)), 0); | 
| 1241 | } | 
| 1242 |  | 
| 1243 | #if QT_CONFIG(signaling_nan) | 
| 1244 | void tst_QPainterPath::testNaNandInfinites() | 
| 1245 | { | 
| 1246 |     QPainterPath path1; | 
| 1247 |     QPainterPath path2 = path1; | 
| 1248 |  | 
| 1249 |     QPointF p1 = QPointF(qSNaN(), 1); | 
| 1250 |     QPointF p2 = QPointF(qQNaN(), 1); | 
| 1251 |     QPointF p3 = QPointF(qQNaN(), 1); | 
| 1252 |     QPointF pInf = QPointF(qInf(), 1); | 
| 1253 |  | 
| 1254 |     // all these operations with NaN/Inf should be ignored | 
| 1255 |     // can't test operator>> reliably, as we can't create a path with NaN to << later | 
| 1256 |  | 
| 1257 |     path1.moveTo(p: p1); | 
| 1258 |     path1.moveTo(x: qSNaN(), y: qQNaN()); | 
| 1259 |     path1.moveTo(p: pInf); | 
| 1260 |  | 
| 1261 |     path1.lineTo(p: p1); | 
| 1262 |     path1.lineTo(x: qSNaN(), y: qQNaN()); | 
| 1263 |     path1.lineTo(p: pInf); | 
| 1264 |  | 
| 1265 |     path1.cubicTo(ctrlPt1: p1, ctrlPt2: p2, endPt: p3); | 
| 1266 |     path1.cubicTo(ctrlPt1: p1, ctrlPt2: QPointF(1, 1), endPt: QPointF(2, 2)); | 
| 1267 |     path1.cubicTo(ctrlPt1: pInf, ctrlPt2: QPointF(10, 10), endPt: QPointF(5, 1)); | 
| 1268 |  | 
| 1269 |     path1.quadTo(ctrlPt: p1, endPt: p2); | 
| 1270 |     path1.quadTo(ctrlPt: QPointF(1, 1), endPt: p3); | 
| 1271 |     path1.quadTo(ctrlPt: QPointF(1, 1), endPt: pInf); | 
| 1272 |  | 
| 1273 |     path1.arcTo(rect: QRectF(p1, p2), startAngle: 5, arcLength: 5); | 
| 1274 |     path1.arcTo(rect: QRectF(pInf, QPointF(1, 1)), startAngle: 5, arcLength: 5); | 
| 1275 |  | 
| 1276 |     path1.addRect(rect: QRectF(p1, p2)); | 
| 1277 |     path1.addRect(rect: QRectF(pInf, QPointF(1, 1))); | 
| 1278 |  | 
| 1279 |     path1.addEllipse(rect: QRectF(p1, p2)); | 
| 1280 |     path1.addEllipse(rect: QRectF(pInf, QPointF(1, 1))); | 
| 1281 |  | 
| 1282 |     QCOMPARE(path1, path2); | 
| 1283 |  | 
| 1284 |     path1.lineTo(p: QPointF(1, 1)); | 
| 1285 |     QVERIFY(path1 != path2); | 
| 1286 | } | 
| 1287 | #endif // signaling_nan | 
| 1288 |  | 
| 1289 | void tst_QPainterPath::connectPathDuplicatePoint() | 
| 1290 | { | 
| 1291 |     QPainterPath a; | 
| 1292 |     a.moveTo(x: 10, y: 10); | 
| 1293 |     a.lineTo(x: 20, y: 20); | 
| 1294 |  | 
| 1295 |     QPainterPath b; | 
| 1296 |     b.moveTo(x: 20, y: 20); | 
| 1297 |     b.lineTo(x: 30, y: 10); | 
| 1298 |  | 
| 1299 |     a.connectPath(path: b); | 
| 1300 |  | 
| 1301 |     QPainterPath c; | 
| 1302 |     c.moveTo(x: 10, y: 10); | 
| 1303 |     c.lineTo(x: 20, y: 20); | 
| 1304 |     c.lineTo(x: 30, y: 10); | 
| 1305 |  | 
| 1306 |     QCOMPARE(c, a); | 
| 1307 | } | 
| 1308 |  | 
| 1309 | void tst_QPainterPath::connectPathMoveTo() | 
| 1310 | { | 
| 1311 |     QPainterPath path1; | 
| 1312 |     QPainterPath path2; | 
| 1313 |     QPainterPath path3; | 
| 1314 |     QPainterPath path4; | 
| 1315 |  | 
| 1316 |     path1.moveTo(x: 1,y: 1); | 
| 1317 |  | 
| 1318 |     path2.moveTo(x: 4,y: 4); | 
| 1319 |     path2.lineTo(x: 5,y: 6); | 
| 1320 |     path2.lineTo(x: 6,y: 7); | 
| 1321 |  | 
| 1322 |     path3.connectPath(path: path2); | 
| 1323 |  | 
| 1324 |     path4.lineTo(x: 5,y: 5); | 
| 1325 |  | 
| 1326 |     path1.connectPath(path: path2); | 
| 1327 |  | 
| 1328 |     QCOMPARE(path1.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1329 |     QCOMPARE(path2.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1330 |     QCOMPARE(path3.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1331 |     QCOMPARE(path4.elementAt(0).type, QPainterPath::MoveToElement); | 
| 1332 | } | 
| 1333 |  | 
| 1334 | void tst_QPainterPath::translate() | 
| 1335 | { | 
| 1336 |     QPainterPath path; | 
| 1337 |  | 
| 1338 |     // Path with no elements. | 
| 1339 |     QCOMPARE(path.currentPosition(), QPointF()); | 
| 1340 |     path.translate(dx: 50.5, dy: 50.5); | 
| 1341 |     QCOMPARE(path.currentPosition(), QPointF()); | 
| 1342 |     QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF()); | 
| 1343 |  | 
| 1344 |     // path.isEmpty(), but we have one MoveTo element that should be translated. | 
| 1345 |     path.moveTo(x: 50, y: 50); | 
| 1346 |     QCOMPARE(path.currentPosition(), QPointF(50, 50)); | 
| 1347 |     path.translate(dx: 99.9, dy: 99.9); | 
| 1348 |     QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9)); | 
| 1349 |     path.translate(dx: -99.9, dy: -99.9); | 
| 1350 |     QCOMPARE(path.currentPosition(), QPointF(50, 50)); | 
| 1351 |     QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0)); | 
| 1352 |  | 
| 1353 |     // Complex path. | 
| 1354 |     QRegion shape(100, 100, 300, 200, QRegion::Ellipse); | 
| 1355 |     shape -= QRect(225, 175, 50, 50); | 
| 1356 |     QPainterPath complexPath; | 
| 1357 |     complexPath.addRegion(region: shape); | 
| 1358 |     QVector<QPointF> untranslatedElements; | 
| 1359 |     for (int i = 0; i < complexPath.elementCount(); ++i) | 
| 1360 |         untranslatedElements.append(t: QPointF(complexPath.elementAt(i))); | 
| 1361 |  | 
| 1362 |     const QPainterPath untranslatedComplexPath(complexPath); | 
| 1363 |     const QPointF offset(100, 100); | 
| 1364 |     complexPath.translate(offset); | 
| 1365 |  | 
| 1366 |     for (int i = 0; i < complexPath.elementCount(); ++i) | 
| 1367 |         QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i)); | 
| 1368 |  | 
| 1369 |     QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath); | 
| 1370 | } | 
| 1371 |  | 
| 1372 |  | 
| 1373 | void tst_QPainterPath::lineWithinBounds() | 
| 1374 | { | 
| 1375 |     const int iteration_count = 3; | 
| 1376 |     volatile const qreal yVal = 0.5; | 
| 1377 |     QPointF a(0.0, yVal); | 
| 1378 |     QPointF b(1000.0, yVal); | 
| 1379 |     QPointF c(2000.0, yVal); | 
| 1380 |     QPointF d(3000.0, yVal); | 
| 1381 |     QPainterPath path; | 
| 1382 |     path.moveTo(p: QPointF(0, yVal)); | 
| 1383 |     path.cubicTo(ctrlPt1: QPointF(1000.0, yVal), ctrlPt2: QPointF(2000.0, yVal), endPt: QPointF(3000.0, yVal)); | 
| 1384 |     for(int i=0; i<=iteration_count; i++) { | 
| 1385 |         qreal actual = path.pointAtPercent(t: qreal(i) / iteration_count).y(); | 
| 1386 |         QVERIFY(actual == yVal); // don't use QCOMPARE, don't want fuzzy comparison | 
| 1387 |     } | 
| 1388 | } | 
| 1389 |  | 
| 1390 | void tst_QPainterPath::intersectionEquality() | 
| 1391 | { | 
| 1392 |     // Test case from QTBUG-17027 | 
| 1393 |     QPainterPath p1; | 
| 1394 |     p1.moveTo(x: 256.0000000000000000, y: 135.8384137532701743); | 
| 1395 |     p1.lineTo(x: 50.9999999999999715, y: 107.9999999999999857); | 
| 1396 |     p1.lineTo(x: 233.5425474228109123, y: 205.3560252921671462); | 
| 1397 |     p1.lineTo(x: 191.7771366877784373, y: 318.0257074407572304); | 
| 1398 |     p1.lineTo(x: -48.2616272048215151, y: 229.0459803737862216); | 
| 1399 |     p1.lineTo(x: 0.0000000000000000, y: 98.8515898136580801); | 
| 1400 |     p1.lineTo(x: 0.0000000000000000, y: 0.0000000000000000); | 
| 1401 |     p1.lineTo(x: 256.0000000000000000, y: 0.0000000000000000); | 
| 1402 |     p1.lineTo(x: 256.0000000000000000, y: 135.8384137532701743); | 
| 1403 |  | 
| 1404 |     QPainterPath p2; | 
| 1405 |     p2.moveTo(x: 1516.2703263523442274, y: 306.9795200262722119); | 
| 1406 |     p2.lineTo(x: -1296.8426224886295585, y: -75.0331736542986931); | 
| 1407 |     p2.lineTo(x: -1678.8553161692004778, y: 2738.0797751866753060); | 
| 1408 |     p2.lineTo(x: 1134.2576326717733081, y: 3120.0924688672457705); | 
| 1409 |     p2.lineTo(x: 1516.2703263523442274, y: 306.9795200262722119); | 
| 1410 |  | 
| 1411 |     QPainterPath i1 = p1.intersected(r: p2); | 
| 1412 |     QPainterPath i2 = p2.intersected(r: p1); | 
| 1413 |     QVERIFY(i1 == i2 || i1.toReversed() == i2); | 
| 1414 |  | 
| 1415 |     p1 = QPainterPath(); | 
| 1416 |     p1.moveTo(x: 256.00000000, y: 135.83841375); | 
| 1417 |     p1.lineTo(x: 50.99999999, y: 107.99999999); | 
| 1418 |     p1.lineTo(x: 233.54254742, y: 205.35602529); | 
| 1419 |     p1.lineTo(x: 191.77713668, y: 318.02570744); | 
| 1420 |     p1.lineTo(x: -48.26162720, y: 229.04598037); | 
| 1421 |     p1.lineTo(x: 0.00000000, y: 98.85158981); | 
| 1422 |     p1.lineTo(x: 0.00000000, y: 0.00000000); | 
| 1423 |     p1.lineTo(x: 256.00000000, y: 0.00000000); | 
| 1424 |     p1.lineTo(x: 256.00000000, y: 135.83841375); | 
| 1425 |  | 
| 1426 |     p2 = QPainterPath(); | 
| 1427 |     p2.moveTo(x: 1516.27032635, y: 306.97952002); | 
| 1428 |     p2.lineTo(x: -1296.84262248, y: -75.03317365); | 
| 1429 |     p2.lineTo(x: -1678.85531616, y: 2738.07977518); | 
| 1430 |     p2.lineTo(x: 1134.25763267, y: 3120.09246886); | 
| 1431 |     p2.lineTo(x: 1516.27032635, y: 306.97952002); | 
| 1432 |  | 
| 1433 |     i1 = p1.intersected(r: p2); | 
| 1434 |     i2 = p2.intersected(r: p1); | 
| 1435 |     QVERIFY(i1 == i2 || i1.toReversed() == i2); | 
| 1436 | } | 
| 1437 |  | 
| 1438 | void tst_QPainterPath::intersectionPointOnEdge() | 
| 1439 | { | 
| 1440 |     // From QTBUG-31551 | 
| 1441 |     QPainterPath p; p.addRoundedRect(x: -10, y: 10, w: 40, h: 40, xRadius: 10, yRadius: 10); | 
| 1442 |     QRectF r(0, 0, 100, 100); | 
| 1443 |     QPainterPath rp; rp.addRect(rect: r); | 
| 1444 |     QVERIFY(!p.intersected(rp).isEmpty()); | 
| 1445 |     QVERIFY(p.intersects(rp)); | 
| 1446 |     QVERIFY(p.intersects(r)); | 
| 1447 | } | 
| 1448 |  | 
| 1449 | QTEST_APPLESS_MAIN(tst_QPainterPath) | 
| 1450 |  | 
| 1451 | #include "tst_qpainterpath.moc" | 
| 1452 |  |