File indexing completed on 2025-02-02 04:14:58

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #include "TestPathShape.h"
0007 
0008 #include <QPainterPath>
0009 #include "KoPathShape.h"
0010 #include "KoPathPoint.h"
0011 #include "KoPathPointData.h"
0012 #include "KoPathSegment.h"
0013 
0014 #include <simpletest.h>
0015 
0016 void TestPathShape::close()
0017 {
0018     KoPathShape path;
0019     path.lineTo(QPointF(10, 0));
0020     path.lineTo(QPointF(10, 10));
0021 
0022     QPainterPath ppath(QPointF(0, 0));
0023     ppath.lineTo(QPointF(10, 0));
0024     ppath.lineTo(10, 10);
0025 
0026     QVERIFY(ppath == path.outline());
0027 
0028     path.close();
0029     ppath.closeSubpath();
0030 
0031     QVERIFY(ppath == path.outline());
0032 
0033     path.lineTo(QPointF(0, 10));
0034     ppath.lineTo(0, 10);
0035 
0036     QVERIFY(ppath == path.outline());
0037 }
0038 
0039 void TestPathShape::moveTo()
0040 {
0041     KoPathShape path;
0042     path.moveTo(QPointF(10, 10));
0043     QPainterPath ppath(QPointF(10, 10));
0044     path.lineTo(QPointF(20, 20));
0045     ppath.lineTo(20, 20);
0046     QVERIFY(ppath == path.outline());
0047     path.moveTo(QPointF(30, 30));
0048     ppath.moveTo(30, 30);
0049     path.lineTo(QPointF(40, 40));
0050     ppath.lineTo(QPointF(40, 40));
0051     QVERIFY(ppath == path.outline());
0052 }
0053 
0054 void TestPathShape::normalize()
0055 {
0056     KoPathShape path;
0057     path.moveTo(QPointF(10, 10));
0058     path.lineTo(QPointF(20, 20));
0059     path.normalize();
0060     QPainterPath ppath(QPointF(0, 0));
0061     ppath.lineTo(10, 10);
0062     QVERIFY(ppath == path.outline());
0063 }
0064 
0065 void TestPathShape::pathPointIndex()
0066 {
0067     KoPathShape path;
0068     KoPathPoint * point1 = path.moveTo(QPointF(10, 10));
0069     KoPathPointIndex p1Index(0, 0);
0070     KoPathPoint * point2 = path.lineTo(QPointF(20, 20));
0071     KoPathPointIndex p2Index(0, 1);
0072     KoPathPoint * point3 = path.moveTo(QPointF(30, 30));
0073     KoPathPointIndex p3Index(1, 0);
0074     KoPathPoint * point4 = path.lineTo(QPointF(40, 40));
0075     KoPathPointIndex p4Index(1, 1);
0076     KoPathPoint * point5 = 0;
0077     KoPathPointIndex p5Index(-1, -1);
0078 
0079     QCOMPARE(p1Index, path.pathPointIndex(point1));
0080     QCOMPARE(p2Index, path.pathPointIndex(point2));
0081     QCOMPARE(p3Index, path.pathPointIndex(point3));
0082     QCOMPARE(p4Index, path.pathPointIndex(point4));
0083     QCOMPARE(p5Index, path.pathPointIndex(point5));
0084 
0085     QVERIFY(p1Index == path.pathPointIndex(point1));
0086     QVERIFY(p2Index == path.pathPointIndex(point2));
0087     QVERIFY(p3Index == path.pathPointIndex(point3));
0088     QVERIFY(p4Index == path.pathPointIndex(point4));
0089     QVERIFY(p5Index == path.pathPointIndex(point5));
0090 }
0091 
0092 void TestPathShape::pointByIndex()
0093 {
0094     KoPathShape path;
0095     KoPathPoint * point1 = path.moveTo(QPointF(10, 10));
0096     KoPathPoint * point2 = path.lineTo(QPointF(20, 20));
0097     KoPathPoint * point3 = path.moveTo(QPointF(30, 30));
0098     KoPathPoint * point4 = path.lineTo(QPointF(40, 40));
0099     KoPathPoint * point5 = 0;
0100 
0101     QVERIFY(point1 == path.pointByIndex(path.pathPointIndex(point1)));
0102     QVERIFY(point2 == path.pointByIndex(path.pathPointIndex(point2)));
0103     QVERIFY(point3 == path.pointByIndex(path.pathPointIndex(point3)));
0104     QVERIFY(point4 == path.pointByIndex(path.pathPointIndex(point4)));
0105     QVERIFY(point5 == path.pointByIndex(path.pathPointIndex(point5)));
0106 }
0107 
0108 void TestPathShape::segmentByIndex()
0109 {
0110     KoPathShape path;
0111     KoPathPoint * point1 = path.moveTo(QPointF(20, 20));
0112     KoPathPoint * point2 = path.lineTo(QPointF(15, 25));
0113     path.lineTo(QPointF(10, 20));
0114     path.close();
0115     path.moveTo(QPointF(20, 30));
0116     KoPathPoint * point3 = path.lineTo(QPointF(20, 30));
0117     path.moveTo(QPointF(30, 30));
0118     path.lineTo(QPointF(40, 30));
0119     path.lineTo(QPointF(40, 40));
0120     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0121     KoPathPoint * point4 = path.moveTo(QPointF(50, 50));
0122     path.lineTo(QPointF(60, 50));
0123     path.lineTo(QPointF(60, 60));
0124     KoPathPoint * point5 = path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0125     path.close();
0126 
0127     QVERIFY(KoPathSegment(point1, point2) == path.segmentByIndex(path.pathPointIndex(point1)));
0128     // test last point in a open path
0129     QVERIFY(KoPathSegment(0, 0) == path.segmentByIndex(path.pathPointIndex(point3)));
0130     // test last point in a closed path
0131     QVERIFY(KoPathSegment(point5, point4) == path.segmentByIndex(path.pathPointIndex(point5)));
0132     // test out of bounds
0133     QVERIFY(KoPathSegment(0, 0) == path.segmentByIndex(KoPathPointIndex(3, 4)));
0134     QVERIFY(KoPathSegment(0, 0) == path.segmentByIndex(KoPathPointIndex(4, 0)));
0135 }
0136 
0137 void TestPathShape::pointCount()
0138 {
0139     KoPathShape path;
0140     path.moveTo(QPointF(20, 20));
0141     path.lineTo(QPointF(15, 25));
0142     path.lineTo(QPointF(10, 20));
0143     path.close();
0144 
0145     QVERIFY(path.pointCount() == 3);
0146 
0147     path.moveTo(QPointF(20, 30));
0148     path.lineTo(QPointF(20, 30));
0149     path.moveTo(QPointF(30, 30));
0150     path.lineTo(QPointF(40, 30));
0151     path.lineTo(QPointF(40, 40));
0152     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0153 
0154     QVERIFY(path.pointCount() == 9);
0155 
0156     path.moveTo(QPointF(50, 50));
0157     path.lineTo(QPointF(60, 50));
0158     path.lineTo(QPointF(60, 60));
0159     path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0160     path.close();
0161 
0162     QVERIFY(path.pointCount() == 13);
0163 }
0164 
0165 void TestPathShape::subpathPointCount()
0166 {
0167     KoPathShape path;
0168     path.moveTo(QPointF(20, 20));
0169     path.lineTo(QPointF(15, 25));
0170     path.lineTo(QPointF(10, 20));
0171     path.close();
0172     path.moveTo(QPointF(20, 30));
0173     path.lineTo(QPointF(20, 30));
0174     path.moveTo(QPointF(30, 30));
0175     path.lineTo(QPointF(40, 30));
0176     path.lineTo(QPointF(40, 40));
0177     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0178     path.moveTo(QPointF(50, 50));
0179     path.lineTo(QPointF(60, 50));
0180     path.lineTo(QPointF(60, 60));
0181     path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0182     path.close();
0183 
0184     QVERIFY(path.subpathPointCount(0) == 3);
0185     QVERIFY(path.subpathPointCount(1) == 2);
0186     QVERIFY(path.subpathPointCount(2) == 4);
0187     QVERIFY(path.subpathPointCount(3) == 4);
0188     QVERIFY(path.subpathPointCount(4) == -1);
0189 }
0190 
0191 void TestPathShape::isClosedSubpath()
0192 {
0193     KoPathShape path;
0194     path.moveTo(QPointF(20, 20));
0195     path.lineTo(QPointF(15, 25));
0196     path.lineTo(QPointF(10, 20));
0197     path.close();
0198     path.moveTo(QPointF(20, 30));
0199     path.lineTo(QPointF(20, 30));
0200     path.moveTo(QPointF(30, 30));
0201     path.lineTo(QPointF(40, 30));
0202     path.lineTo(QPointF(40, 40));
0203     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0204     path.close();
0205     path.moveTo(QPointF(50, 50));
0206     path.lineTo(QPointF(60, 50));
0207     path.lineTo(QPointF(60, 60));
0208     path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0209     path.close();
0210 
0211     QVERIFY(path.isClosedSubpath(0) == true);
0212     QVERIFY(path.isClosedSubpath(1) == false);
0213     QVERIFY(path.isClosedSubpath(2) == true);
0214     QVERIFY(path.isClosedSubpath(3) == true);
0215 }
0216 
0217 void TestPathShape::insertPoint()
0218 {
0219     KoPathShape path;
0220     path.moveTo(QPointF(10, 10));
0221     path.lineTo(QPointF(20, 20));
0222     path.moveTo(QPointF(30, 30));
0223     path.lineTo(QPointF(40, 40));
0224     path.close();
0225 
0226     // add before the first point of a open subpath
0227     KoPathPoint *point1 = new KoPathPoint(&path, QPointF(5, 5), KoPathPoint::Normal);
0228     KoPathPointIndex p1Index(0, 0);
0229     QVERIFY(path.insertPoint(point1, p1Index) == true);
0230     QVERIFY(point1->parent() == &path);
0231 
0232     KoPathPoint *point2 = new KoPathPoint(&path, QPointF(15, 15), KoPathPoint::Normal);
0233     KoPathPointIndex p2Index(0, 2);
0234     QVERIFY(path.insertPoint(point2, p2Index) == true);
0235     QVERIFY(point2->parent() == &path);
0236 
0237     // add after last point of a open subpath
0238     KoPathPoint *point3 = new KoPathPoint(&path, QPointF(25, 25), KoPathPoint::Normal);
0239     KoPathPointIndex p3Index(0, 4);
0240     QVERIFY(path.insertPoint(point3, p3Index) == true);
0241     QVERIFY(point3->parent() == &path);
0242 
0243     KoPathPoint *point4 = new KoPathPoint(&path, QPointF(40, 30), KoPathPoint::Normal);
0244     KoPathPointIndex p4Index(1, 1);
0245     QVERIFY(path.insertPoint(point4, p4Index) == true);
0246     QVERIFY(point4->parent() == &path);
0247 
0248     // add before the first point of a closed subpath
0249     KoPathPoint *point5 = new KoPathPoint(&path, QPointF(30, 35), KoPathPoint::Normal);
0250     KoPathPointIndex p5Index(1, 0);
0251     QVERIFY(path.insertPoint(point5, p5Index) == true);
0252     QVERIFY(point5->parent() == &path);
0253 
0254     // add after last point of a closed subpath
0255     KoPathPoint *point6 = new KoPathPoint(&path, QPointF(35, 40), KoPathPoint::Normal);
0256     KoPathPointIndex p6Index(1, 4);
0257     QVERIFY(path.insertPoint(point6, p6Index) == true);
0258     QVERIFY(point6->parent() == &path);
0259 
0260     // test out of bounds
0261     KoPathPoint *point7 = new KoPathPoint(&path, QPointF(0, 0), KoPathPoint::Normal);
0262     // subpath index out of bounds
0263     KoPathPointIndex p7Index(2, 0);
0264     QVERIFY(path.insertPoint(point7, p7Index) == false);
0265     // position in subpath out of bounds
0266     p7Index.second = 6;
0267     QVERIFY(path.insertPoint(point7, p7Index) == false);
0268 
0269     QPainterPath ppath(QPointF(5, 5));
0270     ppath.lineTo(10, 10);
0271     ppath.lineTo(15, 15);
0272     ppath.lineTo(20, 20);
0273     ppath.lineTo(25, 25);
0274     ppath.moveTo(30, 35);
0275     ppath.lineTo(30, 30);
0276     ppath.lineTo(40, 30);
0277     ppath.lineTo(40, 40);
0278     ppath.lineTo(35, 40);
0279     ppath.closeSubpath();
0280 
0281     QVERIFY(ppath == path.outline());
0282 
0283     KoPathShape path2;
0284     path2.moveTo(QPointF(0, 0));
0285     KoPathPoint * p = new KoPathPoint(0, QPointF(100, 100));
0286     QVERIFY(path2.insertPoint(p, KoPathPointIndex(0, 1)) == true);
0287     QVERIFY(p->parent() == &path2);
0288 }
0289 
0290 void TestPathShape::removePoint()
0291 {
0292     KoPathShape path;
0293     KoPathPoint *point1 = path.moveTo(QPointF(10, 10));
0294     path.lineTo(QPointF(20, 10));
0295     KoPathPoint *point3 = path.lineTo(QPointF(20, 20));
0296     path.lineTo(QPointF(15, 25));
0297     KoPathPoint *point5 = path.lineTo(QPointF(10, 20));
0298     KoPathPoint *point6 = path.moveTo(QPointF(30, 30));
0299     path.lineTo(QPointF(40, 30));
0300     KoPathPoint *point8 = path.lineTo(QPointF(40, 40));
0301     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0302     KoPathPoint *point10 = path.lineTo(QPointF(30, 35));
0303     path.close();
0304 
0305     // remove from beginning of a open subpath
0306     QVERIFY(path.removePoint(path.pathPointIndex(point1)) == point1);
0307     // remove from middle of a open subpath
0308     QVERIFY(path.removePoint(path.pathPointIndex(point3)) == point3);
0309     // remove from end of a open subpath
0310     QVERIFY(path.removePoint(path.pathPointIndex(point5)) == point5);
0311 
0312     // remove from beginning of a closed subpath
0313     QVERIFY(path.removePoint(path.pathPointIndex(point6)) == point6);
0314     // remove from middle of a closed subpath
0315     QVERIFY(path.removePoint(path.pathPointIndex(point8)) == point8);
0316     // remove from end of a closed subpath
0317     QVERIFY(path.removePoint(path.pathPointIndex(point10)) == point10);
0318 
0319     QPainterPath ppath(QPointF(20, 10));
0320     ppath.lineTo(15, 25);
0321     ppath.moveTo(40, 30);
0322     ppath.quadTo(30, 45, 30, 40);
0323     ppath.closeSubpath();
0324 
0325     QVERIFY(ppath == path.outline());
0326 }
0327 
0328 void TestPathShape::splitAfter()
0329 {
0330     KoPathShape path;
0331     path.moveTo(QPointF(10, 10));
0332     path.lineTo(QPointF(20, 10));
0333     path.lineTo(QPointF(20, 20));
0334     path.lineTo(QPointF(15, 25));
0335     path.lineTo(QPointF(10, 20));
0336     path.moveTo(QPointF(30, 30));
0337     path.lineTo(QPointF(40, 30));
0338     path.lineTo(QPointF(40, 40));
0339     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0340     path.close();
0341 
0342     QVERIFY(path.breakAfter(KoPathPointIndex(0, 1)) == true);
0343     // try to break at the last point in the subpath
0344     QVERIFY(path.breakAfter(KoPathPointIndex(1, 2)) == false);
0345     // try to break a closed subpath
0346     QVERIFY(path.breakAfter(KoPathPointIndex(2, 1)) == false);
0347 
0348     QPainterPath ppath(QPointF(10, 10));
0349     ppath.lineTo(20, 10);
0350     ppath.moveTo(20, 20);
0351     ppath.lineTo(15, 25);
0352     ppath.lineTo(10, 20);
0353     ppath.moveTo(30, 30);
0354     ppath.lineTo(40, 30);
0355     ppath.lineTo(40, 40);
0356     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0357     ppath.closeSubpath();
0358 
0359     QVERIFY(ppath == path.outline());
0360 }
0361 
0362 void TestPathShape::join()
0363 {
0364     KoPathShape path;
0365     path.moveTo(QPointF(10, 10));
0366     path.lineTo(QPointF(20, 10));
0367     path.moveTo(QPointF(20, 20));
0368     path.lineTo(QPointF(15, 25));
0369     path.lineTo(QPointF(10, 20));
0370     path.moveTo(QPointF(30, 30));
0371     path.lineTo(QPointF(40, 30));
0372     path.lineTo(QPointF(40, 40));
0373     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0374     path.close();
0375     path.moveTo(QPointF(50, 50));
0376     path.lineTo(QPointF(60, 60));
0377 
0378     QVERIFY(path.join(0) == true);
0379     // try to join to a closed subpath
0380     QVERIFY(path.join(0) == false);
0381     // try to join from a closed subpath
0382     QVERIFY(path.join(1) == false);
0383     // try to join last subpath
0384     QVERIFY(path.join(2) == false);
0385 
0386     QPainterPath ppath(QPointF(10, 10));
0387     ppath.lineTo(20, 10);
0388     ppath.lineTo(20, 20);
0389     ppath.lineTo(15, 25);
0390     ppath.lineTo(10, 20);
0391     ppath.moveTo(30, 30);
0392     ppath.lineTo(40, 30);
0393     ppath.lineTo(40, 40);
0394     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0395     ppath.closeSubpath();
0396     ppath.moveTo(50, 50);
0397     ppath.lineTo(60, 60);
0398 
0399     QVERIFY(ppath == path.outline());
0400 }
0401 
0402 void TestPathShape::moveSubpath()
0403 {
0404     KoPathShape path;
0405     path.moveTo(QPointF(10, 10));
0406     path.lineTo(QPointF(20, 10));
0407     path.moveTo(QPointF(20, 20));
0408     path.lineTo(QPointF(15, 25));
0409     path.lineTo(QPointF(10, 20));
0410     path.moveTo(QPointF(30, 30));
0411     path.lineTo(QPointF(40, 30));
0412     path.lineTo(QPointF(40, 40));
0413     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0414     path.close();
0415 
0416     QVERIFY(path.moveSubpath(0, 1) == true);
0417     QVERIFY(path.moveSubpath(1, 0) == true);
0418     QVERIFY(path.moveSubpath(2, 1) == true);
0419     QVERIFY(path.moveSubpath(0, 2) == true);
0420     QVERIFY(path.moveSubpath(3, 1) == false);
0421     QVERIFY(path.moveSubpath(1, 3) == false);
0422 
0423     QPainterPath ppath(QPointF(30, 30));
0424     ppath.lineTo(40, 30);
0425     ppath.lineTo(40, 40);
0426     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0427     ppath.closeSubpath();
0428     ppath.moveTo(20, 20);
0429     ppath.lineTo(15, 25);
0430     ppath.lineTo(10, 20);
0431     ppath.moveTo(10, 10);
0432     ppath.lineTo(20, 10);
0433 
0434     QVERIFY(ppath == path.outline());
0435 }
0436 
0437 void TestPathShape::openSubpath()
0438 {
0439     KoPathShape path;
0440     path.moveTo(QPointF(20, 20));
0441     KoPathPoint *point1 = path.lineTo(QPointF(15, 25));
0442     path.lineTo(QPointF(10, 20));
0443     path.close();
0444     KoPathPoint *point2 = path.moveTo(QPointF(30, 30));
0445     path.lineTo(QPointF(40, 30));
0446     path.lineTo(QPointF(40, 40));
0447     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0448     path.close();
0449     path.moveTo(QPointF(50, 50));
0450     path.lineTo(QPointF(60, 50));
0451     path.lineTo(QPointF(60, 60));
0452     KoPathPoint *point3 = path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0453     path.close();
0454     KoPathPoint *point4 = path.moveTo(QPointF(100, 100));
0455     point4->setControlPoint2(QPointF(120, 120));
0456     path.lineTo(QPointF(140, 140));
0457     KoPathPoint *point5 = path.lineTo(QPointF(140, 100));
0458     path.close();
0459 
0460     // open at middle point in subpath
0461     QVERIFY(path.openSubpath(path.pathPointIndex(point1)) == KoPathPointIndex(0, 2));
0462     QVERIFY(path.pointByIndex(KoPathPointIndex(0,0))->properties() & KoPathPoint::StartSubpath);
0463     QVERIFY(path.pointByIndex(KoPathPointIndex(0,2))->properties() & KoPathPoint::StopSubpath);
0464     // open at first point in subpath
0465     QVERIFY(path.openSubpath(path.pathPointIndex(point2)) == KoPathPointIndex(1, 0));
0466     QVERIFY(path.pointByIndex(KoPathPointIndex(1,0))->properties() & KoPathPoint::StartSubpath);
0467     QVERIFY(path.pointByIndex(KoPathPointIndex(1,3))->properties() & KoPathPoint::StopSubpath);
0468     // open at last point in subpath
0469     QVERIFY(path.openSubpath(path.pathPointIndex(point3)) == KoPathPointIndex(2, 1));
0470     QVERIFY(path.pointByIndex(KoPathPointIndex(2,0))->properties() & KoPathPoint::StartSubpath);
0471     QVERIFY(path.pointByIndex(KoPathPointIndex(2,3))->properties() & KoPathPoint::StopSubpath);
0472     // try to open subpath
0473     QVERIFY(path.openSubpath(path.pathPointIndex(point3)) == KoPathPointIndex(-1, -1));
0474     // open if the first path is a curve
0475     QVERIFY(path.openSubpath(path.pathPointIndex(point5)) == KoPathPointIndex(3, 1));
0476     QVERIFY(path.pointByIndex(KoPathPointIndex(3,0))->properties() & KoPathPoint::StartSubpath);
0477     QVERIFY(path.pointByIndex(KoPathPointIndex(3,2))->properties() & KoPathPoint::StopSubpath);
0478     // try to open none existing subpath
0479     QVERIFY(path.openSubpath(KoPathPointIndex(4, 1)) == KoPathPointIndex(-1, -1));
0480 
0481     QPainterPath ppath(QPointF(15, 25));
0482     ppath.lineTo(10, 20);
0483     ppath.lineTo(20, 20);
0484     ppath.moveTo(30, 30);
0485     ppath.lineTo(40, 30);
0486     ppath.lineTo(40, 40);
0487     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0488     ppath.moveTo(50, 60);
0489     ppath.lineTo(50, 50);
0490     ppath.lineTo(60, 50);
0491     ppath.lineTo(60, 60);
0492     ppath.moveTo(140, 100);
0493     ppath.lineTo(100, 100);
0494     ppath.quadTo(120, 120, 140, 140);
0495 
0496     QVERIFY(ppath == path.outline());
0497 }
0498 
0499 void TestPathShape::closeSubpath()
0500 {
0501     KoPathShape path;
0502     path.moveTo(QPointF(20, 20));
0503     KoPathPoint *point1 = path.lineTo(QPointF(15, 25));
0504     path.lineTo(QPointF(10, 20));
0505     KoPathPoint *point2 = path.moveTo(QPointF(30, 30));
0506     path.lineTo(QPointF(40, 30));
0507     path.lineTo(QPointF(40, 40));
0508     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0509     path.moveTo(QPointF(50, 50));
0510     path.lineTo(QPointF(60, 50));
0511     path.lineTo(QPointF(60, 60));
0512     KoPathPoint *point3 = path.curveTo(QPointF(60, 65), QPointF(50, 65), QPointF(50, 60));
0513 
0514     // open at middle point in subpath
0515     QVERIFY(path.closeSubpath(path.pathPointIndex(point1)) == KoPathPointIndex(0, 2));
0516     // open at first point in subpath
0517     QVERIFY(path.closeSubpath(path.pathPointIndex(point2)) == KoPathPointIndex(1, 0));
0518     // open at last point in subpath
0519     QVERIFY(path.closeSubpath(path.pathPointIndex(point3)) == KoPathPointIndex(2, 1));
0520     // try to close a closed subpath
0521     QVERIFY(path.closeSubpath(path.pathPointIndex(point3)) == KoPathPointIndex(-1, -1));
0522     // try to close a none existing subpath
0523     QVERIFY(path.closeSubpath(KoPathPointIndex(3, 1)) == KoPathPointIndex(-1, -1));
0524     // try to close at a none existing position in a subpath
0525     QVERIFY(path.closeSubpath(KoPathPointIndex(2, 4)) == KoPathPointIndex(-1, -1));
0526 
0527     QPainterPath ppath(QPointF(15, 25));
0528     ppath.lineTo(10, 20);
0529     ppath.lineTo(20, 20);
0530     ppath.closeSubpath();
0531     ppath.moveTo(30, 30);
0532     ppath.lineTo(40, 30);
0533     ppath.lineTo(40, 40);
0534     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0535     ppath.closeSubpath();
0536     ppath.moveTo(50, 60);
0537     ppath.lineTo(50, 50);
0538     ppath.lineTo(60, 50);
0539     ppath.lineTo(60, 60);
0540     ppath.cubicTo(60, 65, 50, 65, 50, 60);
0541     ppath.closeSubpath();
0542 
0543     QVERIFY(ppath == path.outline());
0544 }
0545 
0546 void TestPathShape::openCloseSubpath()
0547 {
0548     KoPathShape path;
0549     path.moveTo(QPointF(20, 20));
0550     KoPathPoint *point1 = path.lineTo(QPointF(15, 25));
0551     path.lineTo(QPointF(10, 20));
0552     path.close();
0553     KoPathPoint *point2 = path.moveTo(QPointF(30, 30));
0554     path.lineTo(QPointF(40, 30));
0555     path.lineTo(QPointF(40, 40));
0556     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0557 
0558     KoPathPointIndex p1Index = path.pathPointIndex(point1);
0559     KoPathPointIndex p1OldIndex = path.openSubpath(p1Index);
0560     QVERIFY(path.closeSubpath(p1OldIndex) == p1Index);
0561 
0562     KoPathPointIndex p2Index = path.pathPointIndex(point2);
0563     KoPathPointIndex p2OldIndex = path.closeSubpath(p2Index);
0564     QVERIFY(path.openSubpath(p2OldIndex) == p2Index);
0565 
0566     QPainterPath ppath(QPointF(20, 20));
0567     ppath.lineTo(15, 25);
0568     ppath.lineTo(10, 20);
0569     ppath.closeSubpath();
0570     ppath.moveTo(30, 30);
0571     ppath.lineTo(40, 30);
0572     ppath.lineTo(40, 40);
0573     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0574 
0575     QVERIFY(ppath == path.outline());
0576 }
0577 
0578 void TestPathShape::reverseSubpath()
0579 {
0580     KoPathShape path;
0581     path.moveTo(QPointF(10, 10));
0582     path.lineTo(QPointF(20, 10));
0583     path.moveTo(QPointF(20, 20));
0584     path.lineTo(QPointF(15, 25));
0585     path.lineTo(QPointF(10, 20));
0586     path.moveTo(QPointF(30, 30));
0587     path.lineTo(QPointF(40, 30));
0588     path.lineTo(QPointF(40, 40));
0589     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0590     path.close();
0591 
0592     QVERIFY(path.reverseSubpath(0) == true);
0593     QVERIFY(path.reverseSubpath(1) == true);
0594     QVERIFY(path.reverseSubpath(1) == true);
0595     QVERIFY(path.reverseSubpath(2) == true);
0596     QVERIFY(path.reverseSubpath(3) == false);
0597 
0598     QPainterPath ppath(QPointF(20, 10));
0599     ppath.lineTo(10, 10);
0600     ppath.moveTo(20, 20);
0601     ppath.lineTo(15, 25);
0602     ppath.lineTo(10, 20);
0603     ppath.moveTo(30, 40);
0604     ppath.cubicTo(30, 45, 40, 45, 40, 40);
0605     ppath.lineTo(40, 30);
0606     ppath.lineTo(30, 30);
0607     ppath.closeSubpath();
0608 
0609     QVERIFY(ppath == path.outline());
0610 
0611     QVERIFY(path.reverseSubpath(2) == true);
0612     QVERIFY(path.reverseSubpath(2) == true);
0613 
0614     QVERIFY(ppath == path.outline());
0615 }
0616 
0617 void TestPathShape::removeSubpath()
0618 {
0619 #if 0
0620     // enable again when point groups work
0621     KoPathShape path;
0622     path.moveTo(QPointF(10, 10));
0623     path.lineTo(QPointF(20, 10));
0624     path.lineTo(QPointF(20, 20));
0625     path.close();
0626     path.lineTo(QPointF(15, 25));
0627     path.lineTo(QPointF(10, 20));
0628     path.moveTo(QPointF(30, 30));
0629     path.lineTo(QPointF(40, 30));
0630     path.lineTo(QPointF(40, 40));
0631     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0632     path.close();
0633 
0634     QVERIFY(path.removeSubpath(0) != 0);
0635     QVERIFY(path.removeSubpath(1) != 0);
0636     QVERIFY(path.removeSubpath(1) == 0);
0637 
0638     QPainterPath ppath(QPointF(10, 20));
0639     ppath.lineTo(15, 25);
0640     ppath.lineTo(10, 20);
0641 
0642     path.debugPath();
0643 
0644     QVERIFY(ppath == path.outline());
0645 #endif
0646 
0647     KoPathShape path;
0648     path.moveTo(QPointF(10, 10));
0649     path.lineTo(QPointF(20, 10));
0650     path.lineTo(QPointF(20, 20));
0651     path.close();
0652     path.moveTo(QPointF(15, 25));
0653     path.lineTo(QPointF(10, 20));
0654     path.moveTo(QPointF(30, 30));
0655     path.lineTo(QPointF(40, 30));
0656     path.lineTo(QPointF(40, 40));
0657     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0658     path.close();
0659 
0660     QVERIFY(path.removeSubpath(0) != 0);
0661     QVERIFY(path.removeSubpath(1) != 0);
0662     QVERIFY(path.removeSubpath(1) == 0);
0663 
0664     QPainterPath ppath(QPointF(15, 25));
0665     ppath.lineTo(10, 20);
0666 
0667     QVERIFY(ppath == path.outline());
0668 }
0669 
0670 void TestPathShape::addSubpath()
0671 {
0672     KoPathShape path;
0673     path.moveTo(QPointF(10, 10));
0674     path.lineTo(QPointF(20, 10));
0675     path.lineTo(QPointF(20, 20));
0676     path.close();
0677     path.moveTo(QPointF(15, 25));
0678     path.lineTo(QPointF(10, 20));
0679     path.moveTo(QPointF(30, 30));
0680     path.lineTo(QPointF(40, 30));
0681     path.lineTo(QPointF(40, 40));
0682     path.curveTo(QPointF(40, 45), QPointF(30, 45), QPointF(30, 40));
0683     path.close();
0684 
0685     KoSubpath * sp1 = path.removeSubpath(0);
0686     QVERIFY(path.addSubpath(sp1, 0) == true);
0687 
0688     KoSubpath * sp2 = path.removeSubpath(1);
0689     QVERIFY(path.addSubpath(sp2, 1) == true);
0690 
0691     QVERIFY(path.addSubpath(sp2, 4) == false);
0692 
0693     QPainterPath ppath(QPointF(10, 10));
0694     ppath.lineTo(20, 10);
0695     ppath.lineTo(20, 20);
0696     ppath.closeSubpath();
0697     ppath.moveTo(15, 25);
0698     ppath.lineTo(10, 20);
0699     ppath.moveTo(30, 30);
0700     ppath.lineTo(40, 30);
0701     ppath.lineTo(40, 40);
0702     ppath.cubicTo(40, 45, 30, 45, 30, 40);
0703     ppath.closeSubpath();
0704 
0705     QVERIFY(ppath == path.outline());
0706 }
0707 
0708 void TestPathShape::koPathPointDataLess()
0709 {
0710     QList<KoPathPointData> v;
0711     v.push_back(KoPathPointData((KoPathShape*)1, KoPathPointIndex(1, 1)));
0712     v.push_back(KoPathPointData((KoPathShape*)1, KoPathPointIndex(1, 2)));
0713     v.push_back(KoPathPointData((KoPathShape*)1, KoPathPointIndex(1, 3)));
0714     v.push_back(KoPathPointData((KoPathShape*)1, KoPathPointIndex(1, 6)));
0715     v.push_back(KoPathPointData((KoPathShape*)2, KoPathPointIndex(2, 1)));
0716     v.push_back(KoPathPointData((KoPathShape*)2, KoPathPointIndex(2, 3)));
0717     v.push_back(KoPathPointData((KoPathShape*)2, KoPathPointIndex(3, 3)));
0718     v.push_back(KoPathPointData((KoPathShape*)3, KoPathPointIndex(1, 1)));
0719     v.push_back(KoPathPointData((KoPathShape*)3, KoPathPointIndex(1, 2)));
0720 
0721     QList<KoPathPointData> l;
0722     l.push_back(v[8]);
0723     l.push_back(v[0]);
0724     l.push_back(v[1]);
0725     l.push_back(v[7]);
0726     l.push_back(v[6]);
0727     l.push_back(v[2]);
0728     l.push_back(v[5]);
0729     l.push_back(v[3]);
0730     l.push_back(v[4]);
0731 
0732     std::sort(l.begin(), l.end());
0733     for (int i = 0; i < v.size(); ++i) {
0734         KoPathPointData ld = l.at(i);
0735         KoPathPointData vd = v[i];
0736         QVERIFY(ld.pathShape == vd.pathShape);
0737         QVERIFY(ld.pointIndex.first == vd.pointIndex.first);
0738         QVERIFY(ld.pointIndex.second == vd.pointIndex.second);
0739     }
0740 }
0741 
0742 void TestPathShape::closeMerge()
0743 {
0744     KoPathShape path;
0745     KoPathPoint *p1 = path.moveTo(QPointF(0, 0));
0746     KoPathPoint *p2 = path.curveTo(QPointF(50, 0), QPointF(100, 50), QPointF(100, 100));
0747     KoPathPoint *p3 = path.curveTo(QPointF(50, 100), QPointF(0, 50), QPointF(0, 0));
0748     QVERIFY(p1->properties() & KoPathPoint::StartSubpath);
0749     QVERIFY((p1->properties() & KoPathPoint::CloseSubpath) == 0);
0750     QVERIFY(p1->activeControlPoint1() == false);
0751     QVERIFY(p1->activeControlPoint2());
0752     QVERIFY(p2->activeControlPoint1());
0753     QVERIFY(p2->activeControlPoint2());
0754     QVERIFY((p3->properties() & KoPathPoint::CloseSubpath) == 0);
0755     QVERIFY(p3->activeControlPoint1());
0756     QCOMPARE(path.pointCount(), 3);
0757 
0758     path.closeMerge();
0759     QCOMPARE(path.pointCount(), 2);
0760     QVERIFY(p1->properties() & KoPathPoint::CloseSubpath);
0761     QVERIFY(p1->activeControlPoint1());
0762     QVERIFY(p2->properties() & KoPathPoint::CloseSubpath);
0763     QVERIFY(p2->activeControlPoint2());
0764 
0765     QPainterPath ppath(QPointF(0, 0));
0766     ppath.cubicTo(50, 0, 100, 50, 100, 100);
0767     ppath.cubicTo(50, 100, 0, 50, 0, 0);
0768 
0769     QVERIFY(path.outline() == ppath);
0770 }
0771 
0772 SIMPLE_TEST_MAIN(TestPathShape)