Coverage Report

Created: 2026-01-25 07:18

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