src/gui/painting/qpathclipper_p.h
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/painting/qpathclipper_p.h	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,512 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPATHCLIPPER_P_H
+#define QPATHCLIPPER_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qpainterpath.h>
+#include <QtCore/qlist.h>
+
+#include <private/qbezier_p.h>
+#include <private/qdatabuffer_p.h>
+#include <stdio.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QWingedEdge;
+
+class Q_AUTOTEST_EXPORT QPathClipper
+{
+public:
+    enum Operation {
+        BoolAnd,
+        BoolOr,
+        BoolSub,
+        Simplify
+    };
+public:
+    QPathClipper(const QPainterPath &subject,
+                 const QPainterPath &clip);
+
+    QPainterPath clip(Operation op = BoolAnd);
+
+    bool intersect();
+    bool contains();
+
+private:
+    Q_DISABLE_COPY(QPathClipper)
+
+    enum ClipperMode {
+        ClipMode, // do the full clip
+        CheckMode // for contains/intersects (only interested in whether the result path is non-empty)
+    };
+
+    bool handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode);
+    bool doClip(QWingedEdge &list, ClipperMode mode);
+
+    QPainterPath subjectPath;
+    QPainterPath clipPath;
+    Operation op;
+
+    int aMask;
+    int bMask;
+};
+
+struct QPathVertex
+{
+public:
+    QPathVertex(const QPointF &p = QPointF(), int e = -1);
+    operator QPointF() const;
+
+    int edge;
+
+    qreal x;
+    qreal y;
+};
+
+class QPathEdge
+{
+public:
+    enum Traversal {
+        RightTraversal,
+        LeftTraversal
+    };
+
+    enum Direction {
+        Forward,
+        Backward
+    };
+
+    enum Type {
+        Line,
+        Curve
+    };
+
+    QPathEdge(int a = -1, int b = -1);
+
+    mutable int flag;
+
+    int windingA;
+    int windingB;
+
+    int first;
+    int second;
+
+    qreal angle;
+    qreal invAngle;
+
+    const QBezier *bezier;
+    qreal t0;
+    qreal t1;
+
+    int next(Traversal traversal, Direction direction) const;
+
+    void setNext(Traversal traversal, Direction direction, int next);
+    void setNext(Direction direction, int next);
+
+    Direction directionTo(int vertex) const;
+    int vertex(Direction direction) const;
+
+private:
+    int m_next[2][2];
+};
+
+class QPathSegments
+{
+public:
+    struct Intersection {
+        int vertex;
+        qreal t;
+
+        int next;
+
+        bool operator<(const Intersection &o) const {
+            return t < o.t;
+        }
+    };
+
+    struct Segment {
+        Segment(int pathId, int vertexA, int vertexB, int bezierIndex = -1)
+            : path(pathId)
+            , bezier(bezierIndex)
+            , va(vertexA)
+            , vb(vertexB)
+            , intersection(-1)
+        {
+        }
+
+        int path;
+        int bezier;
+
+        // vertices
+        int va;
+        int vb;
+
+        // intersection index
+        int intersection;
+
+        QRectF bounds;
+    };
+
+
+    QPathSegments();
+
+    void setPath(const QPainterPath &path);
+    void addPath(const QPainterPath &path);
+
+    int intersections() const;
+    int segments() const;
+    int points() const;
+
+    const Segment &segmentAt(int index) const;
+    const QLineF lineAt(int index) const;
+    const QBezier *bezierAt(int index) const;
+    const QRectF &elementBounds(int index) const;
+    int pathId(int index) const;
+
+    const QPointF &pointAt(int vertex) const;
+    int addPoint(const QPointF &point);
+
+    const Intersection *intersectionAt(int index) const;
+    void addIntersection(int index, const Intersection &intersection);
+
+    void mergePoints();
+
+private:
+    QDataBuffer<QPointF> m_points;
+    QDataBuffer<Segment> m_segments;
+    QDataBuffer<QBezier> m_beziers;
+    QDataBuffer<Intersection> m_intersections;
+
+    int m_pathId;
+};
+
+class Q_AUTOTEST_EXPORT QWingedEdge
+{
+public:
+    struct TraversalStatus
+    {
+        int edge;
+        QPathEdge::Traversal traversal;
+        QPathEdge::Direction direction;
+
+        void flipDirection();
+        void flipTraversal();
+
+        void flip();
+    };
+
+    QWingedEdge();
+    QWingedEdge(const QPainterPath &subject, const QPainterPath &clip);
+
+    void simplify();
+    QPainterPath toPath() const;
+
+    int edgeCount() const;
+
+    QPathEdge *edge(int edge);
+    const QPathEdge *edge(int edge) const;
+
+    int vertexCount() const;
+
+    int addVertex(const QPointF &p);
+
+    QPathVertex *vertex(int vertex);
+    const QPathVertex *vertex(int vertex) const;
+
+    TraversalStatus next(const TraversalStatus &status) const;
+
+    int addEdge(const QPointF &a, const QPointF &b, const QBezier *bezier = 0, qreal t0 = 0, qreal t1 = 1);
+    int addEdge(int vertexA, int vertexB, const QBezier *bezier = 0, qreal t0 = 0, qreal t1 = 1);
+
+    bool isInside(qreal x, qreal y) const;
+
+    static QPathEdge::Traversal flip(QPathEdge::Traversal traversal);
+    static QPathEdge::Direction flip(QPathEdge::Direction direction);
+
+private:
+    void intersectAndAdd();
+
+    void printNode(int i, FILE *handle);
+
+    QBezier bezierFromIndex(int index) const;
+
+    void removeEdge(int ei);
+    void addBezierEdge(const QBezier *bezier, const QPointF &a, const QPointF &b, qreal alphaA, qreal alphaB, int path);
+    void addBezierEdge(const QBezier *bezier, int vertexA, int vertexB, qreal alphaA, qreal alphaB, int path);
+
+    int insert(const QPathVertex &vertex);
+    TraversalStatus findInsertStatus(int vertex, int edge) const;
+
+    qreal delta(int vertex, int a, int b) const;
+
+    QDataBuffer<QPathEdge> m_edges;
+    QDataBuffer<QPathVertex> m_vertices;
+
+    QVector<qreal> m_splitPoints;
+
+    QPathSegments m_segments;
+};
+
+inline QPathEdge::QPathEdge(int a, int b)
+    : flag(0)
+    , windingA(0)
+    , windingB(0)
+    , first(a)
+    , second(b)
+    , angle(0)
+    , invAngle(0)
+    , bezier(0)
+    , t0(0)
+    , t1(0)
+{
+    m_next[0][0] = -1;
+    m_next[1][0] = -1;
+    m_next[0][0] = -1;
+    m_next[1][0] = -1;
+}
+
+inline int QPathEdge::next(Traversal traversal, Direction direction) const
+{
+    return m_next[int(traversal)][int(direction)];
+}
+
+inline void QPathEdge::setNext(Traversal traversal, Direction direction, int next)
+{
+    m_next[int(traversal)][int(direction)] = next;
+}
+
+inline void QPathEdge::setNext(Direction direction, int next)
+{
+    m_next[0][int(direction)] = next;
+    m_next[1][int(direction)] = next;
+}
+
+inline QPathEdge::Direction QPathEdge::directionTo(int vertex) const
+{
+    return first == vertex ? Backward : Forward;
+}
+
+inline int QPathEdge::vertex(Direction direction) const
+{
+    return direction == Backward ? first : second;
+}
+
+inline QPathVertex::QPathVertex(const QPointF &p, int e)
+    : edge(e)
+    , x(p.x())
+    , y(p.y())
+{
+}
+
+inline QPathVertex::operator QPointF() const
+{
+    return QPointF(x, y);
+}
+
+inline QPathSegments::QPathSegments()
+{
+}
+
+inline int QPathSegments::segments() const
+{
+    return m_segments.size();
+}
+
+inline int QPathSegments::points() const
+{
+    return m_points.size();
+}
+
+inline const QPointF &QPathSegments::pointAt(int i) const
+{
+    return m_points.at(i);
+}
+
+inline int QPathSegments::addPoint(const QPointF &point)
+{
+    m_points << point;
+    return m_points.size() - 1;
+}
+
+inline const QPathSegments::Segment &QPathSegments::segmentAt(int index) const
+{
+    return m_segments.at(index);
+}
+
+inline const QLineF QPathSegments::lineAt(int index) const
+{
+    const Segment &segment = m_segments.at(index);
+    return QLineF(m_points.at(segment.va), m_points.at(segment.vb));
+}
+
+inline const QBezier *QPathSegments::bezierAt(int index) const
+{
+    const Segment &segment = m_segments.at(index);
+    if (segment.bezier >= 0)
+        return &m_beziers.at(segment.bezier);
+    else
+        return 0;
+}
+
+inline const QRectF &QPathSegments::elementBounds(int index) const
+{
+    return m_segments.at(index).bounds;
+}
+
+inline int QPathSegments::pathId(int index) const
+{
+    return m_segments.at(index).path;
+}
+
+inline const QPathSegments::Intersection *QPathSegments::intersectionAt(int index) const
+{
+    const int intersection = m_segments.at(index).intersection;
+    if (intersection < 0)
+        return 0;
+    else
+        return &m_intersections.at(intersection);
+}
+
+inline int QPathSegments::intersections() const
+{
+    return m_intersections.size();
+}
+
+inline void QPathSegments::addIntersection(int index, const Intersection &intersection)
+{
+    m_intersections << intersection;
+
+    Segment &segment = m_segments.at(index);
+    if (segment.intersection < 0) {
+        segment.intersection = m_intersections.size() - 1;
+    } else {
+        Intersection *isect = &m_intersections.at(segment.intersection);
+
+        while (isect->next != 0)
+            isect += isect->next;
+
+        isect->next = (m_intersections.size() - 1) - (isect - m_intersections.data());
+    }
+}
+
+inline void QWingedEdge::TraversalStatus::flipDirection()
+{
+    direction = QWingedEdge::flip(direction);
+}
+
+inline void QWingedEdge::TraversalStatus::flipTraversal()
+{
+    traversal = QWingedEdge::flip(traversal);
+}
+
+inline void QWingedEdge::TraversalStatus::flip()
+{
+    flipDirection();
+    flipTraversal();
+}
+
+inline int QWingedEdge::edgeCount() const
+{
+    return m_edges.size();
+}
+
+inline QPathEdge *QWingedEdge::edge(int edge)
+{
+    return edge < 0 ? 0 : &m_edges.at(edge);
+}
+
+inline const QPathEdge *QWingedEdge::edge(int edge) const
+{
+    return edge < 0 ? 0 : &m_edges.at(edge);
+}
+
+inline int QWingedEdge::vertexCount() const
+{
+    return m_vertices.size();
+}
+
+inline int QWingedEdge::addVertex(const QPointF &p)
+{
+    m_vertices << p;
+    return m_vertices.size() - 1;
+}
+
+inline QPathVertex *QWingedEdge::vertex(int vertex)
+{
+    return vertex < 0 ? 0 : &m_vertices.at(vertex);
+}
+
+inline const QPathVertex *QWingedEdge::vertex(int vertex) const
+{
+    return vertex < 0 ? 0 : &m_vertices.at(vertex);
+}
+
+inline QPathEdge::Traversal QWingedEdge::flip(QPathEdge::Traversal traversal)
+{
+    return traversal == QPathEdge::RightTraversal ? QPathEdge::LeftTraversal : QPathEdge::RightTraversal;
+}
+
+inline QPathEdge::Direction QWingedEdge::flip(QPathEdge::Direction direction)
+{
+    return direction == QPathEdge::Forward ? QPathEdge::Backward : QPathEdge::Forward;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPATHCLIPPER_P_H