1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QPATHCLIPPER_P_H
41 #define QPATHCLIPPER_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 #include <QtGui/qpainterpath.h>
56 #include <QtCore/qlist.h>
57 
58 #include <private/qbezier_p.h>
59 #include <private/qdatabuffer_p.h>
60 #include <stdio.h>
61 
62 QT_BEGIN_NAMESPACE
63 
64 
65 class QWingedEdge;
66 
67 class Q_GUI_EXPORT QPathClipper
68 {
69 public:
70     enum Operation {
71         BoolAnd,
72         BoolOr,
73         BoolSub,
74         Simplify
75     };
76 public:
77     QPathClipper(const QPainterPath &subject,
78                  const QPainterPath &clip);
79 
80     QPainterPath clip(Operation op = BoolAnd);
81 
82     bool intersect();
83     bool contains();
84 
85     static bool pathToRect(const QPainterPath &path, QRectF *rect = nullptr);
86     static QPainterPath intersect(const QPainterPath &path, const QRectF &rect);
87 
88 private:
89     Q_DISABLE_COPY_MOVE(QPathClipper)
90 
91     enum ClipperMode {
92         ClipMode, // do the full clip
93         CheckMode // for contains/intersects (only interested in whether the result path is non-empty)
94     };
95 
96     bool handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode);
97     bool doClip(QWingedEdge &list, ClipperMode mode);
98 
99     QPainterPath subjectPath;
100     QPainterPath clipPath;
101     Operation op;
102 
103     int aMask;
104     int bMask;
105 };
106 
107 struct QPathVertex
108 {
109 public:
110     QPathVertex(const QPointF &p = QPointF(), int e = -1);
111     operator QPointF() const;
112 
113     int edge;
114 
115     qreal x;
116     qreal y;
117 };
118 
119 class QPathEdge
120 {
121 public:
122     enum Traversal {
123         RightTraversal,
124         LeftTraversal
125     };
126 
127     enum Direction {
128         Forward,
129         Backward
130     };
131 
132     enum Type {
133         Line,
134         Curve
135     };
136 
137     explicit QPathEdge(int a = -1, int b = -1);
138 
139     mutable int flag;
140 
141     int windingA;
142     int windingB;
143 
144     int first;
145     int second;
146 
147     double angle;
148     double invAngle;
149 
150     int next(Traversal traversal, Direction direction) const;
151 
152     void setNext(Traversal traversal, Direction direction, int next);
153     void setNext(Direction direction, int next);
154 
155     Direction directionTo(int vertex) const;
156     int vertex(Direction direction) const;
157 
158 private:
159     int m_next[2][2];
160 };
161 
162 class QPathSegments
163 {
164 public:
165     struct Intersection {
166         qreal t;
167         int vertex;
168         int next;
169 
170         bool operator<(const Intersection &o) const {
171             return t < o.t;
172         }
173     };
174 
175     struct Segment {
SegmentSegment176         Segment(int pathId, int vertexA, int vertexB)
177             : path(pathId)
178             , va(vertexA)
179             , vb(vertexB)
180             , intersection(-1)
181         {
182         }
183 
184         int path;
185 
186         // vertices
187         int va;
188         int vb;
189 
190         // intersection index
191         int intersection;
192 
193         QRectF bounds;
194     };
195 
196 
197     QPathSegments(int reserve);
198 
199     void setPath(const QPainterPath &path);
200     void addPath(const QPainterPath &path);
201 
202     int intersections() const;
203     int segments() const;
204     int points() const;
205 
206     const Segment &segmentAt(int index) const;
207     const QLineF lineAt(int index) const;
208     const QRectF &elementBounds(int index) const;
209     int pathId(int index) const;
210 
211     const QPointF &pointAt(int vertex) const;
212     int addPoint(const QPointF &point);
213 
214     const Intersection *intersectionAt(int index) const;
215     void addIntersection(int index, const Intersection &intersection);
216 
217     void mergePoints();
218 
219 private:
220     QDataBuffer<QPointF> m_points;
221     QDataBuffer<Segment> m_segments;
222     QDataBuffer<Intersection> m_intersections;
223 
224     int m_pathId;
225 };
226 
227 class Q_AUTOTEST_EXPORT QWingedEdge
228 {
229 public:
230     struct TraversalStatus
231     {
232         int edge;
233         QPathEdge::Traversal traversal;
234         QPathEdge::Direction direction;
235 
236         void flipDirection();
237         void flipTraversal();
238 
239         void flip();
240     };
241 
242     QWingedEdge();
243     QWingedEdge(const QPainterPath &subject, const QPainterPath &clip);
244 
245     void simplify();
246     QPainterPath toPath() const;
247 
248     int edgeCount() const;
249 
250     QPathEdge *edge(int edge);
251     const QPathEdge *edge(int edge) const;
252 
253     int vertexCount() const;
254 
255     int addVertex(const QPointF &p);
256 
257     QPathVertex *vertex(int vertex);
258     const QPathVertex *vertex(int vertex) const;
259 
260     TraversalStatus next(const TraversalStatus &status) const;
261 
262     int addEdge(const QPointF &a, const QPointF &b);
263     int addEdge(int vertexA, int vertexB);
264 
265     bool isInside(qreal x, qreal y) const;
266 
267     static QPathEdge::Traversal flip(QPathEdge::Traversal traversal);
268     static QPathEdge::Direction flip(QPathEdge::Direction direction);
269 
270 private:
271     void intersectAndAdd();
272 
273     void printNode(int i, FILE *handle);
274 
275     void removeEdge(int ei);
276 
277     int insert(const QPathVertex &vertex);
278     TraversalStatus findInsertStatus(int vertex, int edge) const;
279 
280     qreal delta(int vertex, int a, int b) const;
281 
282     QDataBuffer<QPathEdge> m_edges;
283     QDataBuffer<QPathVertex> m_vertices;
284 
285     QVector<qreal> m_splitPoints;
286 
287     QPathSegments m_segments;
288 };
289 
QPathEdge(int a,int b)290 inline QPathEdge::QPathEdge(int a, int b)
291     : flag(0)
292     , windingA(0)
293     , windingB(0)
294     , first(a)
295     , second(b)
296     , angle(0)
297     , invAngle(0)
298 {
299     m_next[0][0] = -1;
300     m_next[1][0] = -1;
301     m_next[0][0] = -1;
302     m_next[1][0] = -1;
303 }
304 
next(Traversal traversal,Direction direction)305 inline int QPathEdge::next(Traversal traversal, Direction direction) const
306 {
307     return m_next[int(traversal)][int(direction)];
308 }
309 
setNext(Traversal traversal,Direction direction,int next)310 inline void QPathEdge::setNext(Traversal traversal, Direction direction, int next)
311 {
312     m_next[int(traversal)][int(direction)] = next;
313 }
314 
setNext(Direction direction,int next)315 inline void QPathEdge::setNext(Direction direction, int next)
316 {
317     m_next[0][int(direction)] = next;
318     m_next[1][int(direction)] = next;
319 }
320 
directionTo(int vertex)321 inline QPathEdge::Direction QPathEdge::directionTo(int vertex) const
322 {
323     return first == vertex ? Backward : Forward;
324 }
325 
vertex(Direction direction)326 inline int QPathEdge::vertex(Direction direction) const
327 {
328     return direction == Backward ? first : second;
329 }
330 
QPathVertex(const QPointF & p,int e)331 inline QPathVertex::QPathVertex(const QPointF &p, int e)
332     : edge(e)
333     , x(p.x())
334     , y(p.y())
335 {
336 }
337 
QPointF()338 inline QPathVertex::operator QPointF() const
339 {
340     return QPointF(x, y);
341 }
342 
QPathSegments(int reserve)343 inline QPathSegments::QPathSegments(int reserve) :
344     m_points(reserve),
345     m_segments(reserve),
346     m_intersections(reserve),
347     m_pathId(0)
348 {
349 }
350 
segments()351 inline int QPathSegments::segments() const
352 {
353     return m_segments.size();
354 }
355 
points()356 inline int QPathSegments::points() const
357 {
358     return m_points.size();
359 }
360 
pointAt(int i)361 inline const QPointF &QPathSegments::pointAt(int i) const
362 {
363     return m_points.at(i);
364 }
365 
addPoint(const QPointF & point)366 inline int QPathSegments::addPoint(const QPointF &point)
367 {
368     m_points << point;
369     return m_points.size() - 1;
370 }
371 
segmentAt(int index)372 inline const QPathSegments::Segment &QPathSegments::segmentAt(int index) const
373 {
374     return m_segments.at(index);
375 }
376 
lineAt(int index)377 inline const QLineF QPathSegments::lineAt(int index) const
378 {
379     const Segment &segment = m_segments.at(index);
380     return QLineF(m_points.at(segment.va), m_points.at(segment.vb));
381 }
382 
elementBounds(int index)383 inline const QRectF &QPathSegments::elementBounds(int index) const
384 {
385     return m_segments.at(index).bounds;
386 }
387 
pathId(int index)388 inline int QPathSegments::pathId(int index) const
389 {
390     return m_segments.at(index).path;
391 }
392 
intersectionAt(int index)393 inline const QPathSegments::Intersection *QPathSegments::intersectionAt(int index) const
394 {
395     const int intersection = m_segments.at(index).intersection;
396     if (intersection < 0)
397         return nullptr;
398     else
399         return &m_intersections.at(intersection);
400 }
401 
intersections()402 inline int QPathSegments::intersections() const
403 {
404     return m_intersections.size();
405 }
406 
addIntersection(int index,const Intersection & intersection)407 inline void QPathSegments::addIntersection(int index, const Intersection &intersection)
408 {
409     m_intersections << intersection;
410 
411     Segment &segment = m_segments.at(index);
412     if (segment.intersection < 0) {
413         segment.intersection = m_intersections.size() - 1;
414     } else {
415         Intersection *isect = &m_intersections.at(segment.intersection);
416 
417         while (isect->next != 0)
418             isect += isect->next;
419 
420         isect->next = (m_intersections.size() - 1) - (isect - m_intersections.data());
421     }
422 }
423 
edgeCount()424 inline int QWingedEdge::edgeCount() const
425 {
426     return m_edges.size();
427 }
428 
edge(int edge)429 inline QPathEdge *QWingedEdge::edge(int edge)
430 {
431     return edge < 0 ? nullptr : &m_edges.at(edge);
432 }
433 
edge(int edge)434 inline const QPathEdge *QWingedEdge::edge(int edge) const
435 {
436     return edge < 0 ? nullptr : &m_edges.at(edge);
437 }
438 
vertexCount()439 inline int QWingedEdge::vertexCount() const
440 {
441     return m_vertices.size();
442 }
443 
addVertex(const QPointF & p)444 inline int QWingedEdge::addVertex(const QPointF &p)
445 {
446     m_vertices << p;
447     return m_vertices.size() - 1;
448 }
449 
vertex(int vertex)450 inline QPathVertex *QWingedEdge::vertex(int vertex)
451 {
452     return vertex < 0 ? nullptr : &m_vertices.at(vertex);
453 }
454 
vertex(int vertex)455 inline const QPathVertex *QWingedEdge::vertex(int vertex) const
456 {
457     return vertex < 0 ? nullptr : &m_vertices.at(vertex);
458 }
459 
flip(QPathEdge::Traversal traversal)460 inline QPathEdge::Traversal QWingedEdge::flip(QPathEdge::Traversal traversal)
461 {
462     return traversal == QPathEdge::RightTraversal ? QPathEdge::LeftTraversal : QPathEdge::RightTraversal;
463 }
464 
flipTraversal()465 inline void QWingedEdge::TraversalStatus::flipTraversal()
466 {
467     traversal = QWingedEdge::flip(traversal);
468 }
469 
flip(QPathEdge::Direction direction)470 inline QPathEdge::Direction QWingedEdge::flip(QPathEdge::Direction direction)
471 {
472     return direction == QPathEdge::Forward ? QPathEdge::Backward : QPathEdge::Forward;
473 }
474 
flipDirection()475 inline void QWingedEdge::TraversalStatus::flipDirection()
476 {
477     direction = QWingedEdge::flip(direction);
478 }
479 
flip()480 inline void QWingedEdge::TraversalStatus::flip()
481 {
482     flipDirection();
483     flipTraversal();
484 }
485 
486 QT_END_NAMESPACE
487 
488 #endif // QPATHCLIPPER_P_H
489