Coverage Report

Created: 2026-05-16 06:37

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