summaryrefslogtreecommitdiffstats
path: root/tests/auto/qpainterpath
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/qpainterpath
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/qpainterpath')
-rw-r--r--tests/auto/qpainterpath/.gitignore2
-rw-r--r--tests/auto/qpainterpath/qpainterpath.pro5
-rw-r--r--tests/auto/qpainterpath/tst_qpainterpath.cpp1311
3 files changed, 1318 insertions, 0 deletions
diff --git a/tests/auto/qpainterpath/.gitignore b/tests/auto/qpainterpath/.gitignore
new file mode 100644
index 0000000000..4e0e797989
--- /dev/null
+++ b/tests/auto/qpainterpath/.gitignore
@@ -0,0 +1,2 @@
+tst_qpainterpath
+data
diff --git a/tests/auto/qpainterpath/qpainterpath.pro b/tests/auto/qpainterpath/qpainterpath.pro
new file mode 100644
index 0000000000..9708222c99
--- /dev/null
+++ b/tests/auto/qpainterpath/qpainterpath.pro
@@ -0,0 +1,5 @@
+load(qttest_p4)
+SOURCES += tst_qpainterpath.cpp
+
+
+
diff --git a/tests/auto/qpainterpath/tst_qpainterpath.cpp b/tests/auto/qpainterpath/tst_qpainterpath.cpp
new file mode 100644
index 0000000000..c2e64e0da0
--- /dev/null
+++ b/tests/auto/qpainterpath/tst_qpainterpath.cpp
@@ -0,0 +1,1311 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qfile.h>
+#include <qpainterpath.h>
+#include <qpen.h>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QPainterPath : public QObject
+{
+ Q_OBJECT
+
+public:
+
+private slots:
+ void getSetCheck();
+ void swap();
+
+ void contains_QPointF_data();
+ void contains_QPointF();
+
+ void contains_QRectF_data();
+ void contains_QRectF();
+
+ void intersects_QRectF_data();
+ void intersects_QRectF();
+
+ void testContainsAndIntersects_data();
+ void testContainsAndIntersects();
+
+ void testSimplified_data();
+ void testSimplified();
+
+ void testStroker_data();
+ void testStroker();
+
+ void currentPosition();
+
+ void testOperatorEquals();
+ void testOperatorEquals_fuzzy();
+ void testOperatorDatastream();
+
+ void testArcMoveTo_data();
+ void testArcMoveTo();
+ void setElementPositionAt();
+
+ void testOnPath_data();
+ void testOnPath();
+
+ void pointAtPercent_data();
+ void pointAtPercent();
+
+ void angleAtPercent();
+
+ void arcWinding_data();
+ void arcWinding();
+
+ void testToFillPolygons();
+
+ void testNaNandInfinites();
+
+ void closing();
+
+ void operators_data();
+ void operators();
+
+ void connectPathDuplicatePoint();
+ void connectPathMoveTo();
+
+ void translate();
+};
+
+// Testing get/set functions
+void tst_QPainterPath::getSetCheck()
+{
+ QPainterPathStroker obj1;
+ // qreal QPainterPathStroker::width()
+ // void QPainterPathStroker::setWidth(qreal)
+ obj1.setWidth(0.0);
+ QCOMPARE(qreal(1.0), obj1.width()); // Pathstroker sets with to 1 if <= 0
+ obj1.setWidth(0.5);
+ QCOMPARE(qreal(0.5), obj1.width());
+ obj1.setWidth(1.1);
+ QCOMPARE(qreal(1.1), obj1.width());
+
+ // qreal QPainterPathStroker::miterLimit()
+ // void QPainterPathStroker::setMiterLimit(qreal)
+ obj1.setMiterLimit(0.0);
+ QCOMPARE(qreal(0.0), obj1.miterLimit());
+ obj1.setMiterLimit(1.1);
+ QCOMPARE(qreal(1.1), obj1.miterLimit());
+
+ // qreal QPainterPathStroker::curveThreshold()
+ // void QPainterPathStroker::setCurveThreshold(qreal)
+ obj1.setCurveThreshold(0.0);
+ QCOMPARE(qreal(0.0), obj1.curveThreshold());
+ obj1.setCurveThreshold(1.1);
+ QCOMPARE(qreal(1.1), obj1.curveThreshold());
+}
+
+void tst_QPainterPath::swap()
+{
+ QPainterPath p1;
+ p1.addRect( 0, 0,10,10);
+ QPainterPath p2;
+ p2.addRect(10,10,10,10);
+ p1.swap(p2);
+ QCOMPARE(p1.boundingRect().toRect(), QRect(10,10,10,10));
+ QCOMPARE(p2.boundingRect().toRect(), QRect( 0, 0,10,10));
+}
+
+Q_DECLARE_METATYPE(QPainterPath)
+Q_DECLARE_METATYPE(QPointF)
+Q_DECLARE_METATYPE(QRectF)
+
+void tst_QPainterPath::currentPosition()
+{
+ QPainterPath p;
+
+ QCOMPARE(p.currentPosition(), QPointF());
+
+ p.moveTo(100, 100);
+ QCOMPARE(p.currentPosition(), QPointF(100, 100));
+
+ p.lineTo(200, 200);
+ QCOMPARE(p.currentPosition(), QPointF(200, 200));
+
+ p.cubicTo(300, 200, 200, 300, 500, 500);
+ QCOMPARE(p.currentPosition(), QPointF(500, 500));
+}
+
+void tst_QPainterPath::contains_QPointF_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QPointF>("pt");
+ QTest::addColumn<bool>("contained");
+
+ QPainterPath path;
+ path.addRect(0, 0, 100, 100);
+
+ // #####
+ // # #
+ // # #
+ // # #
+ // #####
+
+ QTest::newRow("[0,0] in [0,0,100,100]") << path << QPointF(0, 0) << true;
+
+ QTest::newRow("[99,0] in [0,0,100,100]") << path << QPointF(99, 0) << true;
+ QTest::newRow("[0,99] in [0,0,100,100]") << path << QPointF(0, 99) << true;
+ QTest::newRow("[99,99] in [0,0,100,100]") << path << QPointF(99, 99) << true;
+
+ QTest::newRow("[99.99,0] in [0,0,100,100]") << path << QPointF(99.99, 0) << true;
+ QTest::newRow("[0,99.99] in [0,0,100,100]") << path << QPointF(0, 99.99) << true;
+ QTest::newRow("[99.99,99.99] in [0,0,100,100]") << path << QPointF(99.99, 99.99) << true;
+
+ QTest::newRow("[0.01,0.01] in [0,0,100,100]") << path << QPointF(0.01, 0.01) << true;
+ QTest::newRow("[0,0.01] in [0,0,100,100]") << path << QPointF(0, 0.01) << true;
+ QTest::newRow("[0.01,0] in [0,0,100,100]") << path << QPointF(0.01, 0) << true;
+
+ QTest::newRow("[-0.01,-0.01] in [0,0,100,100]") << path << QPointF(-0.01, -0.01) << false;
+ QTest::newRow("[-0,-0.01] in [0,0,100,100]") << path << QPointF(0, -0.01) << false;
+ QTest::newRow("[-0.01,0] in [0,0,100,100]") << path << QPointF(-0.01, 0) << false;
+
+
+ QTest::newRow("[-10,0] in [0,0,100,100]") << path << QPointF(-10, 0) << false;
+ QTest::newRow("[100,0] in [0,0,100,100]") << path << QPointF(100, 0) << false;
+
+ QTest::newRow("[0,-10] in [0,0,100,100]") << path << QPointF(0, -10) << false;
+ QTest::newRow("[0,100] in [0,0,100,100]") << path << QPointF(0, 100) << false;
+
+ QTest::newRow("[100.1,0] in [0,0,100,100]") << path << QPointF(100.1, 0) << false;
+ QTest::newRow("[0,100.1] in [0,0,100,100]") << path << QPointF(0, 100.1) << false;
+
+ path.addRect(50, 50, 100, 100);
+
+ // #####
+ // # #
+ // # #####
+ // # # # #
+ // ##### #
+ // # #
+ // #####
+
+ QTest::newRow("[49,49] in 2 rects") << path << QPointF(49,49) << true;
+ QTest::newRow("[50,50] in 2 rects") << path << QPointF(50,50) << false;
+ QTest::newRow("[100,100] in 2 rects") << path << QPointF(100,100) << true;
+
+ path.setFillRule(Qt::WindingFill);
+ QTest::newRow("[50,50] in 2 rects (winding)") << path << QPointF(50,50) << true;
+
+ path.addEllipse(0, 0, 150, 150);
+
+ // #####
+ // ## ##
+ // # #####
+ // # # # #
+ // ##### #
+ // ## ##
+ // #####
+
+ QTest::newRow("[50,50] in complex (winding)") << path << QPointF(50, 50) << true;
+
+ path.setFillRule(Qt::OddEvenFill);
+ QTest::newRow("[50,50] in complex (windinf)") << path << QPointF(50, 50) << true;
+ QTest::newRow("[49,49] in complex") << path << QPointF(49,49) << false;
+ QTest::newRow("[100,100] in complex") << path << QPointF(49,49) << false;
+
+
+ // unclosed triangle
+ path = QPainterPath();
+ path.moveTo(100, 100);
+ path.lineTo(130, 70);
+ path.lineTo(150, 110);
+
+ QTest::newRow("[100,100] in triangle") << path << QPointF(100, 100) << true;
+ QTest::newRow("[140,100] in triangle") << path << QPointF(140, 100) << true;
+ QTest::newRow("[130,80] in triangle") << path << QPointF(130, 80) << true;
+
+ QTest::newRow("[110,80] in triangle") << path << QPointF(110, 80) << false;
+ QTest::newRow("[150,100] in triangle") << path << QPointF(150, 100) << false;
+ QTest::newRow("[120,110] in triangle") << path << QPointF(120, 110) << false;
+
+ QRectF base_rect(0, 0, 20, 20);
+
+ path = QPainterPath();
+ path.addEllipse(base_rect);
+
+ // not strictly precise, but good enougth to verify fair precision.
+ QPainterPath inside;
+ inside.addEllipse(base_rect.adjusted(5, 5, -5, -5));
+ QPolygonF inside_poly = inside.toFillPolygon();
+ for (int i=0; i<inside_poly.size(); ++i)
+ QTest::newRow("inside_ellipse") << path << inside_poly.at(i) << true;
+
+ QPainterPath outside;
+ outside.addEllipse(base_rect.adjusted(-5, -5, 5, 5));
+ QPolygonF outside_poly = outside.toFillPolygon();
+ for (int i=0; i<outside_poly.size(); ++i)
+ QTest::newRow("outside_ellipse") << path << outside_poly.at(i) << false;
+
+ path = QPainterPath();
+ base_rect = QRectF(50, 50, 200, 200);
+ path.addEllipse(base_rect);
+ path.setFillRule(Qt::WindingFill);
+
+ QTest::newRow("topleft outside ellipse") << path << base_rect.topLeft() << false;
+ QTest::newRow("topright outside ellipse") << path << base_rect.topRight() << false;
+ QTest::newRow("bottomright outside ellipse") << path << base_rect.bottomRight() << false;
+ QTest::newRow("bottomleft outside ellipse") << path << base_rect.bottomLeft() << false;
+
+ // Test horizontal curve segment
+ path = QPainterPath();
+ path.moveTo(100, 100);
+ path.cubicTo(120, 100, 180, 100, 200, 100);
+ path.lineTo(150, 200);
+ path.closeSubpath();
+
+ QTest::newRow("horizontal cubic, out left") << path << QPointF(0, 100) << false;
+ QTest::newRow("horizontal cubic, out right") << path << QPointF(300, 100) <<false;
+ QTest::newRow("horizontal cubic, in mid") << path << QPointF(150, 100) << true;
+
+ path = QPainterPath();
+ path.addEllipse(QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0));
+ QTest::newRow("huge ellipse, qreal=float crash") << path << QPointF(1100000.35, 1098000.2) << true;
+
+}
+
+void tst_QPainterPath::contains_QPointF()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QPointF, pt);
+ QFETCH(bool, contained);
+
+ QCOMPARE(path.contains(pt), contained);
+}
+
+void tst_QPainterPath::contains_QRectF_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QRectF>("rect");
+ QTest::addColumn<bool>("contained");
+
+ QPainterPath path;
+ path.addRect(0, 0, 100, 100);
+
+ QTest::newRow("same rect") << path << QRectF(0.1, 0.1, 99, 99) << true; // ###
+ QTest::newRow("outside") << path << QRectF(-1, -1, 100, 100) << false;
+ QTest::newRow("covers") << path << QRectF(-1, -1, 102, 102) << false;
+ QTest::newRow("left") << path << QRectF(-10, 50, 5, 5) << false;
+ QTest::newRow("top") << path << QRectF(50, -10, 5, 5) << false;
+ QTest::newRow("right") << path << QRectF(110, 50, 5, 5) << false;
+ QTest::newRow("bottom") << path << QRectF(50, 110, 5, 5) << false;
+
+ path.addRect(50, 50, 100, 100);
+
+ QTest::newRow("r1 top") << path << QRectF(0.1, 0.1, 99, 49) << true;
+ QTest::newRow("r1 left") << path << QRectF(0.1, 0.1, 49, 99) << true;
+ QTest::newRow("r2 right") << path << QRectF(100.01, 50.1, 49, 99) << true;
+ QTest::newRow("r2 bottom") << path << QRectF(50.1, 100.1, 99, 49) << true;
+ QTest::newRow("inside 2 rects") << path << QRectF(51, 51, 48, 48) << false;
+ QTest::newRow("topRight 2 rects") << path << QRectF(100, 0, 49, 49) << false;
+ QTest::newRow("bottomLeft 2 rects") << path << QRectF(0, 100, 49, 49) << false;
+
+ path.setFillRule(Qt::WindingFill);
+ QTest::newRow("inside 2 rects (winding)") << path << QRectF(51, 51, 48, 48) << true;
+
+ path.addEllipse(0, 0, 150, 150);
+ QTest::newRow("topRight 2 rects") << path << QRectF(100, 25, 24, 24) << true;
+ QTest::newRow("bottomLeft 2 rects") << path << QRectF(25, 100, 24, 24) << true;
+
+ path.setFillRule(Qt::OddEvenFill);
+ QTest::newRow("inside 2 rects") << path << QRectF(50, 50, 49, 49) << false;
+}
+
+void tst_QPainterPath::contains_QRectF()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QRectF, rect);
+ QFETCH(bool, contained);
+
+ QCOMPARE(path.contains(rect), contained);
+}
+
+static inline QPainterPath rectPath(qreal x, qreal y, qreal w, qreal h)
+{
+ QPainterPath path;
+ path.addRect(x, y, w, h);
+ path.closeSubpath();
+ return path;
+}
+
+static inline QPainterPath ellipsePath(qreal x, qreal y, qreal w, qreal h)
+{
+ QPainterPath path;
+ path.addEllipse(x, y, w, h);
+ path.closeSubpath();
+ return path;
+}
+
+static inline QPainterPath linePath(qreal x1, qreal y1, qreal x2, qreal y2)
+{
+ QPainterPath path;
+ path.moveTo(x1, y1);
+ path.lineTo(x2, y2);
+ return path;
+}
+
+void tst_QPainterPath::intersects_QRectF_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QRectF>("rect");
+ QTest::addColumn<bool>("intersects");
+
+ QPainterPath path;
+ path.addRect(0, 0, 100, 100);
+
+ QTest::newRow("same rect") << path << QRectF(0.1, 0.1, 99, 99) << true; // ###
+ QTest::newRow("outside") << path << QRectF(-1, -1, 100, 100) << true;
+ QTest::newRow("covers") << path << QRectF(-1, -1, 102, 102) << true;
+ QTest::newRow("left") << path << QRectF(-10, 50, 5, 5) << false;
+ QTest::newRow("top") << path << QRectF(50, -10, 5, 5) << false;
+ QTest::newRow("right") << path << QRectF(110, 50, 5, 5) << false;
+ QTest::newRow("bottom") << path << QRectF(50, 110, 5, 5) << false;
+
+ path.addRect(50, 50, 100, 100);
+
+ QTest::newRow("r1 top") << path << QRectF(0.1, 0.1, 99, 49) << true;
+ QTest::newRow("r1 left") << path << QRectF(0.1, 0.1, 49, 99) << true;
+ QTest::newRow("r2 right") << path << QRectF(100.01, 50.1, 49, 99) << true;
+ QTest::newRow("r2 bottom") << path << QRectF(50.1, 100.1, 99, 49) << true;
+ QTest::newRow("inside 2 rects") << path << QRectF(51, 51, 48, 48) << false;
+
+ path.setFillRule(Qt::WindingFill);
+ QTest::newRow("inside 2 rects (winding)") << path << QRectF(51, 51, 48, 48) << true;
+
+ path.addEllipse(0, 0, 150, 150);
+ QTest::newRow("topRight 2 rects") << path << QRectF(100, 25, 24, 24) << true;
+ QTest::newRow("bottomLeft 2 rects") << path << QRectF(25, 100, 24, 24) << true;
+
+ QTest::newRow("horizontal line") << linePath(0, 0, 10, 0) << QRectF(1, -1, 2, 2) << true;
+ QTest::newRow("vertical line") << linePath(0, 0, 0, 10) << QRectF(-1, 1, 2, 2) << true;
+
+ path = QPainterPath();
+ path.addEllipse(QRectF(-5000.0, -5000.0, 1500000.0, 1500000.0));
+ QTest::newRow("huge ellipse, qreal=float crash") << path << QRectF(1100000.35, 1098000.2, 1500000.0, 1500000.0) << true;
+}
+
+void tst_QPainterPath::intersects_QRectF()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QRectF, rect);
+ QFETCH(bool, intersects);
+
+ QCOMPARE(path.intersects(rect), intersects);
+}
+
+
+void tst_QPainterPath::testContainsAndIntersects_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QPainterPath>("candidate");
+ QTest::addColumn<bool>("contained");
+ QTest::addColumn<bool>("intersects");
+
+ QTest::newRow("rect vs small ellipse (upper left)") << rectPath(0, 0, 100, 100) << ellipsePath(0, 0, 50, 50) << false << true;
+ QTest::newRow("rect vs small ellipse (upper right)") << rectPath(0, 0, 100, 100) << ellipsePath(50, 0, 50, 50) << false << true;
+ QTest::newRow("rect vs small ellipse (lower right)") << rectPath(0, 0, 100, 100) << ellipsePath(50, 50, 50, 50) << false << true;
+ QTest::newRow("rect vs small ellipse (lower left)") << rectPath(0, 0, 100, 100) << ellipsePath(0, 50, 50, 50) << false << true;
+ QTest::newRow("rect vs small ellipse (centered)") << rectPath(0, 0, 100, 100) << ellipsePath(25, 25, 50, 50) << true << true;
+ QTest::newRow("rect vs equal ellipse") << rectPath(0, 0, 100, 100) << ellipsePath(0, 0, 100, 100) << false << true;
+ QTest::newRow("rect vs big ellipse") << rectPath(0, 0, 100, 100) << ellipsePath(-10, -10, 120, 120) << false << true;
+
+ QPainterPath twoEllipses = ellipsePath(0, 0, 100, 100).united(ellipsePath(200, 0, 100, 100));
+
+ QTest::newRow("rect vs two small ellipses") << rectPath(0, 0, 100, 100) << ellipsePath(25, 25, 50, 50).united(ellipsePath(225, 25, 50, 50)) << false << true;
+ QTest::newRow("rect vs two equal ellipses") << rectPath(0, 0, 100, 100) << twoEllipses << false << true;
+
+ QTest::newRow("rect vs self") << rectPath(0, 0, 100, 100) << rectPath(0, 0, 100, 100) << false << true;
+ QTest::newRow("ellipse vs self") << ellipsePath(0, 0, 100, 100) << ellipsePath(0, 0, 100, 100) << false << true;
+
+ QPainterPath twoRects = rectPath(0, 0, 100, 100).united(rectPath(200, 0, 100, 100));
+ QTest::newRow("two rects vs small ellipse (upper left)") << twoRects << ellipsePath(0, 0, 50, 50) << false << true;
+ QTest::newRow("two rects vs small ellipse (upper right)") << twoRects << ellipsePath(50, 0, 50, 50) << false << true;
+ QTest::newRow("two rects vs small ellipse (lower right)") << twoRects << ellipsePath(50, 50, 50, 50) << false << true;
+ QTest::newRow("two rects vs small ellipse (lower left)") << twoRects << ellipsePath(0, 50, 50, 50) << false << true;
+ QTest::newRow("two rects vs small ellipse (centered)") << twoRects << ellipsePath(25, 25, 50, 50) << true << true;
+ QTest::newRow("two rects vs equal ellipse") << twoRects << ellipsePath(0, 0, 100, 100) << false << true;
+ QTest::newRow("two rects vs big ellipse") << twoRects << ellipsePath(-10, -10, 120, 120) << false << true;
+
+ QTest::newRow("two rects vs two small ellipses") << twoRects << ellipsePath(25, 25, 50, 50).united(ellipsePath(225, 25, 50, 50)) << true << true;
+ QTest::newRow("two rects vs two equal ellipses") << twoRects << ellipsePath(0, 0, 100, 100).united(ellipsePath(200, 0, 100, 100)) << false << true;
+
+ QTest::newRow("two rects vs self") << twoRects << twoRects << false << true;
+ QTest::newRow("two ellipses vs self") << twoEllipses << twoEllipses << false << true;
+
+ QPainterPath windingRect = rectPath(0, 0, 100, 100);
+ windingRect.addRect(25, 25, 100, 50);
+ windingRect.setFillRule(Qt::WindingFill);
+
+ QTest::newRow("rect with winding rule vs tall rect") << windingRect << rectPath(40, 20, 20, 60) << true << true;
+ QTest::newRow("rect with winding rule vs self") << windingRect << windingRect << false << true;
+
+ QPainterPath thickFrame = rectPath(0, 0, 100, 100).subtracted(rectPath(25, 25, 50, 50));
+ QPainterPath thinFrame = rectPath(10, 10, 80, 80).subtracted(rectPath(15, 15, 70, 70));
+
+ QTest::newRow("thin frame in thick frame") << thickFrame << thinFrame << true << true;
+ QTest::newRow("rect in thick frame") << thickFrame << rectPath(40, 40, 20, 20) << false << false;
+ QTest::newRow("rect in thin frame") << thinFrame << rectPath(40, 40, 20, 20) << false << false;
+
+ QPainterPath ellipses;
+ ellipses.addEllipse(0, 0, 10, 10);
+ ellipses.addEllipse(4, 4, 2, 2);
+ ellipses.setFillRule(Qt::WindingFill);
+
+ // the definition of QPainterPath::intersects() and contains() is fill-area based,
+ QTest::newRow("line in rect") << rectPath(0, 0, 100, 100) << linePath(10, 10, 90, 90) << true << true;
+ QTest::newRow("horizontal line in rect") << rectPath(0, 0, 100, 100) << linePath(10, 50, 90, 50) << true << true;
+ QTest::newRow("vertical line in rect") << rectPath(0, 0, 100, 100) << linePath(50, 10, 50, 90) << true << true;
+
+ QTest::newRow("line through rect") << rectPath(0, 0, 100, 100) << linePath(-10, -10, 110, 110) << false << true;
+ QTest::newRow("line through rect 2") << rectPath(0, 0, 100, 100) << linePath(-10, 0, 110, 100) << false << true;
+ QTest::newRow("line through rect 3") << rectPath(0, 0, 100, 100) << linePath(5, 10, 110, 100) << false << true;
+ QTest::newRow("line through rect 4") << rectPath(0, 0, 100, 100) << linePath(-10, 0, 90, 90) << false << true;
+
+ QTest::newRow("horizontal line through rect") << rectPath(0, 0, 100, 100) << linePath(-10, 50, 110, 50) << false << true;
+ QTest::newRow("vertical line through rect") << rectPath(0, 0, 100, 100) << linePath(50, -10, 50, 110) << false << true;
+
+ QTest::newRow("line vs line") << linePath(0, 0, 10, 10) << linePath(10, 0, 0, 10) << false << true;
+
+ QTest::newRow("line in rect with hole") << rectPath(0, 0, 10, 10).subtracted(rectPath(2, 2, 6, 6)) << linePath(4, 4, 6, 6) << false << false;
+ QTest::newRow("line in ellipse") << ellipses << linePath(3, 5, 7, 5) << false << true;
+ QTest::newRow("line in ellipse 2") << ellipses << linePath(4.5, 5, 5.5, 5) << true << true;
+
+ QTest::newRow("winding ellipse") << ellipses << ellipsePath(4, 4, 2, 2) << false << true;
+ QTest::newRow("winding ellipse 2") << ellipses << ellipsePath(4.5, 4.5, 1, 1) << true << true;
+ ellipses.setFillRule(Qt::OddEvenFill);
+ QTest::newRow("odd even ellipse") << ellipses << ellipsePath(4, 4, 2, 2) << false << true;
+ QTest::newRow("odd even ellipse 2") << ellipses << ellipsePath(4.5, 4.5, 1, 1) << false << false;
+}
+
+void tst_QPainterPath::testContainsAndIntersects()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QPainterPath, candidate);
+ QFETCH(bool, contained);
+ QFETCH(bool, intersects);
+
+ QCOMPARE(path.intersects(candidate), intersects);
+ QCOMPARE(path.contains(candidate), contained);
+}
+
+void tst_QPainterPath::testSimplified_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<int>("elements");
+
+ QTest::newRow("rect") << rectPath(0, 0, 10, 10) << 5;
+
+ QPainterPath twoRects = rectPath(0, 0, 10, 10);
+ twoRects.addPath(rectPath(5, 0, 10, 10));
+ QTest::newRow("two rects (odd)") << twoRects << 10;
+
+ twoRects.setFillRule(Qt::WindingFill);
+ QTest::newRow("two rects (winding)") << twoRects << 5;
+
+ QPainterPath threeSteps = rectPath(0, 0, 10, 10);
+ threeSteps.addPath(rectPath(0, 10, 20, 10));
+ threeSteps.addPath(rectPath(0, 20, 30, 10));
+
+ QTest::newRow("three rects (steps)") << threeSteps << 9;
+}
+
+void tst_QPainterPath::testSimplified()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(int, elements);
+
+ QPainterPath simplified = path.simplified();
+
+ QCOMPARE(simplified.elementCount(), elements);
+
+ QVERIFY(simplified.subtracted(path).isEmpty());
+ QVERIFY(path.subtracted(simplified).isEmpty());
+}
+
+void tst_QPainterPath::testStroker_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QPen>("pen");
+ QTest::addColumn<QPainterPath>("stroke");
+
+ QTest::newRow("line 1") << linePath(2, 2, 10, 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::FlatCap) << rectPath(2, 1, 8, 2);
+ QTest::newRow("line 2") << linePath(2, 2, 10, 2) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap) << rectPath(1, 1, 10, 2);
+
+ QTest::newRow("rect") << rectPath(1, 1, 8, 8) << QPen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin) << rectPath(0, 0, 10, 10).subtracted(rectPath(2, 2, 6, 6));
+
+ QTest::newRow("dotted line") << linePath(0, 0, 10, 0) << QPen(Qt::black, 2, Qt::DotLine) << rectPath(-1, -1, 4, 2).united(rectPath(5, -1, 4, 2));
+}
+
+void tst_QPainterPath::testStroker()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QPen, pen);
+ QFETCH(QPainterPath, stroke);
+
+ QPainterPathStroker stroker;
+ stroker.setWidth(pen.widthF());
+ stroker.setCapStyle(pen.capStyle());
+ stroker.setJoinStyle(pen.joinStyle());
+ stroker.setMiterLimit(pen.miterLimit());
+ stroker.setDashPattern(pen.style());
+ stroker.setDashOffset(pen.dashOffset());
+
+ QPainterPath result = stroker.createStroke(path);
+
+ // check if stroke == result
+ QVERIFY(result.subtracted(stroke).isEmpty());
+ QVERIFY(stroke.subtracted(result).isEmpty());
+}
+
+void tst_QPainterPath::testOperatorEquals()
+{
+ QPainterPath empty1;
+ QPainterPath empty2;
+ QVERIFY(empty1 == empty2);
+
+ QPainterPath rect1;
+ rect1.addRect(100, 100, 100, 100);
+ QVERIFY(rect1 == rect1);
+ QVERIFY(rect1 != empty1);
+
+ QPainterPath rect2;
+ rect2.addRect(100, 100, 100, 100);
+ QVERIFY(rect1 == rect2);
+
+ rect2.setFillRule(Qt::WindingFill);
+ QVERIFY(rect1 != rect2);
+
+ QPainterPath ellipse1;
+ ellipse1.addEllipse(50, 50, 100, 100);
+ QVERIFY(rect1 != ellipse1);
+
+ QPainterPath ellipse2;
+ ellipse2.addEllipse(50, 50, 100, 100);
+ QVERIFY(ellipse1 == ellipse2);
+}
+
+void tst_QPainterPath::testOperatorEquals_fuzzy()
+{
+ // if operator== returns true for two paths it should
+ // also return true when the same transform is applied to both paths
+ {
+ QRectF a(100, 100, 100, 50);
+ QRectF b = a.translated(1e-14, 1e-14);
+
+ QPainterPath pa;
+ pa.addRect(a);
+ QPainterPath pb;
+ pb.addRect(b);
+
+ QVERIFY(pa == pb);
+
+ QTransform transform;
+ transform.translate(-100, -100);
+
+ QVERIFY(transform.map(pa) == transform.map(pb));
+ }
+
+ // higher tolerance for error when path's bounding rect is big
+ {
+ QRectF a(1, 1, 1e6, 0.5e6);
+ QRectF b = a.translated(1e-7, 1e-7);
+
+ QPainterPath pa;
+ pa.addRect(a);
+ QPainterPath pb;
+ pb.addRect(b);
+
+ QVERIFY(pa == pb);
+
+ QTransform transform;
+ transform.translate(-1, -1);
+
+ QVERIFY(transform.map(pa) == transform.map(pb));
+ }
+
+ // operator== should return true for a path that has
+ // been transformed and then inverse transformed
+ {
+ QPainterPath a;
+ a.addRect(0, 0, 100, 100);
+
+ QTransform transform;
+ transform.translate(100, 20);
+ transform.scale(1.5, 1.5);
+
+ QPainterPath b = transform.inverted().map(transform.map(a));
+
+ QVERIFY(a == b);
+ }
+
+ {
+ QPainterPath a;
+ a.lineTo(10, 0);
+ a.lineTo(10, 10);
+ a.lineTo(0, 10);
+
+ QPainterPath b;
+ b.lineTo(10, 0);
+ b.moveTo(10, 10);
+ b.lineTo(0, 10);
+
+ QVERIFY(a != b);
+ }
+}
+
+void tst_QPainterPath::testOperatorDatastream()
+{
+ QPainterPath path;
+ path.addEllipse(0, 0, 100, 100);
+ path.addRect(0, 0, 100, 100);
+ path.setFillRule(Qt::WindingFill);
+
+ // Write out
+ {
+ QFile data("data");
+ bool ok = data.open(QFile::WriteOnly);
+ QVERIFY(ok);
+ QDataStream stream(&data);
+ stream << path;
+ }
+
+ QPainterPath other;
+ // Read in
+ {
+ QFile data("data");
+ bool ok = data.open(QFile::ReadOnly);
+ QVERIFY(ok);
+ QDataStream stream(&data);
+ stream >> other;
+ }
+
+ QVERIFY(other == path);
+}
+
+void tst_QPainterPath::closing()
+{
+ // lineto's
+ {
+ QPainterPath triangle(QPoint(100, 100));
+
+ triangle.lineTo(200, 100);
+ triangle.lineTo(200, 200);
+ QCOMPARE(triangle.elementCount(), 3);
+
+ triangle.closeSubpath();
+ QCOMPARE(triangle.elementCount(), 4);
+ QCOMPARE(triangle.elementAt(3).type, QPainterPath::LineToElement);
+
+ triangle.moveTo(300, 300);
+ QCOMPARE(triangle.elementCount(), 5);
+ QCOMPARE(triangle.elementAt(4).type, QPainterPath::MoveToElement);
+
+ triangle.lineTo(400, 300);
+ triangle.lineTo(400, 400);
+ QCOMPARE(triangle.elementCount(), 7);
+
+ triangle.closeSubpath();
+ QCOMPARE(triangle.elementCount(), 8);
+
+ // this will should trigger implicit moveto...
+ triangle.lineTo(600, 300);
+ QCOMPARE(triangle.elementCount(), 10);
+ QCOMPARE(triangle.elementAt(8).type, QPainterPath::MoveToElement);
+ QCOMPARE(triangle.elementAt(9).type, QPainterPath::LineToElement);
+
+ triangle.lineTo(600, 700);
+ QCOMPARE(triangle.elementCount(), 11);
+ }
+
+ // curveto's
+ {
+ QPainterPath curves(QPoint(100, 100));
+
+ curves.cubicTo(200, 100, 100, 200, 200, 200);
+ QCOMPARE(curves.elementCount(), 4);
+
+ curves.closeSubpath();
+ QCOMPARE(curves.elementCount(), 5);
+ QCOMPARE(curves.elementAt(4).type, QPainterPath::LineToElement);
+
+ curves.moveTo(300, 300);
+ QCOMPARE(curves.elementCount(), 6);
+ QCOMPARE(curves.elementAt(5).type, QPainterPath::MoveToElement);
+
+ curves.cubicTo(400, 300, 300, 400, 400, 400);
+ QCOMPARE(curves.elementCount(), 9);
+
+ curves.closeSubpath();
+ QCOMPARE(curves.elementCount(), 10);
+
+ // should trigger implicit moveto..
+ curves.cubicTo(100, 800, 800, 100, 800, 800);
+ QCOMPARE(curves.elementCount(), 14);
+ QCOMPARE(curves.elementAt(10).type, QPainterPath::MoveToElement);
+ QCOMPARE(curves.elementAt(11).type, QPainterPath::CurveToElement);
+ }
+
+ {
+ QPainterPath rects;
+ rects.addRect(100, 100, 100, 100);
+
+ QCOMPARE(rects.elementCount(), 5);
+ QCOMPARE(rects.elementAt(0).type, QPainterPath::MoveToElement);
+ QCOMPARE(rects.elementAt(4).type, QPainterPath::LineToElement);
+
+ rects.addRect(300, 100, 100,100);
+ QCOMPARE(rects.elementCount(), 10);
+ QCOMPARE(rects.elementAt(5).type, QPainterPath::MoveToElement);
+ QCOMPARE(rects.elementAt(9).type, QPainterPath::LineToElement);
+
+ rects.lineTo(0, 0);
+ QCOMPARE(rects.elementCount(), 12);
+ QCOMPARE(rects.elementAt(10).type, QPainterPath::MoveToElement);
+ QCOMPARE(rects.elementAt(11).type, QPainterPath::LineToElement);
+ }
+
+ {
+ QPainterPath ellipses;
+ ellipses.addEllipse(100, 100, 100, 100);
+
+ QCOMPARE(ellipses.elementCount(), 13);
+ QCOMPARE(ellipses.elementAt(0).type, QPainterPath::MoveToElement);
+ QCOMPARE(ellipses.elementAt(10).type, QPainterPath::CurveToElement);
+
+ ellipses.addEllipse(300, 100, 100,100);
+ QCOMPARE(ellipses.elementCount(), 26);
+ QCOMPARE(ellipses.elementAt(13).type, QPainterPath::MoveToElement);
+ QCOMPARE(ellipses.elementAt(23).type, QPainterPath::CurveToElement);
+
+ ellipses.lineTo(0, 0);
+ QCOMPARE(ellipses.elementCount(), 28);
+ QCOMPARE(ellipses.elementAt(26).type, QPainterPath::MoveToElement);
+ QCOMPARE(ellipses.elementAt(27).type, QPainterPath::LineToElement);
+ }
+
+ {
+ QPainterPath path;
+ path.moveTo(10, 10);
+ path.lineTo(40, 10);
+ path.lineTo(25, 20);
+ path.lineTo(10 + 1e-13, 10 + 1e-13);
+ QCOMPARE(path.elementCount(), 4);
+ path.closeSubpath();
+ QCOMPARE(path.elementCount(), 4);
+ }
+}
+
+void tst_QPainterPath::testArcMoveTo_data()
+{
+ QTest::addColumn<QRectF>("rect");
+ QTest::addColumn<qreal>("angle");
+
+ QList<QRectF> rects;
+ rects << QRectF(100, 100, 100, 100)
+ << QRectF(100, 100, -100, 100)
+ << QRectF(100, 100, 100, -100)
+ << QRectF(100, 100, -100, -100);
+
+ for (int domain=0; domain<rects.size(); ++domain) {
+ for (int i=-360; i<=360; ++i) {
+ QTest::newRow("test") << rects.at(domain) << (qreal) i;
+ }
+
+ // test low angles
+ QTest::newRow("test") << rects.at(domain) << (qreal) 1e-10;
+ QTest::newRow("test") << rects.at(domain) << (qreal)-1e-10;
+ }
+}
+
+void tst_QPainterPath::operators_data()
+{
+ QTest::addColumn<QPainterPath>("test");
+ QTest::addColumn<QPainterPath>("expected");
+
+ QPainterPath a;
+ QPainterPath b;
+ a.addRect(0, 0, 100, 100);
+ b.addRect(50, 50, 100, 100);
+
+ QTest::newRow("a & b") << (a & b) << a.intersected(b);
+ QTest::newRow("a | b") << (a | b) << a.united(b);
+ QTest::newRow("a + b") << (a + b) << a.united(b);
+ QTest::newRow("a - b") << (a - b) << a.subtracted(b);
+
+ QPainterPath c = a;
+ QTest::newRow("a &= b") << (a &= b) << a.intersected(b);
+ c = a;
+ QTest::newRow("a |= b") << (a |= b) << a.united(b);
+ c = a;
+ QTest::newRow("a += b") << (a += b) << a.united(b);
+ c = a;
+ QTest::newRow("a -= b") << (a -= b) << a.subtracted(b);
+}
+
+void tst_QPainterPath::operators()
+{
+ QFETCH(QPainterPath, test);
+ QFETCH(QPainterPath, expected);
+
+ QCOMPARE(test, expected);
+}
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#define ANGLE(t) ((t) * 2 * M_PI / 360.0)
+
+
+static inline bool pathFuzzyCompare(double p1, double p2)
+{
+ return qAbs(p1 - p2) < 0.001;
+}
+
+
+static inline bool pathFuzzyCompare(float p1, float p2)
+{
+ return qAbs(p1 - p2) < 0.001;
+}
+
+
+void tst_QPainterPath::testArcMoveTo()
+{
+ QFETCH(QRectF, rect);
+ QFETCH(qreal, angle);
+
+ QPainterPath path;
+ path.arcMoveTo(rect, angle);
+ path.arcTo(rect, angle, 30);
+ path.arcTo(rect, angle + 30, 30);
+
+ QPointF pos = path.elementAt(0);
+
+ QVERIFY((path.elementCount()-1) % 3 == 0);
+
+ qreal x_radius = rect.width() / 2.0;
+ qreal y_radius = rect.height() / 2.0;
+
+ QPointF shouldBe = rect.center()
+ + QPointF(x_radius * cos(ANGLE(angle)), -y_radius * sin(ANGLE(angle)));
+
+ qreal iw = 1 / rect.width();
+ qreal ih = 1 / rect.height();
+
+ QVERIFY(pathFuzzyCompare(pos.x() * iw, shouldBe.x() * iw));
+ QVERIFY(pathFuzzyCompare(pos.y() * ih, shouldBe.y() * ih));
+}
+
+void tst_QPainterPath::testOnPath_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<qreal>("start");
+ QTest::addColumn<qreal>("middle");
+ QTest::addColumn<qreal>("end");
+
+ QPainterPath path = QPainterPath(QPointF(153, 199));
+ path.cubicTo(QPointF(147, 61), QPointF(414, 18),
+ QPointF(355, 201));
+
+ QTest::newRow("First case") << path
+ << qreal(93.0)
+ << qreal(4.0)
+ << qreal(252.13);
+
+ path = QPainterPath(QPointF(328, 197));
+ path.cubicTo(QPointF(150, 50), QPointF(401, 50),
+ QPointF(225, 197));
+ QTest::newRow("Second case") << path
+ << qreal(140.0)
+ << qreal(0.0)
+ << qreal(220.0);
+
+ path = QPainterPath(QPointF(328, 197));
+ path.cubicTo(QPointF(101 , 153), QPointF(596, 151),
+ QPointF(353, 197));
+ QTest::newRow("Third case") << path
+ << qreal(169.0)
+ << qreal(0.22)
+ << qreal(191.0);
+
+ path = QPainterPath(QPointF(153, 199));
+ path.cubicTo(QPointF(59, 53), QPointF(597, 218),
+ QPointF(355, 201));
+ QTest::newRow("Fourth case") << path
+ << qreal(122.0)
+ << qreal(348.0)
+ << qreal(175.0);
+
+}
+
+#define SIGN(x) ((x < 0)?-1:1)
+void tst_QPainterPath::testOnPath()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(qreal, start);
+ QFETCH(qreal, middle);
+ QFETCH(qreal, end);
+
+ int signStart = SIGN(start);
+ int signMid = SIGN(middle);
+ int signEnd = SIGN(end);
+
+ static const qreal diff = 3;
+
+ qreal angle = path.angleAtPercent(0);
+ QCOMPARE(SIGN(angle), signStart);
+ QVERIFY(qAbs(angle-start) < diff);
+
+ angle = path.angleAtPercent(0.5);
+ QCOMPARE(SIGN(angle), signMid);
+ QVERIFY(qAbs(angle-middle) < diff);
+
+ angle = path.angleAtPercent(1);
+ QCOMPARE(SIGN(angle), signEnd);
+ QVERIFY(qAbs(angle-end) < diff);
+}
+
+void tst_QPainterPath::pointAtPercent_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<qreal>("percent");
+ QTest::addColumn<QPointF>("point");
+
+ QPainterPath path;
+ path.lineTo(100, 0);
+
+ QTest::newRow("Case 1") << path << qreal(0.2) << QPointF(20, 0);
+ QTest::newRow("Case 2") << path << qreal(0.5) << QPointF(50, 0);
+ QTest::newRow("Case 3") << path << qreal(0.0) << QPointF(0, 0);
+ QTest::newRow("Case 4") << path << qreal(1.0) << QPointF(100, 0);
+
+ path = QPainterPath();
+ path.lineTo(0, 100);
+
+ QTest::newRow("Case 5") << path << qreal(0.2) << QPointF(0, 20);
+ QTest::newRow("Case 6") << path << qreal(0.5) << QPointF(0, 50);
+ QTest::newRow("Case 7") << path << qreal(0.0) << QPointF(0, 0);
+ QTest::newRow("Case 8") << path << qreal(1.0) << QPointF(0, 100);
+
+ path.lineTo(300, 100);
+
+ QTest::newRow("Case 9") << path << qreal(0.25) << QPointF(0, 100);
+ QTest::newRow("Case 10") << path << qreal(0.5) << QPointF(100, 100);
+ QTest::newRow("Case 11") << path << qreal(0.75) << QPointF(200, 100);
+
+ path = QPainterPath();
+ path.addEllipse(0, 0, 100, 100);
+
+ QTest::newRow("Case 12") << path << qreal(0.0) << QPointF(100, 50);
+ QTest::newRow("Case 13") << path << qreal(0.25) << QPointF(50, 100);
+ QTest::newRow("Case 14") << path << qreal(0.5) << QPointF(0, 50);
+ QTest::newRow("Case 15") << path << qreal(0.75) << QPointF(50, 0);
+ QTest::newRow("Case 16") << path << qreal(1.0) << QPointF(100, 50);
+
+ path = QPainterPath();
+ QRectF rect(241, 273, 185, 228);
+ path.addEllipse(rect);
+ QTest::newRow("Case 17") << path << qreal(1.0) << QPointF(rect.right(), qreal(0.5) * (rect.top() + rect.bottom()));
+
+ path = QPainterPath();
+ path.moveTo(100, 100);
+ QTest::newRow("Case 18") << path << qreal(0.0) << QPointF(100, 100);
+ QTest::newRow("Case 19") << path << qreal(1.0) << QPointF(100, 100);
+}
+
+void tst_QPainterPath::pointAtPercent()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(qreal, percent);
+ QFETCH(QPointF, point);
+
+ QPointF result = path.pointAtPercent(percent);
+ QVERIFY(pathFuzzyCompare(point.x() , result.x()));
+ QVERIFY(pathFuzzyCompare(point.y() , result.y()));
+}
+
+void tst_QPainterPath::setElementPositionAt()
+{
+ QPainterPath path(QPointF(42., 42.));
+ QCOMPARE(path.elementCount(), 1);
+ QVERIFY(path.elementAt(0).type == QPainterPath::MoveToElement);
+ QCOMPARE(path.elementAt(0).x, qreal(42.));
+ QCOMPARE(path.elementAt(0).y, qreal(42.));
+
+ QPainterPath copy = path;
+ copy.setElementPositionAt(0, qreal(0), qreal(0));
+ QCOMPARE(copy.elementCount(), 1);
+ QVERIFY(copy.elementAt(0).type == QPainterPath::MoveToElement);
+ QCOMPARE(copy.elementAt(0).x, qreal(0));
+ QCOMPARE(copy.elementAt(0).y, qreal(0));
+
+ QCOMPARE(path.elementCount(), 1);
+ QVERIFY(path.elementAt(0).type == QPainterPath::MoveToElement);
+ QCOMPARE(path.elementAt(0).x, qreal(42.));
+ QCOMPARE(path.elementAt(0).y, qreal(42.));
+}
+
+void tst_QPainterPath::angleAtPercent()
+{
+ for (int angle = 0; angle < 360; ++angle) {
+ QLineF line = QLineF::fromPolar(100, angle);
+ QPainterPath path;
+ path.moveTo(line.p1());
+ path.lineTo(line.p2());
+
+ QCOMPARE(path.angleAtPercent(0.5), line.angle());
+ }
+}
+
+void tst_QPainterPath::arcWinding_data()
+{
+ QTest::addColumn<QPainterPath>("path");
+ QTest::addColumn<QPointF>("point");
+ QTest::addColumn<bool>("inside");
+
+ QPainterPath a;
+ a.addEllipse(0, 0, 100, 100);
+ a.addRect(50, 50, 100, 100);
+
+ QTest::newRow("Case A (oddeven)") << a << QPointF(55, 55) << false;
+ a.setFillRule(Qt::WindingFill);
+ QTest::newRow("Case A (winding)") << a << QPointF(55, 55) << true;
+
+ QPainterPath b;
+ b.arcMoveTo(0, 0, 100, 100, 10);
+ b.arcTo(0, 0, 100, 100, 10, 360);
+ b.addRect(50, 50, 100, 100);
+
+ QTest::newRow("Case B (oddeven)") << b << QPointF(55, 55) << false;
+ b.setFillRule(Qt::WindingFill);
+ QTest::newRow("Case B (winding)") << b << QPointF(55, 55) << false;
+
+ QPainterPath c;
+ c.arcMoveTo(0, 0, 100, 100, 0);
+ c.arcTo(0, 0, 100, 100, 0, 360);
+ c.addRect(50, 50, 100, 100);
+
+ QTest::newRow("Case C (oddeven)") << c << QPointF(55, 55) << false;
+ c.setFillRule(Qt::WindingFill);
+ QTest::newRow("Case C (winding)") << c << QPointF(55, 55) << false;
+
+ QPainterPath d;
+ d.arcMoveTo(0, 0, 100, 100, 10);
+ d.arcTo(0, 0, 100, 100, 10, -360);
+ d.addRect(50, 50, 100, 100);
+
+ QTest::newRow("Case D (oddeven)") << d << QPointF(55, 55) << false;
+ d.setFillRule(Qt::WindingFill);
+ QTest::newRow("Case D (winding)") << d << QPointF(55, 55) << true;
+
+ QPainterPath e;
+ e.arcMoveTo(0, 0, 100, 100, 0);
+ e.arcTo(0, 0, 100, 100, 0, -360);
+ e.addRect(50, 50, 100, 100);
+
+ QTest::newRow("Case E (oddeven)") << e << QPointF(55, 55) << false;
+ e.setFillRule(Qt::WindingFill);
+ QTest::newRow("Case E (winding)") << e << QPointF(55, 55) << true;
+}
+
+void tst_QPainterPath::arcWinding()
+{
+ QFETCH(QPainterPath, path);
+ QFETCH(QPointF, point);
+ QFETCH(bool, inside);
+
+ QCOMPARE(path.contains(point), inside);
+}
+
+void tst_QPainterPath::testToFillPolygons()
+{
+ QPainterPath path;
+ path.lineTo(QPointF(0, 50));
+ path.lineTo(QPointF(50, 50));
+
+ path.moveTo(QPointF(70, 50));
+ path.lineTo(QPointF(70, 100));
+ path.lineTo(QPointF(40, 100));
+
+ const QList<QPolygonF> polygons = path.toFillPolygons();
+ QCOMPARE(polygons.size(), 2);
+ QCOMPARE(polygons.first().count(QPointF(70, 50)), 0);
+}
+
+void tst_QPainterPath::testNaNandInfinites()
+{
+ QPainterPath path1;
+ QPainterPath path2 = path1;
+
+ QPointF p1 = QPointF(qSNaN(), 1);
+ QPointF p2 = QPointF(qQNaN(), 1);
+ QPointF p3 = QPointF(qQNaN(), 1);
+ QPointF pInf = QPointF(qInf(), 1);
+
+ // all these operations with NaN/Inf should be ignored
+ // can't test operator>> reliably, as we can't create a path with NaN to << later
+
+ path1.moveTo(p1);
+ path1.moveTo(qSNaN(), qQNaN());
+ path1.moveTo(pInf);
+
+ path1.lineTo(p1);
+ path1.lineTo(qSNaN(), qQNaN());
+ path1.lineTo(pInf);
+
+ path1.cubicTo(p1, p2, p3);
+ path1.cubicTo(p1, QPointF(1, 1), QPointF(2, 2));
+ path1.cubicTo(pInf, QPointF(10, 10), QPointF(5, 1));
+
+ path1.quadTo(p1, p2);
+ path1.quadTo(QPointF(1, 1), p3);
+ path1.quadTo(QPointF(1, 1), pInf);
+
+ path1.arcTo(QRectF(p1, p2), 5, 5);
+ path1.arcTo(QRectF(pInf, QPointF(1, 1)), 5, 5);
+
+ path1.addRect(QRectF(p1, p2));
+ path1.addRect(QRectF(pInf, QPointF(1, 1)));
+
+ path1.addEllipse(QRectF(p1, p2));
+ path1.addEllipse(QRectF(pInf, QPointF(1, 1)));
+
+ QCOMPARE(path1, path2);
+
+ path1.lineTo(QPointF(1, 1));
+ QVERIFY(path1 != path2);
+}
+
+void tst_QPainterPath::connectPathDuplicatePoint()
+{
+ QPainterPath a;
+ a.moveTo(10, 10);
+ a.lineTo(20, 20);
+
+ QPainterPath b;
+ b.moveTo(20, 20);
+ b.lineTo(30, 10);
+
+ a.connectPath(b);
+
+ QPainterPath c;
+ c.moveTo(10, 10);
+ c.lineTo(20, 20);
+ c.lineTo(30, 10);
+
+ QCOMPARE(c, a);
+}
+
+void tst_QPainterPath::connectPathMoveTo()
+{
+ QPainterPath path1;
+ QPainterPath path2;
+ QPainterPath path3;
+ QPainterPath path4;
+
+ path1.moveTo(1,1);
+
+ path2.moveTo(4,4);
+ path2.lineTo(5,6);
+ path2.lineTo(6,7);
+
+ path3.connectPath(path2);
+
+ path4.lineTo(5,5);
+
+ path1.connectPath(path2);
+
+ QVERIFY(path1.elementAt(0).type == QPainterPath::MoveToElement);
+ QVERIFY(path2.elementAt(0).type == QPainterPath::MoveToElement);
+ QVERIFY(path3.elementAt(0).type == QPainterPath::MoveToElement);
+ QVERIFY(path4.elementAt(0).type == QPainterPath::MoveToElement);
+}
+
+void tst_QPainterPath::translate()
+{
+ QPainterPath path;
+
+ // Path with no elements.
+ QCOMPARE(path.currentPosition(), QPointF());
+ path.translate(50.5, 50.5);
+ QCOMPARE(path.currentPosition(), QPointF());
+ QCOMPARE(path.translated(50.5, 50.5).currentPosition(), QPointF());
+
+ // path.isEmpty(), but we have one MoveTo element that should be translated.
+ path.moveTo(50, 50);
+ QCOMPARE(path.currentPosition(), QPointF(50, 50));
+ path.translate(99.9, 99.9);
+ QCOMPARE(path.currentPosition(), QPointF(149.9, 149.9));
+ path.translate(-99.9, -99.9);
+ QCOMPARE(path.currentPosition(), QPointF(50, 50));
+ QCOMPARE(path.translated(-50, -50).currentPosition(), QPointF(0, 0));
+
+ // Complex path.
+ QRegion shape(100, 100, 300, 200, QRegion::Ellipse);
+ shape -= QRect(225, 175, 50, 50);
+ QPainterPath complexPath;
+ complexPath.addRegion(shape);
+ QVector<QPointF> untranslatedElements;
+ for (int i = 0; i < complexPath.elementCount(); ++i)
+ untranslatedElements.append(QPointF(complexPath.elementAt(i)));
+
+ const QPainterPath untranslatedComplexPath(complexPath);
+ const QPointF offset(100, 100);
+ complexPath.translate(offset);
+
+ for (int i = 0; i < complexPath.elementCount(); ++i)
+ QCOMPARE(QPointF(complexPath.elementAt(i)) - offset, untranslatedElements.at(i));
+
+ QCOMPARE(complexPath.translated(-offset), untranslatedComplexPath);
+}
+
+QTEST_APPLESS_MAIN(tst_QPainterPath)
+
+#include "tst_qpainterpath.moc"