Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/painting/qpathclipper.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4444#include <private/qbezier_p.h>
    4545#include <private/qdatabuffer_p.h>
     46#include <private/qnumeric_p.h>
    4647#include <qmath.h>
    4748
     
    8687}
    8788
    88 static QPointF normalize(const QPointF &p)
    89 {
    90     return p / qSqrt(p.x() * p.x() + p.y() * p.y());
     89static void normalize(double &x, double &y)
     90{
     91    double reciprocal = 1 / qSqrt(x * x + y * y);
     92    x *= reciprocal;
     93    y *= reciprocal;
    9194}
    9295
     
    106109
    107110private:
    108     void intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections);
    109     void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);
    110 
    111     bool beziersIntersect(const QBezier &one, const QBezier &two) const;
    112111    bool linesIntersect(const QLineF &a, const QLineF &b) const;
    113112};
    114 
    115 bool QIntersectionFinder::beziersIntersect(const QBezier &one, const QBezier &two) const
    116 {
    117     return (comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2())
    118             && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4()))
    119            || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3())
    120                && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))
    121            || QBezier::findIntersections(one, two, 0);
    122 }
    123113
    124114bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const
     
    175165    }
    176166
    177     // if the lines are not parallel and share a common end point, then they
    178     // don't intersect
    179     if (p1_equals_q1 || p1_equals_q2 || p2_equals_q1 || p2_equals_q2)
    180         return false;
    181 
    182167    const qreal invPar = 1 / par;
    183168
     
    194179}
    195180
    196 void QIntersectionFinder::intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections)
    197 {
    198     if ((comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2())
    199          && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4()))
    200         || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3())
    201             && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))) {
    202 
    203         return;
    204     }
    205 
    206     t.clear();
    207 
    208     if (!QBezier::findIntersections(one, two, &t))
    209         return;
    210 
    211     int count = t.size();
    212 
    213     for (int i = 0; i < count; ++i) {
    214         qreal alpha_p = t.at(i).first;
    215         qreal alpha_q = t.at(i).second;
    216 
    217         QPointF pt;
    218         if (qFuzzyIsNull(alpha_p)) {
    219             pt = one.pt1();
    220         } else if (qFuzzyIsNull(alpha_p - 1)) {
    221             pt = one.pt4();
    222         } else if (qFuzzyIsNull(alpha_q)) {
    223             pt = two.pt1();
    224         } else if (qFuzzyIsNull(alpha_q - 1)) {
    225             pt = two.pt4();
     181bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const
     182{
     183    if (a.segments() == 0 || b.segments() == 0)
     184        return false;
     185
     186    const QRectF &rb0 = b.elementBounds(0);
     187
     188    qreal minX = rb0.left();
     189    qreal minY = rb0.top();
     190    qreal maxX = rb0.right();
     191    qreal maxY = rb0.bottom();
     192
     193    for (int i = 1; i < b.segments(); ++i) {
     194        const QRectF &r = b.elementBounds(i);
     195        minX = qMin(minX, r.left());
     196        minY = qMin(minY, r.top());
     197        maxX = qMax(maxX, r.right());
     198        maxY = qMax(maxY, r.bottom());
     199    }
     200
     201    QRectF rb(minX, minY, maxX - minX, maxY - minY);
     202
     203    for (int i = 0; i < a.segments(); ++i) {
     204        const QRectF &r1 = a.elementBounds(i);
     205
     206        if (r1.left() > rb.right() || rb.left() > r1.right())
     207            continue;
     208        if (r1.top() > rb.bottom() || rb.top() > r1.bottom())
     209            continue;
     210
     211        for (int j = 0; j < b.segments(); ++j) {
     212            const QRectF &r2 = b.elementBounds(j);
     213
     214            if (r1.left() > r2.right() || r2.left() > r1.right())
     215                continue;
     216            if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
     217                continue;
     218
     219            if (linesIntersect(a.lineAt(i), b.lineAt(j)))
     220                return true;
     221        }
     222    }
     223
     224    return false;
     225}
     226
     227namespace {
     228struct TreeNode
     229{
     230    qreal splitLeft;
     231    qreal splitRight;
     232    bool leaf;
     233
     234    int lowestLeftIndex;
     235    int lowestRightIndex;
     236
     237    union {
     238        struct {
     239            int first;
     240            int last;
     241        } interval;
     242        struct {
     243            int left;
     244            int right;
     245        } children;
     246    } index;
     247};
     248
     249struct RectF
     250{
     251    qreal x1;
     252    qreal y1;
     253    qreal x2;
     254    qreal y2;
     255};
     256
     257class SegmentTree
     258{
     259public:
     260    SegmentTree(QPathSegments &segments);
     261
     262    QRectF boundingRect() const;
     263
     264    void produceIntersections(int segment);
     265
     266private:
     267    TreeNode buildTree(int first, int last, int depth, const RectF &bounds);
     268
     269    void produceIntersectionsLeaf(const TreeNode &node, int segment);
     270    void produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis);
     271    void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);
     272
     273    QPathSegments &m_segments;
     274    QVector<int> m_index;
     275
     276    RectF m_bounds;
     277
     278    QVector<TreeNode> m_tree;
     279    QDataBuffer<QIntersection> m_intersections;
     280};
     281
     282SegmentTree::SegmentTree(QPathSegments &segments)
     283    : m_segments(segments),
     284      m_intersections(0)
     285{
     286    m_bounds.x1 = qt_inf();
     287    m_bounds.y1 = qt_inf();
     288    m_bounds.x2 = -qt_inf();
     289    m_bounds.y2 = -qt_inf();
     290
     291    m_index.resize(m_segments.segments());
     292
     293    for (int i = 0; i < m_index.size(); ++i) {
     294        m_index[i] = i;
     295
     296        const QRectF &segmentBounds = m_segments.elementBounds(i);
     297
     298        if (segmentBounds.left() < m_bounds.x1)
     299            m_bounds.x1 = segmentBounds.left();
     300        if (segmentBounds.top() < m_bounds.y1)
     301            m_bounds.y1 = segmentBounds.top();
     302        if (segmentBounds.right() > m_bounds.x2)
     303            m_bounds.x2 = segmentBounds.right();
     304        if (segmentBounds.bottom() > m_bounds.y2)
     305            m_bounds.y2 = segmentBounds.bottom();
     306    }
     307
     308    m_tree.resize(1);
     309
     310    TreeNode root = buildTree(0, m_index.size(), 0, m_bounds);
     311    m_tree[0] = root;
     312}
     313
     314QRectF SegmentTree::boundingRect() const
     315{
     316    return QRectF(QPointF(m_bounds.x1, m_bounds.y1),
     317                  QPointF(m_bounds.x2, m_bounds.y2));
     318}
     319
     320static inline qreal coordinate(const QPointF &pos, int axis)
     321{
     322    return axis == 0 ? pos.x() : pos.y();
     323}
     324
     325TreeNode SegmentTree::buildTree(int first, int last, int depth, const RectF &bounds)
     326{
     327    if (depth >= 24 || (last - first) <= 10) {
     328        TreeNode node;
     329        node.leaf = true;
     330        node.index.interval.first = first;
     331        node.index.interval.last = last;
     332
     333        return node;
     334    }
     335
     336    int splitAxis = (depth & 1);
     337
     338    TreeNode node;
     339    node.leaf = false;
     340
     341    qreal split = 0.5f * ((&bounds.x1)[splitAxis] + (&bounds.x2)[splitAxis]);
     342
     343    node.splitLeft = (&bounds.x1)[splitAxis];
     344    node.splitRight = (&bounds.x2)[splitAxis];
     345
     346    node.lowestLeftIndex = INT_MAX;
     347    node.lowestRightIndex = INT_MAX;
     348
     349    const int treeSize = m_tree.size();
     350
     351    node.index.children.left = treeSize;
     352    node.index.children.right = treeSize + 1;
     353
     354    m_tree.resize(treeSize + 2);
     355
     356    int l = first;
     357    int r = last - 1;
     358
     359    // partition into left and right sets
     360    while (l <= r) {
     361        const int index = m_index.at(l);
     362        const QRectF &segmentBounds = m_segments.elementBounds(index);
     363
     364        qreal lowCoordinate = coordinate(segmentBounds.topLeft(), splitAxis);
     365
     366        if (coordinate(segmentBounds.center(), splitAxis) < split) {
     367            qreal highCoordinate = coordinate(segmentBounds.bottomRight(), splitAxis);
     368            if (highCoordinate > node.splitLeft)
     369                node.splitLeft = highCoordinate;
     370            if (index < node.lowestLeftIndex)
     371                node.lowestLeftIndex = index;
     372            ++l;
    226373        } else {
    227             pt = one.pointAt(alpha_p);
    228         }
    229 
    230         QIntersection intersection;
    231         intersection.alphaA = alpha_p;
    232         intersection.alphaB = alpha_q;
    233         intersection.pos = pt;
    234         intersections.add(intersection);
    235     }
    236 }
    237 
    238 void QIntersectionFinder::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections)
     374            if (lowCoordinate < node.splitRight)
     375                node.splitRight = lowCoordinate;
     376            if (index < node.lowestRightIndex)
     377                node.lowestRightIndex = index;
     378            qSwap(m_index[l], m_index[r]);
     379            --r;
     380        }
     381    }
     382
     383    RectF lbounds = bounds;
     384    (&lbounds.x2)[splitAxis] = node.splitLeft;
     385
     386    RectF rbounds = bounds;
     387    (&rbounds.x1)[splitAxis] = node.splitRight;
     388
     389    TreeNode left = buildTree(first, l, depth + 1, lbounds);
     390    m_tree[node.index.children.left] = left;
     391
     392    TreeNode right = buildTree(l, last, depth + 1, rbounds);
     393    m_tree[node.index.children.right] = right;
     394
     395    return node;
     396}
     397
     398void SegmentTree::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections)
    239399{
    240400    const QPointF p1 = a.p1();
     
    358518}
    359519
    360 static const QBezier bezierFromLine(const QLineF &line)
    361 {
    362     const QPointF p1 = line.p1();
    363     const QPointF p2 = line.p2();
    364     const QPointF delta = (p2 - p1) / 3;
    365     return QBezier::fromPoints(p1, p1 + delta, p1 + 2 * delta, p2);
    366 }
    367 
    368 bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const
    369 {
    370     QBezier tempA;
    371     QBezier tempB;
    372 
    373     if (a.segments() == 0 || b.segments() == 0)
    374         return false;
    375 
    376     const QRectF &rb0 = b.elementBounds(0);
    377 
    378     qreal minX = rb0.left();
    379     qreal minY = rb0.top();
    380     qreal maxX = rb0.right();
    381     qreal maxY = rb0.bottom();
    382 
    383     for (int i = 1; i < b.segments(); ++i) {
    384         const QRectF &r = b.elementBounds(i);
    385         minX = qMin(minX, r.left());
    386         minY = qMin(minY, r.top());
    387         maxX = qMax(maxX, r.right());
    388         maxY = qMax(maxY, r.bottom());
    389     }
    390 
    391     QRectF rb(minX, minY, maxX - minX, maxY - minY);
    392 
    393     for (int i = 0; i < a.segments(); ++i) {
    394         const QBezier *bezierA = a.bezierAt(i);
    395         bool isBezierA = bezierA != 0;
    396 
    397         const QRectF &r1 = a.elementBounds(i);
    398 
    399         if (r1.left() > rb.right() || rb.left() > r1.right())
     520void SegmentTree::produceIntersections(int segment)
     521{
     522    const QRectF &segmentBounds = m_segments.elementBounds(segment);
     523
     524    RectF sbounds;
     525    sbounds.x1 = segmentBounds.left();
     526    sbounds.y1 = segmentBounds.top();
     527    sbounds.x2 = segmentBounds.right();
     528    sbounds.y2 = segmentBounds.bottom();
     529
     530    produceIntersections(m_tree.at(0), segment, sbounds, m_bounds, 0);
     531}
     532
     533void SegmentTree::produceIntersectionsLeaf(const TreeNode &node, int segment)
     534{
     535    const QRectF &r1 = m_segments.elementBounds(segment);
     536    const QLineF lineA = m_segments.lineAt(segment);
     537
     538    for (int i = node.index.interval.first; i < node.index.interval.last; ++i) {
     539        const int other = m_index.at(i);
     540        if (other >= segment)
    400541            continue;
    401         if (r1.top() > rb.bottom() || rb.top() > r1.bottom())
     542
     543        const QRectF &r2 = m_segments.elementBounds(other);
     544
     545        if (r1.left() > r2.right() || r2.left() > r1.right())
    402546            continue;
    403 
    404         for (int j = 0; j < b.segments(); ++j) {
    405             const QRectF &r2 = b.elementBounds(j);
    406 
    407             if (r1.left() > r2.right() || r2.left() > r1.right())
    408                 continue;
    409             if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
    410                 continue;
    411 
    412             bool isBezierB = b.bezierAt(j) != 0;
    413 
    414             if (isBezierA || isBezierB) {
    415                 const QBezier *bezierB;
    416                 if (isBezierB) {
    417                     bezierB = b.bezierAt(j);
    418                 } else {
    419                     tempB = bezierFromLine(b.lineAt(j));
    420                     bezierB = &tempB;
    421                 }
    422 
    423                 if (!bezierA) {
    424                     tempA = bezierFromLine(a.lineAt(i));
    425                     bezierA = &tempA;
    426                 }
    427 
    428                 if (beziersIntersect(*bezierA, *bezierB))
    429                     return true;
    430             } else {
    431                 if (linesIntersect(a.lineAt(i), b.lineAt(j)))
    432                     return true;
    433             }
    434         }
    435     }
    436 
    437     return false;
     547        if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
     548            continue;
     549
     550        m_intersections.reset();
     551
     552        const QLineF lineB = m_segments.lineAt(other);
     553
     554        intersectLines(lineA, lineB, m_intersections);
     555
     556        for (int k = 0; k < m_intersections.size(); ++k) {
     557            QPathSegments::Intersection i_isect, j_isect;
     558            i_isect.vertex = j_isect.vertex = m_segments.addPoint(m_intersections.at(k).pos);
     559
     560            i_isect.t = m_intersections.at(k).alphaA;
     561            j_isect.t = m_intersections.at(k).alphaB;
     562
     563            i_isect.next = 0;
     564            j_isect.next = 0;
     565
     566            m_segments.addIntersection(segment, i_isect);
     567            m_segments.addIntersection(other, j_isect);
     568        }
     569    }
     570}
     571
     572void SegmentTree::produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis)
     573{
     574    if (node.leaf) {
     575        produceIntersectionsLeaf(node, segment);
     576        return;
     577    }
     578
     579    RectF lbounds = nodeBounds;
     580    (&lbounds.x2)[axis] = node.splitLeft;
     581
     582    RectF rbounds = nodeBounds;
     583    (&rbounds.x1)[axis] = node.splitRight;
     584
     585    if (segment > node.lowestLeftIndex && (&segmentBounds.x1)[axis] <= node.splitLeft)
     586        produceIntersections(m_tree.at(node.index.children.left), segment, segmentBounds, lbounds, !axis);
     587
     588    if (segment > node.lowestRightIndex && (&segmentBounds.x2)[axis] >= node.splitRight)
     589        produceIntersections(m_tree.at(node.index.children.right), segment, segmentBounds, rbounds, !axis);
     590}
     591
    438592}
    439593
    440594void QIntersectionFinder::produceIntersections(QPathSegments &segments)
    441595{
    442     QBezier tempA;
    443     QBezier tempB;
    444 
    445     QVector<QPair<qreal, qreal> > t;
    446     QDataBuffer<QIntersection> intersections;
    447 
    448     for (int i = 0; i < segments.segments(); ++i) {
    449         const QBezier *bezierA = segments.bezierAt(i);
    450         bool isBezierA = bezierA != 0;
    451 
    452         const QRectF &r1 = segments.elementBounds(i);
    453 
    454         for (int j = 0; j < i; ++j) {
    455             const QRectF &r2 = segments.elementBounds(j);
    456 
    457             if (r1.left() > r2.right() || r2.left() > r1.right())
    458                 continue;
    459             if (r1.top() > r2.bottom() || r2.top() > r1.bottom())
    460                 continue;
    461 
    462             intersections.reset();
    463 
    464             bool isBezierB = segments.bezierAt(j) != 0;
    465 
    466             if (isBezierA || isBezierB) {
    467                 const QBezier *bezierB;
    468                 if (isBezierB) {
    469                     bezierB = segments.bezierAt(j);
    470                 } else {
    471                     tempB = bezierFromLine(segments.lineAt(j));
    472                     bezierB = &tempB;
    473                 }
    474 
    475                 if (!bezierA) {
    476                     tempA = bezierFromLine(segments.lineAt(i));
    477                     bezierA = &tempA;
    478                 }
    479 
    480                 intersectBeziers(*bezierA, *bezierB, t, intersections);
    481             } else {
    482                 const QLineF lineA = segments.lineAt(i);
    483                 const QLineF lineB = segments.lineAt(j);
    484 
    485                 intersectLines(lineA, lineB, intersections);
    486             }
    487 
    488             for (int k = 0; k < intersections.size(); ++k) {
    489                 QPathSegments::Intersection i_isect, j_isect;
    490                 i_isect.vertex = j_isect.vertex = segments.addPoint(intersections.at(k).pos);
    491 
    492                 i_isect.t = intersections.at(k).alphaA;
    493                 j_isect.t = intersections.at(k).alphaB;
    494 
    495                 i_isect.next = 0;
    496                 j_isect.next = 0;
    497 
    498                 segments.addIntersection(i, i_isect);
    499                 segments.addIntersection(j, j_isect);
    500             }
    501         }
    502     }
     596    SegmentTree tree(segments);
     597
     598    for (int i = 0; i < segments.segments(); ++i)
     599        tree.produceIntersections(i);
    503600}
    504601
     
    713810        addVertex(m_segments.pointAt(i));
    714811
    715     QDataBuffer<QPathSegments::Intersection> intersections;
     812    QDataBuffer<QPathSegments::Intersection> intersections(m_segments.segments());
    716813    for (int i = 0; i < m_segments.segments(); ++i) {
    717814        intersections.reset();
     
    732829        qSort(intersections.data(), intersections.data() + intersections.size());
    733830
    734         const QBezier *bezier = m_segments.bezierAt(i);
    735         if (bezier) {
    736             int first = m_segments.segmentAt(i).va;
    737             int second = m_segments.segmentAt(i).vb;
    738 
    739             qreal alpha = 0.0;
    740             int last = first;
    741             for (int j = 0; j < intersections.size(); ++j) {
    742                 const QPathSegments::Intersection &isect = intersections.at(j);
    743 
    744                 addBezierEdge(bezier, last, isect.vertex, alpha, isect.t, pathId);
    745 
    746                 alpha = isect.t;
    747                 last = isect.vertex;
    748             }
    749 
    750             addBezierEdge(bezier, last, second, alpha, 1.0, pathId);
    751         } else {
    752             int first = m_segments.segmentAt(i).va;
    753             int second = m_segments.segmentAt(i).vb;
    754 
    755             int last = first;
    756             for (int j = 0; j < intersections.size(); ++j) {
    757                 const QPathSegments::Intersection &isect = intersections.at(j);
    758 
    759                 QPathEdge *ep = edge(addEdge(last, isect.vertex));
    760 
    761                 if (ep) {
    762                     const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1;
    763                     if (pathId == 0)
    764                         ep->windingA += dir;
    765                     else
    766                         ep->windingB += dir;
    767                 }
    768 
    769                 last = isect.vertex;
    770             }
    771 
    772             QPathEdge *ep = edge(addEdge(last, second));
     831        int first = m_segments.segmentAt(i).va;
     832        int second = m_segments.segmentAt(i).vb;
     833
     834        int last = first;
     835        for (int j = 0; j < intersections.size(); ++j) {
     836            const QPathSegments::Intersection &isect = intersections.at(j);
     837
     838            QPathEdge *ep = edge(addEdge(last, isect.vertex));
    773839
    774840            if (ep) {
    775                 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(second).y() ? 1 : -1;
     841                const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1;
    776842                if (pathId == 0)
    777843                    ep->windingA += dir;
     
    779845                    ep->windingB += dir;
    780846            }
    781         }
    782     }
    783 }
    784 
    785 QWingedEdge::QWingedEdge()
    786 {
    787 }
    788 
    789 QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip)
     847
     848            last = isect.vertex;
     849        }
     850
     851        QPathEdge *ep = edge(addEdge(last, second));
     852
     853        if (ep) {
     854            const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(second).y() ? 1 : -1;
     855            if (pathId == 0)
     856                ep->windingA += dir;
     857            else
     858                ep->windingB += dir;
     859        }
     860    }
     861}
     862
     863QWingedEdge::QWingedEdge() :
     864    m_edges(0),
     865    m_vertices(0),
     866    m_segments(0)
     867{
     868}
     869
     870QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip) :
     871    m_edges(subject.elementCount()),
     872    m_vertices(subject.elementCount()),
     873    m_segments(subject.elementCount())
    790874{
    791875    m_segments.setPath(subject);
     
    833917{
    834918    m_points.reset();
    835     m_beziers.reset();
    836919    m_intersections.reset();
    837920    m_segments.reset();
     
    880963                    m_segments << Segment(m_pathId, last, current);
    881964                } else {
    882                     m_segments << Segment(m_pathId, last, current, m_beziers.size());
    883                     m_beziers << bezier;
     965                    QRectF bounds = bezier.bounds();
     966
     967                    // threshold based on similar algorithm as in qtriangulatingstroker.cpp
     968                    int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * (2 * qreal(3.14) / 6));
     969
     970                    if (threshold < 3) threshold = 3;
     971                    qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1);
     972
     973                    for (int t = 1; t < threshold - 1; ++t) {
     974                        currentPoint = bezier.pointAt(t * one_over_threshold_minus_1);
     975
     976                        int index = m_points.size();
     977                        m_segments << Segment(m_pathId, last, index);
     978                        last = index;
     979
     980                        m_points << currentPoint;
     981                    }
     982
     983                    m_segments << Segment(m_pathId, last, current);
    884984                }
    885985            }
     
    897997
    898998    for (int i = firstSegment; i < m_segments.size(); ++i) {
    899         const QBezier *bezier = bezierAt(i);
    900         if (bezier) {
    901             m_segments.at(i).bounds = bezier->bounds();
    902         } else {
    903             const QLineF line = lineAt(i);
    904 
    905             qreal x1 = line.p1().x();
    906             qreal y1 = line.p1().y();
    907             qreal x2 = line.p2().x();
    908             qreal y2 = line.p2().y();
    909 
    910             if (x2 < x1)
    911                 qSwap(x1, x2);
    912             if (y2 < y1)
    913                 qSwap(y1, y2);
    914 
    915             m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1);
    916         }
     999        const QLineF line = lineAt(i);
     1000
     1001        qreal x1 = line.p1().x();
     1002        qreal y1 = line.p1().y();
     1003        qreal x2 = line.p2().x();
     1004        qreal y2 = line.p2().y();
     1005
     1006        if (x2 < x1)
     1007            qSwap(x1, x2);
     1008        if (y2 < y1)
     1009            qSwap(y1, y2);
     1010
     1011        m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1);
    9171012    }
    9181013
     
    9251020    const QPathEdge *bp = edge(b);
    9261021
    927     qreal a_angle = ap->angle;
    928     qreal b_angle = bp->angle;
     1022    double a_angle = ap->angle;
     1023    double b_angle = bp->angle;
    9291024
    9301025    if (vertex == ap->second)
     
    9341029        b_angle = bp->invAngle;
    9351030
    936     qreal result = b_angle - a_angle;
    937 
    938     if (qFuzzyIsNull(result) || qFuzzyCompare(result, 128))
    939         return 0;
    940 
    941     if (result < 0)
     1031    double result = b_angle - a_angle;
     1032
     1033    if (result >= 128.)
     1034        return result - 128.;
     1035    else if (result < 0)
    9421036        return result + 128.;
    9431037    else
     
    9451039}
    9461040
    947 static inline QPointF tangentAt(const QWingedEdge &list, int vi, int ei)
     1041static inline QPointF midPoint(const QWingedEdge &list, int ei)
    9481042{
    9491043    const QPathEdge *ep = list.edge(ei);
    9501044    Q_ASSERT(ep);
    9511045
    952     qreal t;
    953     qreal sign;
    954 
    955     if (ep->first == vi) {
    956         t = ep->t0;
    957         sign = 1;
    958     } else {
    959         t = ep->t1;
    960         sign = -1;
    961     }
    962 
    963     QPointF normal;
    964     if (ep->bezier) {
    965         normal = ep->bezier->derivedAt(t);
    966 
    967         if (qFuzzyIsNull(normal.x()) && qFuzzyIsNull(normal.y()))
    968             normal = ep->bezier->secondDerivedAt(t);
    969     } else {
    970         const QPointF a = *list.vertex(ep->first);
    971         const QPointF b = *list.vertex(ep->second);
    972         normal = b - a;
    973     }
    974 
    975     return normalize(sign * normal);
    976 }
    977 
    978 static inline QPointF midPoint(const QWingedEdge &list, int ei)
    979 {
    980     const QPathEdge *ep = list.edge(ei);
    981     Q_ASSERT(ep);
    982 
    983     if (ep->bezier) {
    984         return ep->bezier->pointAt(0.5 * (ep->t0 + ep->t1));
    985     } else {
    986         const QPointF a = *list.vertex(ep->first);
    987         const QPointF b = *list.vertex(ep->second);
    988         return a + 0.5 * (b - a);
    989     }
    990 }
    991 
    992 static QBezier transform(const QBezier &bezier, const QPointF &xAxis, const QPointF &yAxis, const QPointF &origin)
    993 {
    994     QPointF points[4] = {
    995         bezier.pt1(),
    996         bezier.pt2(),
    997         bezier.pt3(),
    998         bezier.pt4()
    999     };
    1000 
    1001     for (int i = 0; i < 4; ++i) {
    1002         const QPointF p = points[i] - origin;
    1003 
    1004         points[i].rx() = dot(xAxis, p);
    1005         points[i].ry() = dot(yAxis, p);
    1006     }
    1007 
    1008     return QBezier::fromPoints(points[0], points[1], points[2], points[3]);
    1009 }
    1010 
    1011 static bool isLeftOf(const QWingedEdge &list, int vi, int ai, int bi)
    1012 {
    1013     const QPathEdge *ap = list.edge(ai);
    1014     const QPathEdge *bp = list.edge(bi);
    1015 
    1016     Q_ASSERT(ap);
    1017     Q_ASSERT(bp);
    1018 
    1019     if (!(ap->bezier || bp->bezier))
    1020         return false;
    1021 
    1022     const QPointF tangent = tangentAt(list, vi, ai);
    1023     const QPointF normal(tangent.y(), -tangent.x());
    1024 
    1025     const QPointF origin = *list.vertex(vi);
    1026 
    1027     const QPointF dpA = midPoint(list, ai) - origin;
    1028     const QPointF dpB = midPoint(list, bi) - origin;
    1029 
    1030     qreal xA = dot(normal, dpA);
    1031     qreal xB = dot(normal, dpB);
    1032 
    1033     if (xA <= 0 && xB >= 0)
    1034         return true;
    1035 
    1036     if (xA >= 0 && xB <= 0)
    1037         return false;
    1038 
    1039     if (!ap->bezier)
    1040         return xB > 0;
    1041 
    1042     if (!bp->bezier)
    1043         return xA < 0;
    1044 
    1045     // both are beziers on the same side of the tangent
    1046 
    1047     // transform the beziers into the local coordinate system
    1048     // such that positive y is along the tangent, and positive x is along the normal
    1049 
    1050     QBezier bezierA = transform(*ap->bezier, normal, tangent, origin);
    1051     QBezier bezierB = transform(*bp->bezier, normal, tangent, origin);
    1052 
    1053     qreal y = qMin(bezierA.pointAt(0.5 * (ap->t0 + ap->t1)).y(),
    1054                    bezierB.pointAt(0.5 * (bp->t0 + bp->t1)).y());
    1055 
    1056     xA = bezierA.pointAt(bezierA.tForY(ap->t0, ap->t1, y)).x();
    1057     xB = bezierB.pointAt(bezierB.tForY(bp->t0, bp->t1, y)).x();
    1058 
    1059     return xA < xB;
     1046    const QPointF a = *list.vertex(ep->first);
     1047    const QPointF b = *list.vertex(ep->second);
     1048    return a + 0.5 * (b - a);
    10601049}
    10611050
     
    10861075
    10871076        Q_ASSERT(edge(status.edge)->vertex(status.direction) == vi);
    1088 
    10891077        qreal d2 = delta(vi, ei, status.edge);
    10901078
     
    10941082#endif
    10951083
    1096         if (!(qFuzzyIsNull(d2) && isLeftOf(*this, vi, status.edge, ei))
    1097             && (d2 < d || (qFuzzyCompare(d2, d) && isLeftOf(*this, vi, status.edge, position)))) {
     1084        if (d2 < d) {
    10981085            position = status.edge;
    10991086            d = d2;
     
    11871174}
    11881175
    1189 static qreal computeAngle(const QPointF &v)
     1176static double computeAngle(const QPointF &v)
    11901177{
    11911178#if 1
     
    11961183    }
    11971184
    1198     QPointF nv = normalize(v);
    1199     if (nv.y() < 0) {
    1200         if (nv.x() < 0) { // 0 - 32
    1201             return -32. * nv.x();
     1185    double vx = v.x();
     1186    double vy = v.y();
     1187    normalize(vx, vy);
     1188    if (vy < 0) {
     1189        if (vx < 0) { // 0 - 32
     1190            return -32. * vx;
    12021191        } else { // 96 - 128
    1203             return 128. - 32. * nv.x();
     1192            return 128. - 32. * vx;
    12041193        }
    12051194    } else { // 32 - 96
    1206         return 64. + 32 * nv.x();
     1195        return 64. + 32. * vx;
    12071196    }
    12081197#else
     
    12121201}
    12131202
    1214 int QWingedEdge::addEdge(const QPointF &a, const QPointF &b, const QBezier *bezier, qreal t0, qreal t1)
     1203int QWingedEdge::addEdge(const QPointF &a, const QPointF &b)
    12151204{
    12161205    int fi = insert(a);
    12171206    int si = insert(b);
    12181207
    1219     return addEdge(fi, si, bezier, t0, t1);
    1220 }
    1221 
    1222 int QWingedEdge::addEdge(int fi, int si, const QBezier *bezier, qreal t0, qreal t1)
     1208    return addEdge(fi, si);
     1209}
     1210
     1211int QWingedEdge::addEdge(int fi, int si)
    12231212{
    12241213    if (fi == si)
     
    12381227    QPathEdge *ep = edge(ei);
    12391228
    1240     ep->bezier = bezier;
    1241     ep->t0 = t0;
    1242     ep->t1 = t1;
    1243 
    1244     if (bezier) {
    1245         QPointF aTangent = bezier->derivedAt(t0);
    1246         QPointF bTangent = -bezier->derivedAt(t1);
    1247 
    1248         if (qFuzzyIsNull(aTangent.x()) && qFuzzyIsNull(aTangent.y()))
    1249             aTangent = bezier->secondDerivedAt(t0);
    1250 
    1251         if (qFuzzyIsNull(bTangent.x()) && qFuzzyIsNull(bTangent.y()))
    1252             bTangent = bezier->secondDerivedAt(t1);
    1253 
    1254         ep->angle = computeAngle(aTangent);
    1255         ep->invAngle = computeAngle(bTangent);
    1256     } else {
    1257         const QPointF tangent = QPointF(*sp) - QPointF(*fp);
    1258         ep->angle = computeAngle(tangent);
    1259         ep->invAngle = ep->angle + 64;
    1260         if (ep->invAngle >= 128)
    1261             ep->invAngle -= 128;
    1262     }
     1229    const QPointF tangent = QPointF(*sp) - QPointF(*fp);
     1230    ep->angle = computeAngle(tangent);
     1231    ep->invAngle = ep->angle + 64;
     1232    if (ep->invAngle >= 128)
     1233        ep->invAngle -= 128;
    12631234
    12641235    QPathVertex *vertices[2] = { fp, sp };
     
    13151286}
    13161287
    1317 void QWingedEdge::addBezierEdge(const QBezier *bezier, int vertexA, int vertexB, qreal alphaA, qreal alphaB, int path)
    1318 {
    1319     if (qFuzzyCompare(alphaA, alphaB))
    1320         return;
    1321 
    1322     qreal alphaMid = (alphaA + alphaB) * 0.5;
    1323 
    1324     qreal s0 = 0;
    1325     qreal s1 = 1;
    1326     int count = bezier->stationaryYPoints(s0, s1);
    1327 
    1328     m_splitPoints.clear();
    1329     m_splitPoints << alphaA;
    1330     m_splitPoints << alphaMid;
    1331     m_splitPoints << alphaB;
    1332 
    1333     if (count > 0 && !qFuzzyCompare(s0, alphaA) && !qFuzzyCompare(s0, alphaMid) && !qFuzzyCompare(s0, alphaB) && s0 > alphaA && s0 < alphaB)
    1334         m_splitPoints << s0;
    1335 
    1336     if (count > 1 && !qFuzzyCompare(s1, alphaA) && !qFuzzyCompare(s1, alphaMid) && !qFuzzyCompare(s1, alphaB) && s1 > alphaA && s1 < alphaB)
    1337         m_splitPoints << s1;
    1338 
    1339     if (count > 0)
    1340         qSort(m_splitPoints.begin(), m_splitPoints.end());
    1341 
    1342     int last = vertexA;
    1343     for (int i = 0; i < m_splitPoints.size() - 1; ++i) {
    1344         const qreal t0 = m_splitPoints[i];
    1345         const qreal t1 = m_splitPoints[i+1];
    1346 
    1347         int current;
    1348         if ((i + 1) == (m_splitPoints.size() - 1)) {
    1349             current = vertexB;
    1350         } else {
    1351             current = insert(bezier->pointAt(t1));
    1352         }
    1353 
    1354         QPathEdge *ep = edge(addEdge(last, current, bezier, t0, t1));
    1355 
    1356         if (ep) {
    1357             const int dir = m_vertices.at(last).y < m_vertices.at(current).y ? 1 : -1;
    1358             if (path == 0)
    1359                 ep->windingA += dir;
    1360             else
    1361                 ep->windingB += dir;
    1362         }
    1363 
    1364         last = current;
    1365     }
    1366 }
    1367 
    1368 void QWingedEdge::addBezierEdge(const QBezier *bezier, const QPointF &a, const QPointF &b, qreal alphaA, qreal alphaB, int path)
    1369 {
    1370     if (qFuzzyCompare(alphaA, alphaB))
    1371         return;
    1372 
    1373     if (comparePoints(a, b)) {
    1374         int v = insert(a);
    1375 
    1376         addBezierEdge(bezier, v, v, alphaA, alphaB, path);
    1377     } else {
    1378         int va = insert(a);
    1379         int vb = insert(b);
    1380 
    1381         addBezierEdge(bezier, va, vb, alphaA, alphaB, path);
    1382     }
    1383 }
    1384 
    13851288int QWingedEdge::insert(const QPathVertex &vertex)
    13861289{
     
    14311334    status.direction = QPathEdge::Forward;
    14321335
    1433     const QBezier *bezier = 0;
    1434     qreal t0 = 1;
    1435     qreal t1 = 0;
    1436     bool forward = true;
    1437 
    14381336    path.moveTo(*list.vertex(list.edge(edge)->first));
    14391337
     
    14411339        const QPathEdge *ep = list.edge(status.edge);
    14421340
    1443         if (ep->bezier != bezier || (bezier && t0 != ep->t1 && t1 != ep->t0)) {
    1444             if (bezier) {
    1445                 QBezier sub = bezier->bezierOnInterval(t0, t1);
    1446 
    1447                 if (forward)
    1448                     path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4());
    1449                 else
    1450                     path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1());
    1451             }
    1452 
    1453             bezier = ep->bezier;
    1454             t0 = 1;
    1455             t1 = 0;
    1456             forward = status.direction == QPathEdge::Forward;
    1457         }
    1458 
    1459         if (ep->bezier) {
    1460             t0 = qMin(t0, ep->t0);
    1461             t1 = qMax(t1, ep->t1);
    1462         } else
    1463             addLineTo(path, *list.vertex(ep->vertex(status.direction)));
     1341        addLineTo(path, *list.vertex(ep->vertex(status.direction)));
    14641342
    14651343        if (status.traversal == QPathEdge::LeftTraversal)
     
    14701348        status = list.next(status);
    14711349    } while (status.edge != edge);
    1472 
    1473     if (bezier) {
    1474         QBezier sub = bezier->bezierOnInterval(t0, t1);
    1475         if (forward)
    1476             path.cubicTo(sub.pt2(), sub.pt3(), sub.pt4());
    1477         else
    1478             path.cubicTo(sub.pt3(), sub.pt2(), sub.pt1());
    1479     }
    14801350}
    14811351
     
    15361406        return subjectPath.intersects(r2);
    15371407
    1538     QPathSegments a;
     1408    QPathSegments a(subjectPath.elementCount());
    15391409    a.setPath(subjectPath);
    1540     QPathSegments b;
     1410    QPathSegments b(clipPath.elementCount());
    15411411    b.setPath(clipPath);
    15421412
     
    15811451        return subjectPath.contains(r2);
    15821452
    1583     QPathSegments a;
     1453    QPathSegments a(subjectPath.elementCount());
    15841454    a.setPath(subjectPath);
    1585     QPathSegments b;
     1455    QPathSegments b(clipPath.elementCount());
    15861456    b.setPath(clipPath);
    15871457
     
    17051575        if (subjectPath == clipPath)
    17061576            return op == BoolSub ? QPainterPath() : subjectPath;
     1577
     1578        bool subjectIsRect = pathToRect(subjectPath, 0);
     1579        bool clipIsRect = pathToRect(clipPath, 0);
    17071580
    17081581        const QRectF clipBounds = clipPath.boundingRect();
     
    17331606
    17341607        if (clipBounds.contains(subjectBounds)) {
    1735             QRectF clipRect;
    1736             if (pathToRect(clipPath, &clipRect) && clipRect.contains(subjectBounds)) {
     1608            if (clipIsRect) {
    17371609                switch (op) {
    17381610                case BoolSub:
     
    17471619            }
    17481620        } else if (subjectBounds.contains(clipBounds)) {
    1749             QRectF subjectRect;
    1750             if (pathToRect(subjectPath, &subjectRect) && subjectRect.contains(clipBounds)) {
     1621            if (subjectIsRect) {
    17511622                switch (op) {
    17521623                case BoolSub:
    17531624                    if (clipPath.fillRule() == Qt::OddEvenFill) {
    17541625                        QPainterPath result = clipPath;
    1755                         result.addRect(subjectRect);
     1626                        result.addRect(subjectBounds);
    17561627                        return result;
    17571628                    } else {
    17581629                        QPainterPath result = clipPath.simplified();
    1759                         result.addRect(subjectRect);
     1630                        result.addRect(subjectBounds);
    17601631                        return result;
    17611632                    }
     
    17701641            }
    17711642        }
     1643
     1644        if (op == BoolAnd) {
     1645            if (subjectIsRect)
     1646                return intersect(clipPath, subjectBounds);
     1647            else if (clipIsRect)
     1648                return intersect(subjectPath, clipBounds);
     1649        }
    17721650    }
    17731651
     
    19311809
    19321810        if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {
    1933             if (ep->bezier) {
    1934                 qreal maxX = qMax(a.x(), qMax(b.x(), qMax(ep->bezier->x2, ep->bezier->x3)));
    1935                 qreal minX = qMin(a.x(), qMin(b.x(), qMin(ep->bezier->x2, ep->bezier->x3)));
    1936 
    1937                 if (minX > x) {
    1938                     winding += w;
    1939                 } else if (maxX > x) {
    1940                     const qreal t = ep->bezier->tForY(ep->t0, ep->t1, y);
    1941                     const qreal intersection = ep->bezier->pointAt(t).x();
    1942 
    1943                     if (intersection > x)
    1944                         winding += w;
    1945                 }
    1946             } else {
    1947                 qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
    1948 
    1949                 if (intersectionX > x)
    1950                     winding += w;
    1951             }
     1811            qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
     1812
     1813            if (intersectionX > x)
     1814                winding += w;
    19521815        }
    19531816    }
     
    19651828
    19661829        if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {
    1967             if (edge->bezier) {
    1968                 const qreal t = edge->bezier->tForY(edge->t0, edge->t1, y);
    1969                 const qreal intersection = edge->bezier->pointAt(t).x();
    1970 
    1971                 const QCrossingEdge edge = { i, intersection };
    1972                 crossings << edge;
    1973             } else {
    1974                 const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
    1975                 const QCrossingEdge edge = { i, intersection };
    1976                 crossings << edge;
    1977             }
     1830            const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());
     1831            const QCrossingEdge edge = { i, intersection };
     1832            crossings << edge;
    19781833        }
    19791834    }
     
    20531908}
    20541909
     1910namespace {
     1911
     1912QList<QPainterPath> toSubpaths(const QPainterPath &path)
     1913{
     1914
     1915    QList<QPainterPath> subpaths;
     1916    if (path.isEmpty())
     1917        return subpaths;
     1918
     1919    QPainterPath current;
     1920    for (int i = 0; i < path.elementCount(); ++i) {
     1921        const QPainterPath::Element &e = path.elementAt(i);
     1922        switch (e.type) {
     1923        case QPainterPath::MoveToElement:
     1924            if (current.elementCount() > 1)
     1925                subpaths += current;
     1926            current = QPainterPath();
     1927            current.moveTo(e);
     1928            break;
     1929        case QPainterPath::LineToElement:
     1930            current.lineTo(e);
     1931            break;
     1932        case QPainterPath::CurveToElement: {
     1933            current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2));
     1934            i+=2;
     1935            break;
     1936        }
     1937        case QPainterPath::CurveToDataElement:
     1938            Q_ASSERT(!"toSubpaths(), bad element type");
     1939            break;
     1940        }
     1941    }
     1942
     1943    if (current.elementCount() > 1)
     1944        subpaths << current;
     1945
     1946    return subpaths;
     1947}
     1948
     1949enum Edge
     1950{
     1951    Left, Top, Right, Bottom
     1952};
     1953
     1954static bool isVertical(Edge edge)
     1955{
     1956    return edge == Left || edge == Right;
     1957}
     1958
     1959template <Edge edge>
     1960bool compare(const QPointF &p, qreal t)
     1961{
     1962    switch (edge)
     1963    {
     1964    case Left:
     1965        return p.x() < t;
     1966    case Right:
     1967        return p.x() > t;
     1968    case Top:
     1969        return p.y() < t;
     1970    default:
     1971        return p.y() > t;
     1972    }
     1973}
     1974
     1975template <Edge edge>
     1976QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t)
     1977{
     1978    QLineF line(a, b);
     1979    switch (edge) {
     1980    case Left: // fall-through
     1981    case Right:
     1982        return line.pointAt((t - a.x()) / (b.x() - a.x()));
     1983    default:
     1984        return line.pointAt((t - a.y()) / (b.y() - a.y()));
     1985    }
     1986}
     1987
     1988void addLine(QPainterPath &path, const QLineF &line)
     1989{
     1990    if (path.elementCount() > 0)
     1991        path.lineTo(line.p1());
     1992    else
     1993        path.moveTo(line.p1());
     1994
     1995    path.lineTo(line.p2());
     1996}
     1997
     1998template <Edge edge>
     1999void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result)
     2000{
     2001    bool outA = compare<edge>(a, t);
     2002    bool outB = compare<edge>(b, t);
     2003    if (outA && outB)
     2004        return;
     2005
     2006    if (outA)
     2007        addLine(result, QLineF(intersectLine<edge>(a, b, t), b));
     2008    else if(outB)
     2009        addLine(result, QLineF(a, intersectLine<edge>(a, b, t)));
     2010    else
     2011        addLine(result, QLineF(a, b));
     2012}
     2013
     2014void addBezier(QPainterPath &path, const QBezier &bezier)
     2015{
     2016    if (path.elementCount() > 0)
     2017        path.lineTo(bezier.pt1());
     2018    else
     2019        path.moveTo(bezier.pt1());
     2020
     2021    path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4());
     2022}
     2023
     2024template <Edge edge>
     2025void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result)
     2026{
     2027    QBezier bezier = QBezier::fromPoints(a, b, c, d);
     2028
     2029    bool outA = compare<edge>(a, t);
     2030    bool outB = compare<edge>(b, t);
     2031    bool outC = compare<edge>(c, t);
     2032    bool outD = compare<edge>(d, t);
     2033
     2034    int outCount = int(outA) + int(outB) + int(outC) + int(outD);
     2035
     2036    if (outCount == 4)
     2037        return;
     2038
     2039    if (outCount == 0) {
     2040        addBezier(result, bezier);
     2041        return;
     2042    }
     2043
     2044    QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform();
     2045    QBezier unflipped = bezier;
     2046    QBezier flipped = bezier.mapBy(flip);
     2047
     2048    qreal t0 = 0, t1 = 1;
     2049    int stationary = flipped.stationaryYPoints(t0, t1);
     2050
     2051    qreal segments[4];
     2052    QPointF points[4];
     2053    points[0] = unflipped.pt1();
     2054    segments[0] = 0;
     2055
     2056    int segmentCount = 0;
     2057    if (stationary > 0) {
     2058        ++segmentCount;
     2059        segments[segmentCount] = t0;
     2060        points[segmentCount] = unflipped.pointAt(t0);
     2061    }
     2062    if (stationary > 1) {
     2063        ++segmentCount;
     2064        segments[segmentCount] = t1;
     2065        points[segmentCount] = unflipped.pointAt(t1);
     2066    }
     2067    ++segmentCount;
     2068    segments[segmentCount] = 1;
     2069    points[segmentCount] = unflipped.pt4();
     2070
     2071    qreal lastIntersection = 0;
     2072    for (int i = 0; i < segmentCount; ++i) {
     2073        outA = compare<edge>(points[i], t);
     2074        outB = compare<edge>(points[i+1], t);
     2075
     2076        if (outA != outB) {
     2077            qreal intersection = flipped.tForY(segments[i], segments[i+1], t);
     2078
     2079            if (outB)
     2080                addBezier(result, unflipped.getSubRange(lastIntersection, intersection));
     2081
     2082            lastIntersection = intersection;
     2083        }
     2084    }
     2085
     2086    if (!outB)
     2087        addBezier(result, unflipped.getSubRange(lastIntersection, 1));
     2088}
     2089
     2090// clips a single subpath against a single edge
     2091template <Edge edge>
     2092QPainterPath clip(const QPainterPath &path, qreal t)
     2093{
     2094    QPainterPath result;
     2095    for (int i = 1; i < path.elementCount(); ++i) {
     2096        const QPainterPath::Element &element = path.elementAt(i);
     2097        Q_ASSERT(!element.isMoveTo());
     2098        if (element.isLineTo()) {
     2099            clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result);
     2100        } else {
     2101            clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result);
     2102            i += 2;
     2103        }
     2104    }
     2105
     2106    int last = path.elementCount() - 1;
     2107    if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0)))
     2108        clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result);
     2109
     2110    return result;
     2111}
     2112
     2113QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect)
     2114{
     2115    QList<QPainterPath> subpaths = toSubpaths(path);
     2116
     2117    QPainterPath result;
     2118    result.setFillRule(path.fillRule());
     2119    for (int i = 0; i < subpaths.size(); ++i) {
     2120        QPainterPath subPath = subpaths.at(i);
     2121        QRectF bounds = subPath.boundingRect();
     2122        if (bounds.intersects(rect)) {
     2123            if (bounds.left() < rect.left())
     2124                subPath = clip<Left>(subPath, rect.left());
     2125            if (bounds.right() > rect.right())
     2126                subPath = clip<Right>(subPath, rect.right());
     2127
     2128            bounds = subPath.boundingRect();
     2129
     2130            if (bounds.top() < rect.top())
     2131                subPath = clip<Top>(subPath, rect.top());
     2132            if (bounds.bottom() > rect.bottom())
     2133                subPath = clip<Bottom>(subPath, rect.bottom());
     2134
     2135            if (subPath.elementCount() > 1)
     2136                result.addPath(subPath);
     2137        }
     2138    }
     2139    return result;
     2140}
     2141
     2142}
     2143
     2144QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect)
     2145{
     2146    return intersectPath(path, rect);
     2147}
     2148
    20552149QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.