src/gui/painting/qpathclipper.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qpathclipper_p.h"
       
    43 
       
    44 #include <private/qbezier_p.h>
       
    45 #include <private/qdatabuffer_p.h>
       
    46 #include <qmath.h>
       
    47 
       
    48 /**
       
    49   The algorithm is as follows:
       
    50 
       
    51   1. Find all intersections between the two paths (including self-intersections),
       
    52      and build a winged edge structure of non-intersecting parts.
       
    53   2. While there are more unhandled edges:
       
    54     3. Pick a y-coordinate from an unhandled edge.
       
    55     4. Intersect the horizontal line at y-coordinate with all edges.
       
    56     5. Traverse intersections left to right deciding whether each subpath should be added or not.
       
    57     6. If the subpath should be added, traverse the winged-edge structure and add the edges to
       
    58        a separate winged edge structure.
       
    59     7. Mark all edges in subpaths crossing the horizontal line as handled.
       
    60  8. (Optional) Simplify the resulting winged edge structure by merging shared edges.
       
    61  9. Convert the resulting winged edge structure to a painter path.
       
    62  */
       
    63 
       
    64 #include <qdebug.h>
       
    65 
       
    66 QT_BEGIN_NAMESPACE
       
    67 
       
    68 static inline bool fuzzyIsNull(qreal d)
       
    69 {
       
    70     if (sizeof(qreal) == sizeof(double))
       
    71         return qAbs(d) <= 1e-12;
       
    72     else
       
    73         return qAbs(d) <= 1e-5f;
       
    74 }
       
    75 
       
    76 static inline bool comparePoints(const QPointF &a, const QPointF &b)
       
    77 {
       
    78     return fuzzyIsNull(a.x() - b.x())
       
    79            && fuzzyIsNull(a.y() - b.y());
       
    80 }
       
    81 
       
    82 //#define QDEBUG_CLIPPER
       
    83 static qreal dot(const QPointF &a, const QPointF &b)
       
    84 {
       
    85     return a.x() * b.x() + a.y() * b.y();
       
    86 }
       
    87 
       
    88 static QPointF normalize(const QPointF &p)
       
    89 {
       
    90     return p / qSqrt(p.x() * p.x() + p.y() * p.y());
       
    91 }
       
    92 
       
    93 static bool pathToRect(const QPainterPath &path, QRectF *rect = 0);
       
    94 
       
    95 struct QIntersection
       
    96 {
       
    97     qreal alphaA;
       
    98     qreal alphaB;
       
    99 
       
   100     QPointF pos;
       
   101 };
       
   102 
       
   103 class QIntersectionFinder
       
   104 {
       
   105 public:
       
   106     void produceIntersections(QPathSegments &segments);
       
   107     bool hasIntersections(const QPathSegments &a, const QPathSegments &b) const;
       
   108 
       
   109 private:
       
   110     void intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections);
       
   111     void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);
       
   112 
       
   113     bool beziersIntersect(const QBezier &one, const QBezier &two) const;
       
   114     bool linesIntersect(const QLineF &a, const QLineF &b) const;
       
   115 };
       
   116 
       
   117 bool QIntersectionFinder::beziersIntersect(const QBezier &one, const QBezier &two) const
       
   118 {
       
   119     return (comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2())
       
   120             && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4()))
       
   121            || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3())
       
   122                && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))
       
   123            || QBezier::findIntersections(one, two, 0);
       
   124 }
       
   125 
       
   126 bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const
       
   127 {
       
   128     const QPointF p1 = a.p1();
       
   129     const QPointF p2 = a.p2();
       
   130 
       
   131     const QPointF q1 = b.p1();
       
   132     const QPointF q2 = b.p2();
       
   133 
       
   134     if (comparePoints(p1, p2) || comparePoints(q1, q2))
       
   135         return false;
       
   136 
       
   137     const bool p1_equals_q1 = comparePoints(p1, q1);
       
   138     const bool p2_equals_q2 = comparePoints(p2, q2);
       
   139 
       
   140     if (p1_equals_q1 && p2_equals_q2)
       
   141         return true;
       
   142 
       
   143     const bool p1_equals_q2 = comparePoints(p1, q2);
       
   144     const bool p2_equals_q1 = comparePoints(p2, q1);
       
   145 
       
   146     if (p1_equals_q2 && p2_equals_q1)
       
   147         return true;
       
   148 
       
   149     const QPointF pDelta = p2 - p1;
       
   150     const QPointF qDelta = q2 - q1;
       
   151 
       
   152     const qreal par = pDelta.x() * qDelta.y() - pDelta.y() * qDelta.x();
       
   153 
       
   154     if (qFuzzyIsNull(par)) {
       
   155         const QPointF normal(-pDelta.y(), pDelta.x());
       
   156 
       
   157         // coinciding?
       
   158         if (qFuzzyIsNull(dot(normal, q1 - p1))) {
       
   159             const qreal dp = dot(pDelta, pDelta);
       
   160 
       
   161             const qreal tq1 = dot(pDelta, q1 - p1);
       
   162             const qreal tq2 = dot(pDelta, q2 - p1);
       
   163 
       
   164             if ((tq1 > 0 && tq1 < dp) || (tq2 > 0 && tq2 < dp))
       
   165                 return true;
       
   166 
       
   167             const qreal dq = dot(qDelta, qDelta);
       
   168 
       
   169             const qreal tp1 = dot(qDelta, p1 - q1);
       
   170             const qreal tp2 = dot(qDelta, p2 - q1);
       
   171 
       
   172             if ((tp1 > 0 && tp1 < dq) || (tp2 > 0 && tp2 < dq))
       
   173                 return true;
       
   174         }
       
   175 
       
   176         return false;
       
   177     }
       
   178 
       
   179     // if the lines are not parallel and share a common end point, then they
       
   180     // don't intersect
       
   181     if (p1_equals_q1 || p1_equals_q2 || p2_equals_q1 || p2_equals_q2)
       
   182         return false;
       
   183 
       
   184     const qreal invPar = 1 / par;
       
   185 
       
   186     const qreal tp = (qDelta.y() * (q1.x() - p1.x()) -
       
   187                       qDelta.x() * (q1.y() - p1.y())) * invPar;
       
   188 
       
   189     if (tp < 0 || tp > 1)
       
   190         return false;
       
   191 
       
   192     const qreal tq = (pDelta.y() * (q1.x() - p1.x()) -
       
   193                       pDelta.x() * (q1.y() - p1.y())) * invPar;
       
   194 
       
   195     return tq >= 0 && tq <= 1;
       
   196 }
       
   197 
       
   198 void QIntersectionFinder::intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections)
       
   199 {
       
   200     if ((comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2())
       
   201          && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4()))
       
   202         || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3())
       
   203             && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))) {
       
   204 
       
   205         return;
       
   206     }
       
   207 
       
   208     t.clear();
       
   209 
       
   210     if (!QBezier::findIntersections(one, two, &t))
       
   211         return;
       
   212 
       
   213     int count = t.size();
       
   214 
       
   215     for (int i = 0; i < count; ++i) {
       
   216         qreal alpha_p = t.at(i).first;
       
   217         qreal alpha_q = t.at(i).second;
       
   218 
       
   219         QPointF pt;
       
   220         if (qFuzzyIsNull(alpha_p)) {
       
   221             pt = one.pt1();
       
   222         } else if (qFuzzyIsNull(alpha_p - 1)) {
       
   223             pt = one.pt4();
       
   224         } else if (qFuzzyIsNull(alpha_q)) {
       
   225             pt = two.pt1();
       
   226         } else if (qFuzzyIsNull(alpha_q - 1)) {
       
   227             pt = two.pt4();
       
   228         } else {
       
   229             pt = one.pointAt(alpha_p);
       
   230         }
       
   231 
       
   232         QIntersection intersection;
       
   233         intersection.alphaA = alpha_p;
       
   234         intersection.alphaB = alpha_q;
       
   235         intersection.pos = pt;
       
   236         intersections.add(intersection);
       
   237     }
       
   238 }
       
   239 
       
   240 void QIntersectionFinder::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections)
       
   241 {
       
   242     const QPointF p1 = a.p1();
       
   243     const QPointF p2 = a.p2();
       
   244 
       
   245     const QPointF q1 = b.p1();
       
   246     const QPointF q2 = b.p2();
       
   247 
       
   248     if (comparePoints(p1, p2) || comparePoints(q1, q2))
       
   249         return;
       
   250 
       
   251     const bool p1_equals_q1 = comparePoints(p1, q1);
       
   252     const bool p2_equals_q2 = comparePoints(p2, q2);
       
   253 
       
   254     if (p1_equals_q1 && p2_equals_q2)
       
   255         return;
       
   256 
       
   257     const bool p1_equals_q2 = comparePoints(p1, q2);
       
   258     const bool p2_equals_q1 = comparePoints(p2, q1);
       
   259 
       
   260     if (p1_equals_q2 && p2_equals_q1)
       
   261         return;
       
   262 
       
   263     const QPointF pDelta = p2 - p1;
       
   264     const QPointF qDelta = q2 - q1;
       
   265 
       
   266     const qreal par = pDelta.x() * qDelta.y() - pDelta.y() * qDelta.x();
       
   267 
       
   268     if (qFuzzyIsNull(par)) {
       
   269         const QPointF normal(-pDelta.y(), pDelta.x());
       
   270 
       
   271         // coinciding?
       
   272         if (qFuzzyIsNull(dot(normal, q1 - p1))) {
       
   273             const qreal invDp = 1 / dot(pDelta, pDelta);
       
   274 
       
   275             const qreal tq1 = dot(pDelta, q1 - p1) * invDp;
       
   276             const qreal tq2 = dot(pDelta, q2 - p1) * invDp;
       
   277 
       
   278             if (tq1 > 0 && tq1 < 1) {
       
   279                 QIntersection intersection;
       
   280                 intersection.alphaA = tq1;
       
   281                 intersection.alphaB = 0;
       
   282                 intersection.pos = q1;
       
   283                 intersections.add(intersection);
       
   284             }
       
   285 
       
   286             if (tq2 > 0 && tq2 < 1) {
       
   287                 QIntersection intersection;
       
   288                 intersection.alphaA = tq2;
       
   289                 intersection.alphaB = 1;
       
   290                 intersection.pos = q2;
       
   291                 intersections.add(intersection);
       
   292             }
       
   293 
       
   294             const qreal invDq = 1 / dot(qDelta, qDelta);
       
   295 
       
   296             const qreal tp1 = dot(qDelta, p1 - q1) * invDq;
       
   297             const qreal tp2 = dot(qDelta, p2 - q1) * invDq;
       
   298 
       
   299             if (tp1 > 0 && tp1 < 1) {
       
   300                 QIntersection intersection;
       
   301                 intersection.alphaA = 0;
       
   302                 intersection.alphaB = tp1;
       
   303                 intersection.pos = p1;
       
   304                 intersections.add(intersection);
       
   305             }
       
   306 
       
   307             if (tp2 > 0 && tp2 < 1) {
       
   308                 QIntersection intersection;
       
   309                 intersection.alphaA = 1;
       
   310                 intersection.alphaB = tp2;
       
   311                 intersection.pos = p2;
       
   312                 intersections.add(intersection);
       
   313             }
       
   314         }
       
   315 
       
   316         return;
       
   317     }
       
   318 
       
   319     // if the lines are not parallel and share a common end point, then they
       
   320     // don't intersect
       
   321     if (p1_equals_q1 || p1_equals_q2 || p2_equals_q1 || p2_equals_q2)
       
   322         return;
       
   323 
       
   324 
       
   325     const qreal tp = (qDelta.y() * (q1.x() - p1.x()) -
       
   326                       qDelta.x() * (q1.y() - p1.y())) / par;
       
   327     const qreal tq = (pDelta.y() * (q1.x() - p1.x()) -
       
   328                       pDelta.x() * (q1.y() - p1.y())) / par;
       
   329 
       
   330     if (tp<0 || tp>1 || tq<0 || tq>1)
       
   331         return;
       
   332 
       
   333     const bool p_zero = qFuzzyIsNull(tp);
       
   334     const bool p_one = qFuzzyIsNull(tp - 1);
       
   335 
       
   336     const bool q_zero = qFuzzyIsNull(tq);
       
   337     const bool q_one = qFuzzyIsNull(tq - 1);
       
   338 
       
   339     if ((q_zero || q_one) && (p_zero || p_one))
       
   340         return;
       
   341 
       
   342     QPointF pt;
       
   343     if (p_zero) {
       
   344         pt = p1;
       
   345     } else if (p_one) {
       
   346         pt = p2;
       
   347     } else if (q_zero) {
       
   348         pt = q1;
       
   349     } else if (q_one) {
       
   350         pt = q2;
       
   351     } else {
       
   352         pt = q1 + (q2 - q1) * tq;
       
   353     }
       
   354 
       
   355     QIntersection intersection;
       
   356     intersection.alphaA = tp;
       
   357     intersection.alphaB = tq;
       
   358     intersection.pos = pt;
       
   359     intersections.add(intersection);
       
   360 }
       
   361 
       
   362 static const QBezier bezierFromLine(const QLineF &line)
       
   363 {
       
   364     const QPointF p1 = line.p1();
       
   365     const QPointF p2 = line.p2();
       
   366     const QPointF delta = (p2 - p1) / 3;
       
   367     return QBezier::fromPoints(p1, p1 + delta, p1 + 2 * delta, p2);
       
   368 }
       
   369 
       
   370 bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const
       
   371 {
       
   372     QBezier tempA;
       
   373     QBezier tempB;
       
   374 
       
   375     if (a.segments() == 0 || b.segments() == 0)
       
   376         return false;
       
   377 
       
   378     const QRectF &rb0 = b.elementBounds(0);
       
   379 
       
   380     qreal minX = rb0.left();
       
   381     qreal minY = rb0.top();
       
   382     qreal maxX = rb0.right();
       
   383     qreal maxY = rb0.bottom();
       
   384 
       
   385     for (int i = 1; i < b.segments(); ++i) {
       
   386         const QRectF &r = b.elementBounds(i);
       
   387         minX = qMin(minX, r.left());
       
   388         minY = qMin(minY, r.top());
       
   389         maxX = qMax(maxX, r.right());
       
   390         maxY = qMax(maxY, r.bottom());
       
   391     }
       
   392 
       
   393     QRectF rb(minX, minY, maxX - minX, maxY - minY);
       
   394 
       
   395     for (int i = 0; i < a.segments(); ++i) {
       
   396         const QBezier *bezierA = a.bezierAt(i);
       
   397         bool isBezierA = bezierA != 0;
       
   398 
       
   399         const QRectF &r1 = a.elementBounds(i);
       
   400 
       
   401         if (r1.left() > rb.right() || rb.left() > r1.right())
       
   402             continue;
       
   403         if (r1.top() > rb.bottom() || rb.top() > r1.bottom())
       
   404             continue;
       
   405 
       
   406         for (int j = 0; j < b.segments(); ++j) {
       
   407             const QRectF &r2 = b.elementBounds(j);
       
   408 
       
   409             if (r1.left() > r2.right() || r2.left() > r1.right())
       
   410                 continue;
       
   411             if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
       
   412                 continue;
       
   413 
       
   414             bool isBezierB = b.bezierAt(j) != 0;
       
   415 
       
   416             if (isBezierA || isBezierB) {
       
   417                 const QBezier *bezierB;
       
   418                 if (isBezierB) {
       
   419                     bezierB = b.bezierAt(j);
       
   420                 } else {
       
   421                     tempB = bezierFromLine(b.lineAt(j));
       
   422                     bezierB = &tempB;
       
   423                 }
       
   424 
       
   425                 if (!bezierA) {
       
   426                     tempA = bezierFromLine(a.lineAt(i));
       
   427                     bezierA = &tempA;
       
   428                 }
       
   429 
       
   430                 if (beziersIntersect(*bezierA, *bezierB))
       
   431                     return true;
       
   432             } else {
       
   433                 if (linesIntersect(a.lineAt(i), b.lineAt(j)))
       
   434                     return true;
       
   435             }
       
   436         }
       
   437     }
       
   438 
       
   439     return false;
       
   440 }
       
   441 
       
   442 void QIntersectionFinder::produceIntersections(QPathSegments &segments)
       
   443 {
       
   444     QBezier tempA;
       
   445     QBezier tempB;
       
   446 
       
   447     QVector<QPair<qreal, qreal> > t;
       
   448     QDataBuffer<QIntersection> intersections;
       
   449 
       
   450     for (int i = 0; i < segments.segments(); ++i) {
       
   451         const QBezier *bezierA = segments.bezierAt(i);
       
   452         bool isBezierA = bezierA != 0;
       
   453 
       
   454         const QRectF &r1 = segments.elementBounds(i);
       
   455 
       
   456         for (int j = 0; j < i; ++j) {
       
   457             const QRectF &r2 = segments.elementBounds(j);
       
   458 
       
   459             if (r1.left() > r2.right() || r2.left() > r1.right())
       
   460                 continue;
       
   461             if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
       
   462                 continue;
       
   463 
       
   464             intersections.reset();
       
   465 
       
   466             bool isBezierB = segments.bezierAt(j) != 0;
       
   467 
       
   468             if (isBezierA || isBezierB) {
       
   469                 const QBezier *bezierB;
       
   470                 if (isBezierB) {
       
   471                     bezierB = segments.bezierAt(j);
       
   472                 } else {
       
   473                     tempB = bezierFromLine(segments.lineAt(j));
       
   474                     bezierB = &tempB;
       
   475                 }
       
   476 
       
   477                 if (!bezierA) {
       
   478                     tempA = bezierFromLine(segments.lineAt(i));
       
   479                     bezierA = &tempA;
       
   480                 }
       
   481 
       
   482                 intersectBeziers(*bezierA, *bezierB, t, intersections);
       
   483             } else {
       
   484                 const QLineF lineA = segments.lineAt(i);
       
   485                 const QLineF lineB = segments.lineAt(j);
       
   486 
       
   487                 intersectLines(lineA, lineB, intersections);
       
   488             }
       
   489 
       
   490             for (int k = 0; k < intersections.size(); ++k) {
       
   491                 QPathSegments::Intersection i_isect, j_isect;
       
   492                 i_isect.vertex = j_isect.vertex = segments.addPoint(intersections.at(k).pos);
       
   493 
       
   494                 i_isect.t = intersections.at(k).alphaA;
       
   495                 j_isect.t = intersections.at(k).alphaB;
       
   496 
       
   497                 i_isect.next = 0;
       
   498                 j_isect.next = 0;
       
   499 
       
   500                 segments.addIntersection(i, i_isect);
       
   501                 segments.addIntersection(j, j_isect);
       
   502             }
       
   503         }
       
   504     }
       
   505 }
       
   506 
       
   507 class QKdPointTree
       
   508 {
       
   509 public:
       
   510     enum Traversal {
       
   511         TraverseBoth,
       
   512         TraverseLeft,
       
   513         TraverseRight,
       
   514         TraverseNone
       
   515     };
       
   516 
       
   517     struct Node {
       
   518         int point;
       
   519         int id;
       
   520 
       
   521         Node *left;
       
   522         Node *right;
       
   523     };
       
   524 
       
   525     QKdPointTree(const QPathSegments &segments)
       
   526         : m_segments(&segments)
       
   527         , m_nodes(m_segments->points())
       
   528         , m_id(0)
       
   529     {
       
   530         m_nodes.resize(m_segments->points());
       
   531 
       
   532         for (int i = 0; i < m_nodes.size(); ++i) {
       
   533             m_nodes.at(i).point = i;
       
   534             m_nodes.at(i).id = -1;
       
   535         }
       
   536 
       
   537         m_rootNode = build(0, m_nodes.size());
       
   538     }
       
   539 
       
   540     int build(int begin, int end, int depth = 0);
       
   541 
       
   542     Node *rootNode()
       
   543     {
       
   544         return &m_nodes.at(m_rootNode);
       
   545     }
       
   546 
       
   547     inline int nextId()
       
   548     {
       
   549         return m_id++;
       
   550     }
       
   551 
       
   552 private:
       
   553     const QPathSegments *m_segments;
       
   554     QDataBuffer<Node> m_nodes;
       
   555 
       
   556     int m_rootNode;
       
   557     int m_id;
       
   558 };
       
   559 
       
   560 template <typename T>
       
   561 void qTraverseKdPointTree(QKdPointTree::Node &node, T &t, int depth = 0)
       
   562 {
       
   563     QKdPointTree::Traversal status = t(node, depth);
       
   564 
       
   565     const bool traverseRight = (status == QKdPointTree::TraverseBoth || status == QKdPointTree::TraverseRight);
       
   566     const bool traverseLeft = (status == QKdPointTree::TraverseBoth || status == QKdPointTree::TraverseLeft);
       
   567 
       
   568     if (traverseLeft && node.left)
       
   569         QT_PREPEND_NAMESPACE(qTraverseKdPointTree<T>)(*node.left, t, depth + 1);
       
   570 
       
   571     if (traverseRight && node.right)
       
   572         QT_PREPEND_NAMESPACE(qTraverseKdPointTree<T>)(*node.right, t, depth + 1);
       
   573 }
       
   574 
       
   575 static inline qreal component(const QPointF &point, unsigned int i)
       
   576 {
       
   577     Q_ASSERT(i < 2);
       
   578     const qreal components[] = { point.x(), point.y() };
       
   579     return components[i];
       
   580 }
       
   581 
       
   582 int QKdPointTree::build(int begin, int end, int depth)
       
   583 {
       
   584     Q_ASSERT(end > begin);
       
   585 
       
   586     const qreal pivot = component(m_segments->pointAt(m_nodes.at(begin).point), depth & 1);
       
   587 
       
   588     int first = begin + 1;
       
   589     int last = end - 1;
       
   590 
       
   591     while (first <= last) {
       
   592         const qreal value = component(m_segments->pointAt(m_nodes.at(first).point), depth & 1);
       
   593 
       
   594         if (value < pivot)
       
   595             ++first;
       
   596         else {
       
   597             qSwap(m_nodes.at(first), m_nodes.at(last));
       
   598             --last;
       
   599         }
       
   600     }
       
   601 
       
   602     qSwap(m_nodes.at(last), m_nodes.at(begin));
       
   603 
       
   604     if (last > begin)
       
   605         m_nodes.at(last).left = &m_nodes.at(build(begin, last, depth + 1));
       
   606     else
       
   607         m_nodes.at(last).left = 0;
       
   608 
       
   609     if (last + 1 < end)
       
   610         m_nodes.at(last).right = &m_nodes.at(build(last + 1, end, depth + 1));
       
   611     else
       
   612         m_nodes.at(last).right = 0;
       
   613 
       
   614     return last;
       
   615 }
       
   616 
       
   617 class QKdPointFinder
       
   618 {
       
   619 public:
       
   620     QKdPointFinder(int point, const QPathSegments &segments, QKdPointTree &tree)
       
   621         : m_point(point)
       
   622         , m_result(-1)
       
   623         , m_segments(&segments)
       
   624         , m_tree(&tree)
       
   625     {
       
   626         pointComponents[0] = segments.pointAt(point).x();
       
   627         pointComponents[1] = segments.pointAt(point).y();
       
   628     }
       
   629 
       
   630     inline QKdPointTree::Traversal operator()(QKdPointTree::Node &node, int depth)
       
   631     {
       
   632         if (m_result != -1)
       
   633             return QKdPointTree::TraverseNone;
       
   634 
       
   635         const QPointF &nodePoint = m_segments->pointAt(node.point);
       
   636 
       
   637         const qreal pivotComponents[] = { nodePoint.x(), nodePoint.y() };
       
   638 
       
   639         const qreal pivot = pivotComponents[depth & 1];
       
   640         const qreal value = pointComponents[depth & 1];
       
   641 
       
   642         if (fuzzyIsNull(pivot - value)) {
       
   643             const qreal pivot2 = pivotComponents[(depth + 1) & 1];
       
   644             const qreal value2 = pointComponents[(depth + 1) & 1];
       
   645 
       
   646             if (fuzzyIsNull(pivot2 - value2)) {
       
   647                 if (node.id < 0)
       
   648                     node.id = m_tree->nextId();
       
   649 
       
   650                 m_result = node.id;
       
   651                 return QKdPointTree::TraverseNone;
       
   652             } else
       
   653                 return QKdPointTree::TraverseBoth;
       
   654         } else if (value < pivot) {
       
   655             return QKdPointTree::TraverseLeft;
       
   656         } else {
       
   657             return QKdPointTree::TraverseRight;
       
   658         }
       
   659     }
       
   660 
       
   661     int result() const
       
   662     {
       
   663         return m_result;
       
   664     }
       
   665 
       
   666 private:
       
   667     int m_point;
       
   668     qreal pointComponents[2];
       
   669     int m_result;
       
   670     const QPathSegments *m_segments;
       
   671     QKdPointTree *m_tree;
       
   672 };
       
   673 
       
   674 // merge all points that are within qFuzzyCompare range of each other
       
   675 void QPathSegments::mergePoints()
       
   676 {
       
   677     QKdPointTree tree(*this);
       
   678 
       
   679     if (tree.rootNode()) {
       
   680         QDataBuffer<QPointF> mergedPoints(points());
       
   681         QDataBuffer<int> pointIndices(points());
       
   682 
       
   683         for (int i = 0; i < points(); ++i) {
       
   684             QKdPointFinder finder(i, *this, tree);
       
   685             QT_PREPEND_NAMESPACE(qTraverseKdPointTree<QKdPointFinder>)(*tree.rootNode(), finder);
       
   686 
       
   687             Q_ASSERT(finder.result() != -1);
       
   688 
       
   689             if (finder.result() >= mergedPoints.size())
       
   690                 mergedPoints << m_points.at(i);
       
   691 
       
   692             pointIndices << finder.result();
       
   693         }
       
   694 
       
   695         for (int i = 0; i < m_segments.size(); ++i) {
       
   696             m_segments.at(i).va = pointIndices.at(m_segments.at(i).va);
       
   697             m_segments.at(i).vb = pointIndices.at(m_segments.at(i).vb);
       
   698         }
       
   699 
       
   700         for (int i = 0; i < m_intersections.size(); ++i)
       
   701             m_intersections.at(i).vertex = pointIndices.at(m_intersections.at(i).vertex);
       
   702 
       
   703         m_points.swap(mergedPoints);
       
   704     }
       
   705 }
       
   706 
       
   707 void QWingedEdge::intersectAndAdd()
       
   708 {
       
   709     QIntersectionFinder finder;
       
   710     finder.produceIntersections(m_segments);
       
   711 
       
   712     m_segments.mergePoints();
       
   713 
       
   714     for (int i = 0; i < m_segments.points(); ++i)
       
   715         addVertex(m_segments.pointAt(i));
       
   716 
       
   717     QDataBuffer<QPathSegments::Intersection> intersections;
       
   718     for (int i = 0; i < m_segments.segments(); ++i) {
       
   719         intersections.reset();
       
   720 
       
   721         int pathId = m_segments.pathId(i);
       
   722 
       
   723         const QPathSegments::Intersection *isect = m_segments.intersectionAt(i);
       
   724         while (isect) {
       
   725             intersections << *isect;
       
   726 
       
   727             if (isect->next) {
       
   728                 isect += isect->next;
       
   729             } else {
       
   730                 isect = 0;
       
   731             }
       
   732         }
       
   733 
       
   734         qSort(intersections.data(), intersections.data() + intersections.size());
       
   735 
       
   736         const QBezier *bezier = m_segments.bezierAt(i);
       
   737         if (bezier) {
       
   738             int first = m_segments.segmentAt(i).va;
       
   739             int second = m_segments.segmentAt(i).vb;
       
   740 
       
   741             qreal alpha = 0.0;
       
   742             int last = first;
       
   743             for (int j = 0; j < intersections.size(); ++j) {
       
   744                 const QPathSegments::Intersection &isect = intersections.at(j);
       
   745 
       
   746                 addBezierEdge(bezier, last, isect.vertex, alpha, isect.t, pathId);
       
   747 
       
   748                 alpha = isect.t;
       
   749                 last = isect.vertex;
       
   750             }
       
   751 
       
   752             addBezierEdge(bezier, last, second, alpha, 1.0, pathId);
       
   753         } else {
       
   754             int first = m_segments.segmentAt(i).va;
       
   755             int second = m_segments.segmentAt(i).vb;
       
   756 
       
   757             int last = first;
       
   758             for (int j = 0; j < intersections.size(); ++j) {
       
   759                 const QPathSegments::Intersection &isect = intersections.at(j);
       
   760 
       
   761                 QPathEdge *ep = edge(addEdge(last, isect.vertex));
       
   762 
       
   763                 if (ep) {
       
   764                     const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1;
       
   765                     if (pathId == 0)
       
   766                         ep->windingA += dir;
       
   767                     else
       
   768                         ep->windingB += dir;
       
   769                 }
       
   770 
       
   771                 last = isect.vertex;
       
   772             }
       
   773 
       
   774             QPathEdge *ep = edge(addEdge(last, second));
       
   775 
       
   776             if (ep) {
       
   777                 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(second).y() ? 1 : -1;
       
   778                 if (pathId == 0)
       
   779                     ep->windingA += dir;
       
   780                 else
       
   781                     ep->windingB += dir;
       
   782             }
       
   783         }
       
   784     }
       
   785 }
       
   786 
       
   787 QWingedEdge::QWingedEdge()
       
   788 {
       
   789 }
       
   790 
       
   791 QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip)
       
   792 {
       
   793     m_segments.setPath(subject);
       
   794     m_segments.addPath(clip);
       
   795 
       
   796     intersectAndAdd();
       
   797 }
       
   798 
       
   799 QWingedEdge::TraversalStatus QWingedEdge::next(const QWingedEdge::TraversalStatus &status) const
       
   800 {
       
   801     const QPathEdge *sp = edge(status.edge);
       
   802     Q_ASSERT(sp);
       
   803 
       
   804     TraversalStatus result;
       
   805     result.edge = sp->next(status.traversal, status.direction);
       
   806     result.traversal = status.traversal;
       
   807     result.direction = status.direction;
       
   808 
       
   809     const QPathEdge *rp = edge(result.edge);
       
   810     Q_ASSERT(rp);
       
   811 
       
   812     if (sp->vertex(status.direction) == rp->vertex(status.direction))
       
   813         result.flip();
       
   814 
       
   815     return result;
       
   816 }
       
   817 
       
   818 static bool isLine(const QBezier &bezier)
       
   819 {
       
   820     const bool equal_1_2 = comparePoints(bezier.pt1(), bezier.pt2());
       
   821     const bool equal_2_3 = comparePoints(bezier.pt2(), bezier.pt3());
       
   822     const bool equal_3_4 = comparePoints(bezier.pt3(), bezier.pt4());
       
   823 
       
   824     // point?
       
   825     if (equal_1_2 && equal_2_3 && equal_3_4)
       
   826         return true;
       
   827 
       
   828     if (comparePoints(bezier.pt1(), bezier.pt4()))
       
   829         return equal_1_2 || equal_3_4;
       
   830 
       
   831     return (equal_1_2 && equal_3_4) || (equal_1_2 && equal_2_3) || (equal_2_3 && equal_3_4);
       
   832 }
       
   833 
       
   834 void QPathSegments::setPath(const QPainterPath &path)
       
   835 {
       
   836     m_points.reset();
       
   837     m_beziers.reset();
       
   838     m_intersections.reset();
       
   839     m_segments.reset();
       
   840 
       
   841     m_pathId = 0;
       
   842 
       
   843     addPath(path);
       
   844 }
       
   845 
       
   846 void QPathSegments::addPath(const QPainterPath &path)
       
   847 {
       
   848     int firstSegment = m_segments.size();
       
   849 
       
   850     bool hasMoveTo = false;
       
   851     int lastMoveTo = 0;
       
   852     int last = 0;
       
   853     for (int i = 0; i < path.elementCount(); ++i) {
       
   854         int current = m_points.size();
       
   855 
       
   856         QPointF currentPoint;
       
   857         if (path.elementAt(i).type == QPainterPath::CurveToElement)
       
   858             currentPoint = path.elementAt(i+2);
       
   859         else
       
   860             currentPoint = path.elementAt(i);
       
   861 
       
   862         if (i > 0 && comparePoints(m_points.at(lastMoveTo), currentPoint))
       
   863             current = lastMoveTo;
       
   864         else
       
   865             m_points << currentPoint;
       
   866 
       
   867         switch (path.elementAt(i).type) {
       
   868         case QPainterPath::MoveToElement:
       
   869             if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo)))
       
   870                 m_segments << Segment(m_pathId, last, lastMoveTo);
       
   871             hasMoveTo = true;
       
   872             last = lastMoveTo = current;
       
   873             break;
       
   874         case QPainterPath::LineToElement:
       
   875             m_segments << Segment(m_pathId, last, current);
       
   876             last = current;
       
   877             break;
       
   878         case QPainterPath::CurveToElement:
       
   879             {
       
   880                 QBezier bezier = QBezier::fromPoints(m_points.at(last), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2));
       
   881                 if (isLine(bezier)) {
       
   882                     m_segments << Segment(m_pathId, last, current);
       
   883                 } else {
       
   884                     m_segments << Segment(m_pathId, last, current, m_beziers.size());
       
   885                     m_beziers << bezier;
       
   886                 }
       
   887             }
       
   888             last = current;
       
   889             i += 2;
       
   890             break;
       
   891         default:
       
   892             Q_ASSERT(false);
       
   893             break;
       
   894         }
       
   895     }
       
   896 
       
   897     if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo)))
       
   898         m_segments << Segment(m_pathId, last, lastMoveTo);
       
   899 
       
   900     for (int i = firstSegment; i < m_segments.size(); ++i) {
       
   901         const QBezier *bezier = bezierAt(i);
       
   902         if (bezier) {
       
   903             m_segments.at(i).bounds = bezier->bounds();
       
   904         } else {
       
   905             const QLineF line = lineAt(i);
       
   906 
       
   907             qreal x1 = line.p1().x();
       
   908             qreal y1 = line.p1().y();
       
   909             qreal x2 = line.p2().x();
       
   910             qreal y2 = line.p2().y();
       
   911 
       
   912             if (x2 < x1)
       
   913                 qSwap(x1, x2);
       
   914             if (y2 < y1)
       
   915                 qSwap(y1, y2);
       
   916 
       
   917             m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1);
       
   918         }
       
   919     }
       
   920 
       
   921     ++m_pathId;
       
   922 }
       
   923 
       
   924 qreal QWingedEdge::delta(int vertex, int a, int b) const
       
   925 {
       
   926     const QPathEdge *ap = edge(a);
       
   927     const QPathEdge *bp = edge(b);
       
   928 
       
   929     qreal a_angle = ap->angle;
       
   930     qreal b_angle = bp->angle;
       
   931 
       
   932     if (vertex == ap->second)
       
   933         a_angle = ap->invAngle;
       
   934 
       
   935     if (vertex == bp->second)
       
   936         b_angle = bp->invAngle;
       
   937 
       
   938     qreal result = b_angle - a_angle;
       
   939 
       
   940     if (qFuzzyIsNull(result) || qFuzzyCompare(result, 128))
       
   941         return 0;
       
   942 
       
   943     if (result < 0)
       
   944         return result + 128.;
       
   945     else
       
   946         return result;
       
   947 }
       
   948 
       
   949 static inline QPointF tangentAt(const QWingedEdge &list, int vi, int ei)
       
   950 {
       
   951     const QPathEdge *ep = list.edge(ei);
       
   952     Q_ASSERT(ep);
       
   953 
       
   954     qreal t;
       
   955     qreal sign;
       
   956 
       
   957     if (ep->first == vi) {
       
   958         t = ep->t0;
       
   959         sign = 1;
       
   960     } else {
       
   961         t = ep->t1;
       
   962         sign = -1;
       
   963     }
       
   964 
       
   965     QPointF normal;
       
   966     if (ep->bezier) {
       
   967         normal = ep->bezier->derivedAt(t);
       
   968 
       
   969         if (qFuzzyIsNull(normal.x()) && qFuzzyIsNull(normal.y()))
       
   970             normal = ep->bezier->secondDerivedAt(t);
       
   971     } else {
       
   972         const QPointF a = *list.vertex(ep->first);
       
   973         const QPointF b = *list.vertex(ep->second);
       
   974         normal = b - a;
       
   975     }
       
   976 
       
   977     return normalize(sign * normal);
       
   978 }
       
   979 
       
   980 static inline QPointF midPoint(const QWingedEdge &list, int ei)
       
   981 {
       
   982     const QPathEdge *ep = list.edge(ei);
       
   983     Q_ASSERT(ep);
       
   984 
       
   985     if (ep->bezier) {
       
   986         return ep->bezier->pointAt(0.5 * (ep->t0 + ep->t1));
       
   987     } else {
       
   988         const QPointF a = *list.vertex(ep->first);
       
   989         const QPointF b = *list.vertex(ep->second);
       
   990         return a + 0.5 * (b - a);
       
   991     }
       
   992 }
       
   993 
       
   994 static QBezier transform(const QBezier &bezier, const QPointF &xAxis, const QPointF &yAxis, const QPointF &origin)
       
   995 {
       
   996     QPointF points[4] = {
       
   997         bezier.pt1(),
       
   998         bezier.pt2(),
       
   999         bezier.pt3(),
       
  1000         bezier.pt4()
       
  1001     };
       
  1002 
       
  1003     for (int i = 0; i < 4; ++i) {
       
  1004         const QPointF p = points[i] - origin;
       
  1005 
       
  1006         points[i].rx() = dot(xAxis, p);
       
  1007         points[i].ry() = dot(yAxis, p);
       
  1008     }
       
  1009 
       
  1010     return QBezier::fromPoints(points[0], points[1], points[2], points[3]);
       
  1011 }
       
  1012 
       
  1013 static bool isLeftOf(const QWingedEdge &list, int vi, int ai, int bi)
       
  1014 {
       
  1015     const QPathEdge *ap = list.edge(ai);
       
  1016     const QPathEdge *bp = list.edge(bi);
       
  1017 
       
  1018     Q_ASSERT(ap);
       
  1019     Q_ASSERT(bp);
       
  1020 
       
  1021     if (!(ap->bezier || bp->bezier))
       
  1022         return false;
       
  1023 
       
  1024     const QPointF tangent = tangentAt(list, vi, ai);
       
  1025     const QPointF normal(tangent.y(), -tangent.x());
       
  1026 
       
  1027     const QPointF origin = *list.vertex(vi);
       
  1028 
       
  1029     const QPointF dpA = midPoint(list, ai) - origin;
       
  1030     const QPointF dpB = midPoint(list, bi) - origin;
       
  1031 
       
  1032     qreal xA = dot(normal, dpA);
       
  1033     qreal xB = dot(normal, dpB);
       
  1034 
       
  1035     if (xA <= 0 && xB >= 0)
       
  1036         return true;
       
  1037 
       
  1038     if (xA >= 0 && xB <= 0)
       
  1039         return false;
       
  1040 
       
  1041     if (!ap->bezier)
       
  1042         return xB > 0;
       
  1043 
       
  1044     if (!bp->bezier)
       
  1045         return xA < 0;
       
  1046 
       
  1047     // both are beziers on the same side of the tangent
       
  1048 
       
  1049     // transform the beziers into the local coordinate system
       
  1050     // such that positive y is along the tangent, and positive x is along the normal
       
  1051 
       
  1052     QBezier bezierA = transform(*ap->bezier, normal, tangent, origin);
       
  1053     QBezier bezierB = transform(*bp->bezier, normal, tangent, origin);
       
  1054 
       
  1055     qreal y = qMin(bezierA.pointAt(0.5 * (ap->t0 + ap->t1)).y(),
       
  1056                    bezierB.pointAt(0.5 * (bp->t0 + bp->t1)).y());
       
  1057 
       
  1058     xA = bezierA.pointAt(bezierA.tForY(ap->t0, ap->t1, y)).x();
       
  1059     xB = bezierB.pointAt(bezierB.tForY(bp->t0, bp->t1, y)).x();
       
  1060 
       
  1061     return xA < xB;
       
  1062 }
       
  1063 
       
  1064 QWingedEdge::TraversalStatus QWingedEdge::findInsertStatus(int vi, int ei) const
       
  1065 {
       
  1066     const QPathVertex *vp = vertex(vi);
       
  1067 
       
  1068     Q_ASSERT(vp);
       
  1069     Q_ASSERT(ei >= 0);
       
  1070     Q_ASSERT(vp->edge >= 0);
       
  1071 
       
  1072     int position = vp->edge;
       
  1073     qreal d = 128.;
       
  1074 
       
  1075     TraversalStatus status;
       
  1076     status.direction = edge(vp->edge)->directionTo(vi);
       
  1077     status.traversal = QPathEdge::RightTraversal;
       
  1078     status.edge = vp->edge;
       
  1079 
       
  1080 #ifdef QDEBUG_CLIPPER
       
  1081     const QPathEdge *ep = edge(ei);
       
  1082     qDebug() << "Finding insert status for edge" << ei << "at vertex" << QPointF(*vp) << ", angles: " << ep->angle << ep->invAngle;
       
  1083 #endif
       
  1084 
       
  1085     do {
       
  1086         status = next(status);
       
  1087         status.flip();
       
  1088 
       
  1089         Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi);
       
  1090 
       
  1091         qreal d2 = delta(vi, ei, status.edge);
       
  1092 
       
  1093 #ifdef QDEBUG_CLIPPER
       
  1094         const QPathEdge *op = edge(status.edge);
       
  1095         qDebug() << "Delta to edge" << status.edge << d2 << ", angles: " << op->angle << op->invAngle;
       
  1096 #endif
       
  1097 
       
  1098         if (!(qFuzzyIsNull(d2) && isLeftOf(*this, vi, status.edge, ei))
       
  1099             && (d2 < d || (qFuzzyCompare(d2, d) && isLeftOf(*this, vi, status.edge, position)))) {
       
  1100             position = status.edge;
       
  1101             d = d2;
       
  1102         }
       
  1103     } while (status.edge != vp->edge);
       
  1104 
       
  1105     status.traversal = QPathEdge::LeftTraversal;
       
  1106     status.direction = QPathEdge::Forward;
       
  1107     status.edge = position;
       
  1108 
       
  1109     if (edge(status.edge)->vertex(status.direction) != vi)
       
  1110         status.flip();
       
  1111 
       
  1112 #ifdef QDEBUG_CLIPPER
       
  1113     qDebug() << "Inserting edge" << ei << "to" << (status.traversal == QPathEdge::LeftTraversal ? "left" : "right") << "of edge" << status.edge;
       
  1114 #endif
       
  1115 
       
  1116     Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi);
       
  1117 
       
  1118     return status;
       
  1119 }
       
  1120 
       
  1121 void QWingedEdge::removeEdge(int ei)
       
  1122 {
       
  1123     QPathEdge *ep = edge(ei);
       
  1124 
       
  1125     TraversalStatus status;
       
  1126     status.direction = QPathEdge::Forward;
       
  1127     status.traversal = QPathEdge::RightTraversal;
       
  1128     status.edge = ei;
       
  1129 
       
  1130     TraversalStatus forwardRight = next(status);
       
  1131     forwardRight.flipDirection();
       
  1132 
       
  1133     status.traversal = QPathEdge::LeftTraversal;
       
  1134     TraversalStatus forwardLeft = next(status);
       
  1135     forwardLeft.flipDirection();
       
  1136 
       
  1137     status.direction = QPathEdge::Backward;
       
  1138     TraversalStatus backwardLeft = next(status);
       
  1139     backwardLeft.flipDirection();
       
  1140 
       
  1141     status.traversal = QPathEdge::RightTraversal;
       
  1142     TraversalStatus backwardRight = next(status);
       
  1143     backwardRight.flipDirection();
       
  1144 
       
  1145     edge(forwardRight.edge)->setNext(forwardRight.traversal, forwardRight.direction, forwardLeft.edge);
       
  1146     edge(forwardLeft.edge)->setNext(forwardLeft.traversal, forwardLeft.direction, forwardRight.edge);
       
  1147 
       
  1148     edge(backwardRight.edge)->setNext(backwardRight.traversal, backwardRight.direction, backwardLeft.edge);
       
  1149     edge(backwardLeft.edge)->setNext(backwardLeft.traversal, backwardLeft.direction, backwardRight.edge);
       
  1150 
       
  1151     ep->setNext(QPathEdge::Forward, ei);
       
  1152     ep->setNext(QPathEdge::Backward, ei);
       
  1153 
       
  1154     QPathVertex *a = vertex(ep->first);
       
  1155     QPathVertex *b = vertex(ep->second);
       
  1156 
       
  1157     a->edge = backwardRight.edge;
       
  1158     b->edge = forwardRight.edge;
       
  1159 }
       
  1160 
       
  1161 static int commonEdge(const QWingedEdge &list, int a, int b)
       
  1162 {
       
  1163     const QPathVertex *ap = list.vertex(a);
       
  1164     Q_ASSERT(ap);
       
  1165 
       
  1166     const QPathVertex *bp = list.vertex(b);
       
  1167     Q_ASSERT(bp);
       
  1168 
       
  1169     if (ap->edge < 0 || bp->edge < 0)
       
  1170         return -1;
       
  1171 
       
  1172     QWingedEdge::TraversalStatus status;
       
  1173     status.edge = ap->edge;
       
  1174     status.direction = list.edge(status.edge)->directionTo(a);
       
  1175     status.traversal = QPathEdge::RightTraversal;
       
  1176 
       
  1177     do {
       
  1178         const QPathEdge *ep = list.edge(status.edge);
       
  1179 
       
  1180         if ((ep->first == a && ep->second == b)
       
  1181             || (ep->first == b && ep->second == a))
       
  1182             return status.edge;
       
  1183 
       
  1184         status = list.next(status);
       
  1185         status.flip();
       
  1186     } while (status.edge != ap->edge);
       
  1187 
       
  1188     return -1;
       
  1189 }
       
  1190 
       
  1191 static qreal computeAngle(const QPointF &v)
       
  1192 {
       
  1193 #if 1
       
  1194     if (v.x() == 0) {
       
  1195         return v.y() <= 0 ? 0 : 64.;
       
  1196     } else if (v.y() == 0) {
       
  1197         return v.x() <= 0 ? 32. : 96.;
       
  1198     }
       
  1199 
       
  1200     QPointF nv = normalize(v);
       
  1201     if (nv.y() < 0) {
       
  1202         if (nv.x() < 0) { // 0 - 32
       
  1203             return -32. * nv.x();
       
  1204         } else { // 96 - 128
       
  1205             return 128. - 32. * nv.x();
       
  1206         }
       
  1207     } else { // 32 - 96
       
  1208         return 64. + 32 * nv.x();
       
  1209     }
       
  1210 #else
       
  1211     // doesn't seem to be robust enough
       
  1212     return atan2(v.x(), v.y()) + Q_PI;
       
  1213 #endif
       
  1214 }
       
  1215 
       
  1216 int QWingedEdge::addEdge(const QPointF &a, const QPointF &b, const QBezier *bezier, qreal t0, qreal t1)
       
  1217 {
       
  1218     int fi = insert(a);
       
  1219     int si = insert(b);
       
  1220 
       
  1221     return addEdge(fi, si, bezier, t0, t1);
       
  1222 }
       
  1223 
       
  1224 int QWingedEdge::addEdge(int fi, int si, const QBezier *bezier, qreal t0, qreal t1)
       
  1225 {
       
  1226     if (fi == si)
       
  1227         return -1;
       
  1228 
       
  1229     int common = commonEdge(*this, fi, si);
       
  1230     if (common >= 0)
       
  1231         return common;
       
  1232 
       
  1233     m_edges << QPathEdge(fi, si);
       
  1234 
       
  1235     int ei = m_edges.size() - 1;
       
  1236 
       
  1237     QPathVertex *fp = vertex(fi);
       
  1238     QPathVertex *sp = vertex(si);
       
  1239 
       
  1240     QPathEdge *ep = edge(ei);
       
  1241 
       
  1242     ep->bezier = bezier;
       
  1243     ep->t0 = t0;
       
  1244     ep->t1 = t1;
       
  1245 
       
  1246     if (bezier) {
       
  1247         QPointF aTangent = bezier->derivedAt(t0);
       
  1248         QPointF bTangent = -bezier->derivedAt(t1);
       
  1249 
       
  1250         if (qFuzzyIsNull(aTangent.x()) && qFuzzyIsNull(aTangent.y()))
       
  1251             aTangent = bezier->secondDerivedAt(t0);
       
  1252 
       
  1253         if (qFuzzyIsNull(bTangent.x()) && qFuzzyIsNull(bTangent.y()))
       
  1254             bTangent = bezier->secondDerivedAt(t1);
       
  1255 
       
  1256         ep->angle = computeAngle(aTangent);
       
  1257         ep->invAngle = computeAngle(bTangent);
       
  1258     } else {
       
  1259         const QPointF tangent = QPointF(*sp) - QPointF(*fp);
       
  1260         ep->angle = computeAngle(tangent);
       
  1261         ep->invAngle = ep->angle + 64;
       
  1262         if (ep->invAngle >= 128)
       
  1263             ep->invAngle -= 128;
       
  1264     }
       
  1265 
       
  1266     QPathVertex *vertices[2] = { fp, sp };
       
  1267     QPathEdge::Direction dirs[2] = { QPathEdge::Backward, QPathEdge::Forward };
       
  1268 
       
  1269 #ifdef QDEBUG_CLIPPER
       
  1270     printf("** Adding edge %d / vertices: %.07f %.07f, %.07f %.07f\n", ei, fp->x, fp->y, sp->x, sp->y);
       
  1271 #endif
       
  1272 
       
  1273     for (int i = 0; i < 2; ++i) {
       
  1274         QPathVertex *vp = vertices[i];
       
  1275         if (vp->edge < 0) {
       
  1276             vp->edge = ei;
       
  1277             ep->setNext(dirs[i], ei);
       
  1278         } else {
       
  1279             int vi = ep->vertex(dirs[i]);
       
  1280             Q_ASSERT(vertex(vi) == vertices[i]);
       
  1281 
       
  1282             TraversalStatus os = findInsertStatus(vi, ei);
       
  1283             QPathEdge *op = edge(os.edge);
       
  1284 
       
  1285             Q_ASSERT(vertex(op->vertex(os.direction)) == vertices[i]);
       
  1286 
       
  1287             TraversalStatus ns = next(os);
       
  1288             ns.flipDirection();
       
  1289             QPathEdge *np = edge(ns.edge);
       
  1290 
       
  1291             op->setNext(os.traversal, os.direction, ei);
       
  1292             np->setNext(ns.traversal, ns.direction, ei);
       
  1293 
       
  1294             int oe = os.edge;
       
  1295             int ne = ns.edge;
       
  1296 
       
  1297             os = next(os);
       
  1298             ns = next(ns);
       
  1299 
       
  1300             os.flipDirection();
       
  1301             ns.flipDirection();
       
  1302 
       
  1303             Q_ASSERT(os.edge == ei);
       
  1304             Q_ASSERT(ns.edge == ei);
       
  1305 
       
  1306             ep->setNext(os.traversal, os.direction, oe);
       
  1307             ep->setNext(ns.traversal, ns.direction, ne);
       
  1308         }
       
  1309     }
       
  1310 
       
  1311     Q_ASSERT(ep->next(QPathEdge::RightTraversal, QPathEdge::Forward) >= 0);
       
  1312     Q_ASSERT(ep->next(QPathEdge::RightTraversal, QPathEdge::Backward) >= 0);
       
  1313     Q_ASSERT(ep->next(QPathEdge::LeftTraversal, QPathEdge::Forward) >= 0);
       
  1314     Q_ASSERT(ep->next(QPathEdge::LeftTraversal, QPathEdge::Backward) >= 0);
       
  1315 
       
  1316     return ei;
       
  1317 }
       
  1318 
       
  1319 void QWingedEdge::addBezierEdge(const QBezier *bezier, int vertexA, int vertexB, qreal alphaA, qreal alphaB, int path)
       
  1320 {
       
  1321     if (qFuzzyCompare(alphaA, alphaB))
       
  1322         return;
       
  1323 
       
  1324     qreal alphaMid = (alphaA + alphaB) * 0.5;
       
  1325 
       
  1326     qreal s0 = 0;
       
  1327     qreal s1 = 1;
       
  1328     int count = bezier->stationaryYPoints(s0, s1);
       
  1329 
       
  1330     m_splitPoints.clear();
       
  1331     m_splitPoints << alphaA;
       
  1332     m_splitPoints << alphaMid;
       
  1333     m_splitPoints << alphaB;
       
  1334 
       
  1335     if (count > 0 && !qFuzzyCompare(s0, alphaA) && !qFuzzyCompare(s0, alphaMid) && !qFuzzyCompare(s0, alphaB) && s0 > alphaA && s0 < alphaB)
       
  1336         m_splitPoints << s0;
       
  1337 
       
  1338     if (count > 1 && !qFuzzyCompare(s1, alphaA) && !qFuzzyCompare(s1, alphaMid) && !qFuzzyCompare(s1, alphaB) && s1 > alphaA && s1 < alphaB)
       
  1339         m_splitPoints << s1;
       
  1340 
       
  1341     if (count > 0)
       
  1342         qSort(m_splitPoints.begin(), m_splitPoints.end());
       
  1343 
       
  1344     int last = vertexA;
       
  1345     for (int i = 0; i < m_splitPoints.size() - 1; ++i) {
       
  1346         const qreal t0 = m_splitPoints[i];
       
  1347         const qreal t1 = m_splitPoints[i+1];
       
  1348 
       
  1349         int current;
       
  1350         if ((i + 1) == (m_splitPoints.size() - 1)) {
       
  1351             current = vertexB;
       
  1352         } else {
       
  1353             current = insert(bezier->pointAt(t1));
       
  1354         }
       
  1355 
       
  1356         QPathEdge *ep = edge(addEdge(last, current, bezier, t0, t1));
       
  1357 
       
  1358         if (ep) {
       
  1359             const int dir = m_vertices.at(last).y < m_vertices.at(current).y ? 1 : -1;
       
  1360             if (path == 0)
       
  1361                 ep->windingA += dir;
       
  1362             else
       
  1363                 ep->windingB += dir;
       
  1364         }
       
  1365 
       
  1366         last = current;
       
  1367     }
       
  1368 }
       
  1369 
       
  1370 void QWingedEdge::addBezierEdge(const QBezier *bezier, const QPointF &a, const QPointF &b, qreal alphaA, qreal alphaB, int path)
       
  1371 {
       
  1372     if (qFuzzyCompare(alphaA, alphaB))
       
  1373         return;
       
  1374 
       
  1375     if (comparePoints(a, b)) {
       
  1376         int v = insert(a);
       
  1377 
       
  1378         addBezierEdge(bezier, v, v, alphaA, alphaB, path);
       
  1379     } else {
       
  1380         int va = insert(a);
       
  1381         int vb = insert(b);
       
  1382 
       
  1383         addBezierEdge(bezier, va, vb, alphaA, alphaB, path);
       
  1384     }
       
  1385 }
       
  1386 
       
  1387 int QWingedEdge::insert(const QPathVertex &vertex)
       
  1388 {
       
  1389     if (!m_vertices.isEmpty()) {
       
  1390         const QPathVertex &last = m_vertices.last();
       
  1391         if (vertex.x == last.x && vertex.y == last.y)
       
  1392             return m_vertices.size() - 1;
       
  1393 
       
  1394         for (int i = 0; i < m_vertices.size(); ++i) {
       
  1395             const QPathVertex &v = m_vertices.at(i);
       
  1396             if (qFuzzyCompare(v.x, vertex.x) && qFuzzyCompare(v.y, vertex.y)) {
       
  1397                 return i;
       
  1398             }
       
  1399         }
       
  1400     }
       
  1401 
       
  1402     m_vertices << vertex;
       
  1403     return m_vertices.size() - 1;
       
  1404 }
       
  1405 
       
  1406 static void addLineTo(QPainterPath &path, const QPointF &point)
       
  1407 {
       
  1408     const int elementCount = path.elementCount();
       
  1409     if (elementCount >= 2) {
       
  1410         const QPainterPath::Element &middle = path.elementAt(elementCount - 1);
       
  1411         if (middle.type == QPainterPath::LineToElement) {
       
  1412             const QPointF first = path.elementAt(elementCount - 2);
       
  1413             const QPointF d1 = point - first;
       
  1414             const QPointF d2 = middle - first;
       
  1415 
       
  1416             const QPointF p(-d1.y(), d1.x());
       
  1417 
       
  1418             if (qFuzzyIsNull(dot(p, d2))) {
       
  1419                 path.setElementPositionAt(elementCount - 1, point.x(), point.y());
       
  1420                 return;
       
  1421             }
       
  1422         }
       
  1423     }
       
  1424 
       
  1425     path.lineTo(point);
       
  1426 }
       
  1427 
       
  1428 static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
       
  1429 {
       
  1430     QWingedEdge::TraversalStatus status;
       
  1431     status.edge = edge;
       
  1432     status.traversal = traversal;
       
  1433     status.direction = QPathEdge::Forward;
       
  1434 
       
  1435     const QBezier *bezier = 0;
       
  1436     qreal t0 = 1;
       
  1437     qreal t1 = 0;
       
  1438     bool forward = true;
       
  1439 
       
  1440     path.moveTo(*list.vertex(list.edge(edge)->first));
       
  1441 
       
  1442     do {
       
  1443         const QPathEdge *ep = list.edge(status.edge);
       
  1444 
       
  1445         if (ep->bezier != bezier || (bezier && t0 != ep->t1 && t1 != ep->t0)) {
       
  1446             if (bezier) {
       
  1447                 QBezier sub = bezier->bezierOnInterval(t0, t1);
       
  1448 
       
  1449                 if (forward)
       
  1450                     path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4());
       
  1451                 else
       
  1452                     path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1());
       
  1453             }
       
  1454 
       
  1455             bezier = ep->bezier;
       
  1456             t0 = 1;
       
  1457             t1 = 0;
       
  1458             forward = status.direction == QPathEdge::Forward;
       
  1459         }
       
  1460 
       
  1461         if (ep->bezier) {
       
  1462             t0 = qMin(t0, ep->t0);
       
  1463             t1 = qMax(t1, ep->t1);
       
  1464         } else
       
  1465             addLineTo(path, *list.vertex(ep->vertex(status.direction)));
       
  1466 
       
  1467         if (status.traversal == QPathEdge::LeftTraversal)
       
  1468             ep->flag &= ~16;
       
  1469         else
       
  1470             ep->flag &= ~32;
       
  1471 
       
  1472         status = list.next(status);
       
  1473     } while (status.edge != edge);
       
  1474 
       
  1475     if (bezier) {
       
  1476         QBezier sub = bezier->bezierOnInterval(t0, t1);
       
  1477         if (forward)
       
  1478             path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4());
       
  1479         else
       
  1480             path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1());
       
  1481     }
       
  1482 }
       
  1483 
       
  1484 void QWingedEdge::simplify()
       
  1485 {
       
  1486     for (int i = 0; i < edgeCount(); ++i) {
       
  1487         const QPathEdge *ep = edge(i);
       
  1488 
       
  1489         // if both sides are part of the inside then we can collapse the edge
       
  1490         int flag = 0x3 << 4;
       
  1491         if ((ep->flag & flag) == flag) {
       
  1492             removeEdge(i);
       
  1493 
       
  1494             ep->flag &= ~flag;
       
  1495         }
       
  1496     }
       
  1497 }
       
  1498 
       
  1499 QPainterPath QWingedEdge::toPath() const
       
  1500 {
       
  1501     QPainterPath path;
       
  1502 
       
  1503     for (int i = 0; i < edgeCount(); ++i) {
       
  1504         const QPathEdge *ep = edge(i);
       
  1505 
       
  1506         if (ep->flag & 16) {
       
  1507             add(path, *this, i, QPathEdge::LeftTraversal);
       
  1508         }
       
  1509 
       
  1510         if (ep->flag & 32)
       
  1511             add(path, *this, i, QPathEdge::RightTraversal);
       
  1512     }
       
  1513 
       
  1514     return path;
       
  1515 }
       
  1516 
       
  1517 bool QPathClipper::intersect()
       
  1518 {
       
  1519     if (subjectPath == clipPath)
       
  1520         return true;
       
  1521 
       
  1522     QRectF r1 = subjectPath.controlPointRect();
       
  1523     QRectF r2 = clipPath.controlPointRect();
       
  1524     if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||
       
  1525         qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {
       
  1526         // no way we could intersect
       
  1527         return false;
       
  1528     }
       
  1529 
       
  1530     bool subjectIsRect = pathToRect(subjectPath);
       
  1531     bool clipIsRect = pathToRect(clipPath);
       
  1532 
       
  1533     if (subjectIsRect && clipIsRect)
       
  1534         return true;
       
  1535     else if (subjectIsRect)
       
  1536         return clipPath.intersects(r1);
       
  1537     else if (clipIsRect)
       
  1538         return subjectPath.intersects(r2);
       
  1539 
       
  1540     QPathSegments a;
       
  1541     a.setPath(subjectPath);
       
  1542     QPathSegments b;
       
  1543     b.setPath(clipPath);
       
  1544 
       
  1545     QIntersectionFinder finder;
       
  1546     if (finder.hasIntersections(a, b))
       
  1547         return true;
       
  1548 
       
  1549     for (int i = 0; i < clipPath.elementCount(); ++i) {
       
  1550         if (clipPath.elementAt(i).type == QPainterPath::MoveToElement) {
       
  1551             const QPointF point = clipPath.elementAt(i);
       
  1552             if (r1.contains(point) && subjectPath.contains(point))
       
  1553                 return true;
       
  1554         }
       
  1555     }
       
  1556 
       
  1557     for (int i = 0; i < subjectPath.elementCount(); ++i) {
       
  1558         if (subjectPath.elementAt(i).type == QPainterPath::MoveToElement) {
       
  1559             const QPointF point = subjectPath.elementAt(i);
       
  1560             if (r2.contains(point) && clipPath.contains(point))
       
  1561                 return true;
       
  1562         }
       
  1563     }
       
  1564 
       
  1565     return false;
       
  1566 }
       
  1567 
       
  1568 bool QPathClipper::contains()
       
  1569 {
       
  1570     if (subjectPath == clipPath)
       
  1571         return false;
       
  1572 
       
  1573     QRectF r1 = subjectPath.controlPointRect();
       
  1574     QRectF r2 = clipPath.controlPointRect();
       
  1575     if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||
       
  1576         qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {
       
  1577         // no intersection -> not contained
       
  1578         return false;
       
  1579     }
       
  1580 
       
  1581     bool clipIsRect = pathToRect(clipPath);
       
  1582     if (clipIsRect)
       
  1583         return subjectPath.contains(r2);
       
  1584 
       
  1585     QPathSegments a;
       
  1586     a.setPath(subjectPath);
       
  1587     QPathSegments b;
       
  1588     b.setPath(clipPath);
       
  1589 
       
  1590     QIntersectionFinder finder;
       
  1591     if (finder.hasIntersections(a, b))
       
  1592         return false;
       
  1593 
       
  1594     for (int i = 0; i < clipPath.elementCount(); ++i) {
       
  1595         if (clipPath.elementAt(i).type == QPainterPath::MoveToElement) {
       
  1596             const QPointF point = clipPath.elementAt(i);
       
  1597             if (!r1.contains(point) || !subjectPath.contains(point))
       
  1598                 return false;
       
  1599         }
       
  1600     }
       
  1601 
       
  1602     return true;
       
  1603 }
       
  1604 
       
  1605 QPathClipper::QPathClipper(const QPainterPath &subject,
       
  1606                            const QPainterPath &clip)
       
  1607     : subjectPath(subject)
       
  1608     , clipPath(clip)
       
  1609 {
       
  1610     aMask = subjectPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;
       
  1611     bMask = clipPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;
       
  1612 }
       
  1613 
       
  1614 template <typename Iterator, typename Equality>
       
  1615 Iterator qRemoveDuplicates(Iterator begin, Iterator end, Equality eq)
       
  1616 {
       
  1617     if (begin == end)
       
  1618         return end;
       
  1619 
       
  1620     Iterator last = begin;
       
  1621     ++begin;
       
  1622     Iterator insert = begin;
       
  1623     for (Iterator it = begin; it != end; ++it) {
       
  1624         if (!eq(*it, *last)) {
       
  1625             *insert++ = *it;
       
  1626             last = it;
       
  1627         }
       
  1628     }
       
  1629 
       
  1630     return insert;
       
  1631 }
       
  1632 
       
  1633 static void clear(QWingedEdge& list, int edge, QPathEdge::Traversal traversal)
       
  1634 {
       
  1635     QWingedEdge::TraversalStatus status;
       
  1636     status.edge = edge;
       
  1637     status.traversal = traversal;
       
  1638     status.direction = QPathEdge::Forward;
       
  1639 
       
  1640     do {
       
  1641         if (status.traversal == QPathEdge::LeftTraversal)
       
  1642             list.edge(status.edge)->flag |= 1;
       
  1643         else
       
  1644             list.edge(status.edge)->flag |= 2;
       
  1645 
       
  1646         status = list.next(status);
       
  1647     } while (status.edge != edge);
       
  1648 }
       
  1649 
       
  1650 template <typename InputIterator>
       
  1651 InputIterator qFuzzyFind(InputIterator first, InputIterator last, qreal val)
       
  1652 {
       
  1653     while (first != last && !qFuzzyCompare(qreal(*first), qreal(val)))
       
  1654         ++first;
       
  1655     return first;
       
  1656 }
       
  1657 
       
  1658 static bool fuzzyCompare(qreal a, qreal b)
       
  1659 {
       
  1660     return qFuzzyCompare(a, b);
       
  1661 }
       
  1662 
       
  1663 static bool pathToRect(const QPainterPath &path, QRectF *rect)
       
  1664 {
       
  1665     if (path.elementCount() != 5)
       
  1666         return false;
       
  1667 
       
  1668     const bool mightBeRect = path.elementAt(0).isMoveTo()
       
  1669         && path.elementAt(1).isLineTo()
       
  1670         && path.elementAt(2).isLineTo()
       
  1671         && path.elementAt(3).isLineTo()
       
  1672         && path.elementAt(4).isLineTo();
       
  1673 
       
  1674     if (!mightBeRect)
       
  1675         return false;
       
  1676 
       
  1677     const qreal x1 = path.elementAt(0).x;
       
  1678     const qreal y1 = path.elementAt(0).y;
       
  1679 
       
  1680     const qreal x2 = path.elementAt(1).x;
       
  1681     const qreal y2 = path.elementAt(2).y;
       
  1682 
       
  1683     if (path.elementAt(1).y != y1)
       
  1684         return false;
       
  1685 
       
  1686     if (path.elementAt(2).x != x2)
       
  1687         return false;
       
  1688 
       
  1689     if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)
       
  1690         return false;
       
  1691 
       
  1692     if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)
       
  1693         return false;
       
  1694 
       
  1695     if (rect)
       
  1696         *rect = QRectF(QPointF(x1, y1), QPointF(x2, y2));
       
  1697 
       
  1698     return true;
       
  1699 }
       
  1700 
       
  1701 
       
  1702 QPainterPath QPathClipper::clip(Operation operation)
       
  1703 {
       
  1704     op = operation;
       
  1705 
       
  1706     if (op != Simplify) {
       
  1707         if (subjectPath == clipPath)
       
  1708             return op == BoolSub ? QPainterPath() : subjectPath;
       
  1709 
       
  1710         const QRectF clipBounds = clipPath.boundingRect();
       
  1711         const QRectF subjectBounds = subjectPath.boundingRect();
       
  1712 
       
  1713         if (!clipBounds.intersects(subjectBounds)) {
       
  1714             switch (op) {
       
  1715             case BoolSub:
       
  1716                 return subjectPath;
       
  1717             case BoolAnd:
       
  1718                 return QPainterPath();
       
  1719             case BoolOr: {
       
  1720                 QPainterPath result = subjectPath;
       
  1721                 if (result.fillRule() == clipPath.fillRule()) {
       
  1722                     result.addPath(clipPath);
       
  1723                 } else if (result.fillRule() == Qt::WindingFill) {
       
  1724                     result = result.simplified();
       
  1725                     result.addPath(clipPath);
       
  1726                 } else {
       
  1727                     result.addPath(clipPath.simplified());
       
  1728                 }
       
  1729                 return result;
       
  1730              }
       
  1731             default:
       
  1732                 break;
       
  1733             }
       
  1734         }
       
  1735 
       
  1736         if (clipBounds.contains(subjectBounds)) {
       
  1737             QRectF clipRect;
       
  1738             if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) {
       
  1739                 switch (op) {
       
  1740                 case BoolSub:
       
  1741                     return QPainterPath();
       
  1742                 case BoolAnd:
       
  1743                     return subjectPath;
       
  1744                 case BoolOr:
       
  1745                     return clipPath;
       
  1746                 default:
       
  1747                     break;
       
  1748                 }
       
  1749             }
       
  1750         } else if (subjectBounds.contains(clipBounds)) {
       
  1751             QRectF subjectRect;
       
  1752             if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) {
       
  1753                 switch (op) {
       
  1754                 case BoolSub:
       
  1755                     if (clipPath.fillRule() == Qt::OddEvenFill) {
       
  1756                         QPainterPath result = clipPath;
       
  1757                         result.addRect(subjectRect);
       
  1758                         return result;
       
  1759                     } else {
       
  1760                         QPainterPath result = clipPath.simplified();
       
  1761                         result.addRect(subjectRect);
       
  1762                         return result;
       
  1763                     }
       
  1764                     break;
       
  1765                 case BoolAnd:
       
  1766                     return clipPath;
       
  1767                 case BoolOr:
       
  1768                     return subjectPath;
       
  1769                 default:
       
  1770                     break;
       
  1771                 }
       
  1772             }
       
  1773         }
       
  1774     }
       
  1775 
       
  1776     QWingedEdge list(subjectPath, clipPath);
       
  1777 
       
  1778     doClip(list, ClipMode);
       
  1779 
       
  1780     QPainterPath path = list.toPath();
       
  1781     return path;
       
  1782 }
       
  1783 
       
  1784 bool QPathClipper::doClip(QWingedEdge &list, ClipperMode mode)
       
  1785 {
       
  1786     QVector<qreal> y_coords;
       
  1787     y_coords.reserve(list.vertexCount());
       
  1788     for (int i = 0; i < list.vertexCount(); ++i)
       
  1789         y_coords << list.vertex(i)->y;
       
  1790 
       
  1791     qSort(y_coords.begin(), y_coords.end());
       
  1792     y_coords.resize(qRemoveDuplicates(y_coords.begin(), y_coords.end(), fuzzyCompare) - y_coords.begin());
       
  1793 
       
  1794 #ifdef QDEBUG_CLIPPER
       
  1795     printf("sorted y coords:\n");
       
  1796     for (int i = 0; i < y_coords.size(); ++i) {
       
  1797         printf("%.9f\n", y_coords[i]);
       
  1798     }
       
  1799 #endif
       
  1800 
       
  1801     bool found;
       
  1802     do {
       
  1803         found = false;
       
  1804         int index = 0;
       
  1805         qreal maxHeight = 0;
       
  1806         for (int i = 0; i < list.edgeCount(); ++i) {
       
  1807             QPathEdge *edge = list.edge(i);
       
  1808 
       
  1809             // have both sides of this edge already been handled?
       
  1810             if ((edge->flag & 0x3) == 0x3)
       
  1811                 continue;
       
  1812 
       
  1813             QPathVertex *a = list.vertex(edge->first);
       
  1814             QPathVertex *b = list.vertex(edge->second);
       
  1815 
       
  1816             if (qFuzzyCompare(a->y, b->y))
       
  1817                 continue;
       
  1818 
       
  1819             found = true;
       
  1820 
       
  1821             qreal height = qAbs(a->y - b->y);
       
  1822             if (height > maxHeight) {
       
  1823                 index = i;
       
  1824                 maxHeight = height;
       
  1825             }
       
  1826         }
       
  1827 
       
  1828         if (found) {
       
  1829             QPathEdge *edge = list.edge(index);
       
  1830 
       
  1831             QPathVertex *a = list.vertex(edge->first);
       
  1832             QPathVertex *b = list.vertex(edge->second);
       
  1833 
       
  1834             // FIXME: this can be optimized by using binary search
       
  1835             const int first = qFuzzyFind(y_coords.begin(), y_coords.end(), qMin(a->y, b->y)) - y_coords.begin();
       
  1836             const int last = qFuzzyFind(y_coords.begin() + first, y_coords.end(), qMax(a->y, b->y)) - y_coords.begin();
       
  1837 
       
  1838             Q_ASSERT(first < y_coords.size() - 1);
       
  1839             Q_ASSERT(last < y_coords.size());
       
  1840 
       
  1841             qreal bestY = 0.5 * (y_coords[first] + y_coords[first+1]);
       
  1842             qreal biggestGap = y_coords[first+1] - y_coords[first];
       
  1843 
       
  1844             for (int i = first + 1; i < last; ++i) {
       
  1845                 qreal gap = y_coords[i+1] - y_coords[i];
       
  1846 
       
  1847                 if (gap > biggestGap) {
       
  1848                     bestY = 0.5 * (y_coords[i] + y_coords[i+1]);
       
  1849                     biggestGap = gap;
       
  1850                 }
       
  1851             }
       
  1852 
       
  1853 #ifdef QDEBUG_CLIPPER
       
  1854             printf("y: %.9f, gap: %.9f\n", bestY, biggestGap);
       
  1855 #endif
       
  1856 
       
  1857             if (handleCrossingEdges(list, bestY, mode) && mode == CheckMode)
       
  1858                 return true;
       
  1859 
       
  1860             edge->flag |= 0x3;
       
  1861         }
       
  1862     } while (found);
       
  1863 
       
  1864     if (mode == ClipMode)
       
  1865         list.simplify();
       
  1866 
       
  1867     return false;
       
  1868 }
       
  1869 
       
  1870 static void traverse(QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
       
  1871 {
       
  1872     QWingedEdge::TraversalStatus status;
       
  1873     status.edge = edge;
       
  1874     status.traversal = traversal;
       
  1875     status.direction = QPathEdge::Forward;
       
  1876 
       
  1877     do {
       
  1878         int flag = status.traversal == QPathEdge::LeftTraversal ? 1 : 2;
       
  1879 
       
  1880         QPathEdge *ep = list.edge(status.edge);
       
  1881 
       
  1882         ep->flag |= (flag | (flag << 4));
       
  1883 
       
  1884 #ifdef QDEBUG_CLIPPER
       
  1885         qDebug() << "traverse: adding edge " << status.edge << ", mask:" << (flag << 4) <<ep->flag;
       
  1886 #endif
       
  1887 
       
  1888         status = list.next(status);
       
  1889     } while (status.edge != edge);
       
  1890 }
       
  1891 
       
  1892 struct QCrossingEdge
       
  1893 {
       
  1894     int edge;
       
  1895     qreal x;
       
  1896 
       
  1897     bool operator<(const QCrossingEdge &edge) const
       
  1898     {
       
  1899         return x < edge.x;
       
  1900     }
       
  1901 };
       
  1902 
       
  1903 static bool bool_op(bool a, bool b, QPathClipper::Operation op)
       
  1904 {
       
  1905     switch (op) {
       
  1906     case QPathClipper::BoolAnd:
       
  1907         return a && b;
       
  1908     case QPathClipper::BoolOr: // fall-through
       
  1909     case QPathClipper::Simplify:
       
  1910         return a || b;
       
  1911     case QPathClipper::BoolSub:
       
  1912         return a && !b;
       
  1913     default:
       
  1914         Q_ASSERT(false);
       
  1915         return false;
       
  1916     }
       
  1917 }
       
  1918 
       
  1919 bool QWingedEdge::isInside(qreal x, qreal y) const
       
  1920 {
       
  1921     int winding = 0;
       
  1922     for (int i = 0; i < edgeCount(); ++i) {
       
  1923         const QPathEdge *ep = edge(i);
       
  1924 
       
  1925         // left xor right
       
  1926         int w = ((ep->flag >> 4) ^ (ep->flag >> 5)) & 1;
       
  1927 
       
  1928         if (!w)
       
  1929             continue;
       
  1930 
       
  1931         QPointF a = *vertex(ep->first);
       
  1932         QPointF b = *vertex(ep->second);
       
  1933 
       
  1934         if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {
       
  1935             if (ep->bezier) {
       
  1936                 qreal maxX = qMax(a.x(), qMax(b.x(), qMax(ep->bezier->x2, ep->bezier->x3)));
       
  1937                 qreal minX = qMin(a.x(), qMin(b.x(), qMin(ep->bezier->x2, ep->bezier->x3)));
       
  1938 
       
  1939                 if (minX > x) {
       
  1940                     winding += w;
       
  1941                 } else if (maxX > x) {
       
  1942                     const qreal t = ep->bezier->tForY(ep->t0, ep->t1, y);
       
  1943                     const qreal intersection = ep->bezier->pointAt(t).x();
       
  1944 
       
  1945                     if (intersection > x)
       
  1946                         winding += w;
       
  1947                 }
       
  1948             } else {
       
  1949                 qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
       
  1950 
       
  1951                 if (intersectionX > x)
       
  1952                     winding += w;
       
  1953             }
       
  1954         }
       
  1955     }
       
  1956 
       
  1957     return winding & 1;
       
  1958 }
       
  1959 
       
  1960 static QVector<QCrossingEdge> findCrossings(const QWingedEdge &list, qreal y)
       
  1961 {
       
  1962     QVector<QCrossingEdge> crossings;
       
  1963     for (int i = 0; i < list.edgeCount(); ++i) {
       
  1964         const QPathEdge *edge = list.edge(i);
       
  1965         QPointF a = *list.vertex(edge->first);
       
  1966         QPointF b = *list.vertex(edge->second);
       
  1967 
       
  1968         if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {
       
  1969             if (edge->bezier) {
       
  1970                 const qreal t = edge->bezier->tForY(edge->t0, edge->t1, y);
       
  1971                 const qreal intersection = edge->bezier->pointAt(t).x();
       
  1972 
       
  1973                 const QCrossingEdge edge = { i, intersection };
       
  1974                 crossings << edge;
       
  1975             } else {
       
  1976                 const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
       
  1977                 const QCrossingEdge edge = { i, intersection };
       
  1978                 crossings << edge;
       
  1979             }
       
  1980         }
       
  1981     }
       
  1982     return crossings;
       
  1983 }
       
  1984 
       
  1985 bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode)
       
  1986 {
       
  1987     QVector<QCrossingEdge> crossings = findCrossings(list, y);
       
  1988 
       
  1989     Q_ASSERT(!crossings.isEmpty());
       
  1990     qSort(crossings.begin(), crossings.end());
       
  1991 
       
  1992     int windingA = 0;
       
  1993     int windingB = 0;
       
  1994 
       
  1995     int windingD = 0;
       
  1996 
       
  1997 #ifdef QDEBUG_CLIPPER
       
  1998     qDebug() << "crossings:" << crossings.size();
       
  1999 #endif
       
  2000     for (int i = 0; i < crossings.size() - 1; ++i) {
       
  2001         int ei = crossings.at(i).edge;
       
  2002         const QPathEdge *edge = list.edge(ei);
       
  2003 
       
  2004         windingA += edge->windingA;
       
  2005         windingB += edge->windingB;
       
  2006 
       
  2007         const bool hasLeft = (edge->flag >> 4) & 1;
       
  2008         const bool hasRight = (edge->flag >> 4) & 2;
       
  2009 
       
  2010         windingD += hasLeft ^ hasRight;
       
  2011 
       
  2012         const bool inA = (windingA & aMask) != 0;
       
  2013         const bool inB = (windingB & bMask) != 0;
       
  2014         const bool inD = (windingD & 0x1) != 0;
       
  2015 
       
  2016         const bool inside = bool_op(inA, inB, op);
       
  2017         const bool add = inD ^ inside;
       
  2018 
       
  2019 #ifdef QDEBUG_CLIPPER
       
  2020         printf("y %f, x %f, inA: %d, inB: %d, inD: %d, inside: %d, flag: %x, bezier: %p, edge: %d\n", y, crossings.at(i).x, inA, inB, inD, inside, edge->flag, edge->bezier, ei);
       
  2021 #endif
       
  2022 
       
  2023         if (add) {
       
  2024             if (mode == CheckMode)
       
  2025                 return true;
       
  2026 
       
  2027             qreal y0 = list.vertex(edge->first)->y;
       
  2028             qreal y1 = list.vertex(edge->second)->y;
       
  2029 
       
  2030             if (y0 < y1) {
       
  2031                 if (!(edge->flag & 1))
       
  2032                     traverse(list, ei, QPathEdge::LeftTraversal);
       
  2033 
       
  2034                 if (!(edge->flag & 2))
       
  2035                     clear(list, ei, QPathEdge::RightTraversal);
       
  2036             } else {
       
  2037                 if (!(edge->flag & 1))
       
  2038                     clear(list, ei, QPathEdge::LeftTraversal);
       
  2039 
       
  2040                 if (!(edge->flag & 2))
       
  2041                     traverse(list, ei, QPathEdge::RightTraversal);
       
  2042             }
       
  2043 
       
  2044             ++windingD;
       
  2045         } else {
       
  2046             if (!(edge->flag & 1))
       
  2047                 clear(list, ei, QPathEdge::LeftTraversal);
       
  2048 
       
  2049             if (!(edge->flag & 2))
       
  2050                 clear(list, ei, QPathEdge::RightTraversal);
       
  2051         }
       
  2052     }
       
  2053 
       
  2054     return false;
       
  2055 }
       
  2056 
       
  2057 QT_END_NAMESPACE