diff options
Diffstat (limited to 'src/gui/painting/qpathclipper_p.h')
-rw-r--r-- | src/gui/painting/qpathclipper_p.h | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h new file mode 100644 index 0000000..981ca84 --- /dev/null +++ b/src/gui/painting/qpathclipper_p.h @@ -0,0 +1,519 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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; + + bool isBezier() 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 bool QPathEdge::isBezier() const +{ + return bezier >= 0; +} + +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 |