Coverage Report

Created: 2026-11-10 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qstroker_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 QSTROKER_P_H
6
#define QSTROKER_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 "private/qdatabuffer_p.h"
22
#include "private/qnumeric_p.h"
23
24
QT_BEGIN_NAMESPACE
25
26
// #define QFIXED_IS_26_6
27
28
#if defined QFIXED_IS_26_6
29
typedef int qfixed;
30
#define qt_real_to_fixed(real) qfixed(real * 64)
31
#define qt_int_to_fixed(real) qfixed(int(real) << 6)
32
#define qt_fixed_to_real(fixed) qreal(fixed / qreal(64))
33
#define qt_fixed_to_int(fixed) int(fixed >> 6)
34
struct qfixed2d
35
{
36
    qfixed x;
37
    qfixed y;
38
39
    bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; }
40
};
41
#elif defined QFIXED_IS_32_32
42
typedef qint64 qfixed;
43
#define qt_real_to_fixed(real) qfixed(real * double(qint64(1) << 32))
44
#define qt_fixed_to_real(fixed) qreal(fixed / double(qint64(1) << 32))
45
struct qfixed2d
46
{
47
    qfixed x;
48
    qfixed y;
49
50
    bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; }
51
};
52
#elif defined QFIXED_IS_16_16
53
typedef int qfixed;
54
#define qt_real_to_fixed(real) qfixed(real * qreal(1 << 16))
55
#define qt_fixed_to_real(fixed) qreal(fixed / qreal(1 << 16))
56
struct qfixed2d
57
{
58
    qfixed x;
59
    qfixed y;
60
61
    bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; }
62
};
63
#else
64
typedef qreal qfixed;
65
136k
#define qt_real_to_fixed(real) qfixed(real)
66
0
#define qt_fixed_to_real(fixed) fixed
67
struct qfixed2d
68
{
69
    qfixed x;
70
    qfixed y;
71
72
0
    bool isFinite() { return qIsFinite(x) && qIsFinite(y); }
73
0
    bool operator==(const qfixed2d &other) const { return qFuzzyCompare(x, other.x)
74
0
                                                       && qFuzzyCompare(y, other.y); }
75
};
76
#endif
77
78
0
#define QT_PATH_KAPPA 0.5522847498
79
80
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
81
                          QPointF *controlPoints, int *point_count);
82
83
qreal qt_t_for_arc_angle(qreal angle);
84
85
typedef void (*qStrokerMoveToHook)(qfixed x, qfixed y, void *data);
86
typedef void (*qStrokerLineToHook)(qfixed x, qfixed y, void *data);
87
typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y,
88
                                    qfixed c2x, qfixed c2y,
89
                                    qfixed ex, qfixed ey,
90
                                    void *data);
91
92
// qtransform.cpp
93
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
94
95
class Q_GUI_EXPORT QStrokerOps
96
{
97
public:
98
    struct Element {
99
        QPainterPath::ElementType type;
100
        qfixed x;
101
        qfixed y;
102
103
0
        inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; }
104
0
        inline bool isLineTo() const { return type == QPainterPath::LineToElement; }
105
0
        inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; }
106
107
0
        operator qfixed2d () { qfixed2d pt = { x, y }; return pt; }
108
    };
109
110
    QStrokerOps();
111
    virtual ~QStrokerOps();
112
113
24.8k
    void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; }
114
24.8k
    void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; }
115
24.8k
    void setCubicToHook(qStrokerCubicToHook cubicToHook) { m_cubicTo = cubicToHook; }
116
117
    virtual void begin(void *customData);
118
    virtual void end();
119
120
    inline void moveTo(qfixed x, qfixed y);
121
    inline void lineTo(qfixed x, qfixed y);
122
    inline void cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey);
123
124
    void strokePath(const QPainterPath &path, void *data, const QTransform &matrix);
125
    void strokePolygon(const QPointF *points, int pointCount, bool implicit_close,
126
                       void *data, const QTransform &matrix);
127
    void strokeEllipse(const QRectF &ellipse, void *data, const QTransform &matrix);
128
129
0
    QRectF clipRect() const { return m_clip_rect; }
130
12.4k
    void setClipRect(const QRectF &clip) { m_clip_rect = clip; }
131
132
    void setCurveThresholdFromTransform(const QTransform &transform)
133
0
    {
134
0
        qreal scale;
135
0
        qt_scaleForTransform(transform, &scale);
136
0
        const qreal threshold = scale == 0 ? qreal(0.5) : (qreal(0.5) / scale);
137
        // The dashes are flattened with this threshold; an explicitly set curve
138
        // threshold puts an upper bound on it.
139
0
        m_dashThreshold =
140
0
                m_curveThresholdExplicitlySet ? qMin(threshold, m_curveThreshold) : threshold;
141
0
    }
142
143
    void setCurveThreshold(qfixed threshold)
144
0
    {
145
0
        m_curveThreshold = threshold;
146
0
        m_curveThresholdExplicitlySet = true;
147
0
    }
148
0
    qfixed curveThreshold() const { return m_curveThreshold; }
149
0
    bool curveThresholdExplicitlySet() const { return m_curveThresholdExplicitlySet; }
150
151
protected:
152
    inline void emitMoveTo(qfixed x, qfixed y);
153
    inline void emitLineTo(qfixed x, qfixed y);
154
    inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey);
155
156
    virtual void processCurrentSubpath() = 0;
157
    QDataBuffer<Element> m_elements;
158
159
    QRectF m_clip_rect;
160
    qfixed m_curveThreshold;
161
    qfixed m_dashThreshold;
162
    bool m_curveThresholdExplicitlySet;
163
164
    void *m_customData;
165
    qStrokerMoveToHook m_moveTo;
166
    qStrokerLineToHook m_lineTo;
167
    qStrokerCubicToHook m_cubicTo;
168
169
};
170
171
class Q_GUI_EXPORT QStroker : public QStrokerOps
172
{
173
public:
174
175
    enum LineJoinMode {
176
        FlatJoin,
177
        SquareJoin,
178
        MiterJoin,
179
        RoundJoin,
180
        RoundCap,
181
        SvgMiterJoin
182
    };
183
184
    QStroker();
185
    ~QStroker();
186
187
    void setStrokeWidth(qfixed width)
188
12.4k
    {
189
12.4k
        m_strokeWidth = width;
190
12.4k
        m_curveThreshold = qt_real_to_fixed(qBound(0.00025, 1.0 / qt_fixed_to_real(width), 0.25));
191
12.4k
    }
192
0
    qfixed strokeWidth() const { return m_strokeWidth; }
193
194
12.4k
    void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); }
195
0
    Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); }
196
0
    LineJoinMode capStyleMode() const { return m_capStyle; }
197
198
12.4k
    void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); }
199
0
    Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); }
200
0
    LineJoinMode joinStyleMode() const { return m_joinStyle; }
201
202
12.4k
    void setMiterLimit(qfixed length) { m_miterLimit = length; }
203
0
    qfixed miterLimit() const { return m_miterLimit; }
204
205
0
    void setForceOpen(bool state) { m_forceOpen = state; }
206
0
    bool forceOpen() const { return m_forceOpen; }
207
208
    void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join);
209
    inline void emitMoveTo(qfixed x, qfixed y);
210
    inline void emitLineTo(qfixed x, qfixed y);
211
    inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey);
212
213
protected:
214
    static Qt::PenCapStyle capForJoinMode(LineJoinMode mode);
215
    static LineJoinMode joinModeForCap(Qt::PenCapStyle);
216
217
    static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode);
218
    static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle);
219
220
    void processCurrentSubpath() override;
221
222
    qfixed m_strokeWidth;
223
    qfixed m_miterLimit;
224
225
    LineJoinMode m_capStyle;
226
    LineJoinMode m_joinStyle;
227
228
    qfixed m_back1X;
229
    qfixed m_back1Y;
230
231
    qfixed m_back2X;
232
    qfixed m_back2Y;
233
234
    bool m_forceOpen;
235
};
236
237
class Q_GUI_EXPORT QDashStroker : public QStrokerOps
238
{
239
public:
240
    QDashStroker(QStroker *stroker);
241
    ~QDashStroker();
242
243
0
    QStroker *stroker() const { return m_stroker; }
244
245
    static QList<qfixed> patternForStyle(Qt::PenStyle style);
246
0
    static int repetitionLimit() { return 10000; }
247
248
0
    void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
249
0
    QList<qfixed> dashPattern() const { return m_dashPattern; }
250
251
0
    void setDashOffset(qreal offset) { m_dashOffset = offset; }
252
0
    qreal dashOffset() const { return m_dashOffset; }
253
254
    void begin(void *data) override;
255
    void end() override;
256
257
0
    inline void setStrokeWidth(qreal width) { m_stroke_width = width; }
258
0
    inline void setMiterLimit(qreal limit) { m_miter_limit = limit; }
259
260
protected:
261
    void processCurrentSubpath() override;
262
263
    QStroker *m_stroker;
264
    QList<qfixed> m_dashPattern;
265
    qreal m_dashOffset;
266
267
    qreal m_stroke_width;
268
    qreal m_miter_limit;
269
};
270
271
272
/*******************************************************************************
273
 * QStrokerOps inline membmers
274
 */
275
276
inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y)
277
0
{
278
0
    Q_ASSERT(m_moveTo);
279
0
    m_moveTo(x, y, m_customData);
280
0
}
281
282
inline void QStrokerOps::emitLineTo(qfixed x, qfixed y)
283
0
{
284
0
    Q_ASSERT(m_lineTo);
285
0
    m_lineTo(x, y, m_customData);
286
0
}
287
288
inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey)
289
0
{
290
0
    Q_ASSERT(m_cubicTo);
291
0
    m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData);
292
0
}
293
294
inline void QStrokerOps::moveTo(qfixed x, qfixed y)
295
0
{
296
0
    if (m_elements.size()>1)
297
0
        processCurrentSubpath();
298
0
    m_elements.reset();
299
0
    Element e = { QPainterPath::MoveToElement, x, y };
300
0
    m_elements.add(e);
301
0
}
302
303
inline void QStrokerOps::lineTo(qfixed x, qfixed y)
304
0
{
305
0
    Element e = { QPainterPath::LineToElement, x, y };
306
0
    m_elements.add(e);
307
0
}
308
309
inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey)
310
0
{
311
0
    Element c1 = { QPainterPath::CurveToElement, x1, y1 };
312
0
    Element c2 = { QPainterPath::CurveToDataElement, x2, y2 };
313
0
    Element e = { QPainterPath::CurveToDataElement, ex, ey };
314
0
    m_elements.add(c1);
315
0
    m_elements.add(c2);
316
0
    m_elements.add(e);
317
0
}
318
319
/*******************************************************************************
320
 * QStroker inline members
321
 */
322
inline void QStroker::emitMoveTo(qfixed x, qfixed y)
323
0
{
324
0
    m_back2X = m_back1X;
325
0
    m_back2Y = m_back1Y;
326
0
    m_back1X = x;
327
0
    m_back1Y = y;
328
0
    QStrokerOps::emitMoveTo(x, y);
329
0
}
330
331
inline void QStroker::emitLineTo(qfixed x, qfixed y)
332
0
{
333
0
    m_back2X = m_back1X;
334
0
    m_back2Y = m_back1Y;
335
0
    m_back1X = x;
336
0
    m_back1Y = y;
337
0
    QStrokerOps::emitLineTo(x, y);
338
0
}
339
340
inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y,
341
                                  qfixed c2x, qfixed c2y,
342
                                  qfixed ex, qfixed ey)
343
0
{
344
0
    if (c2x == ex && c2y == ey) {
345
0
        if (c1x == ex && c1y == ey) {
346
0
            m_back2X = m_back1X;
347
0
            m_back2Y = m_back1Y;
348
0
        } else {
349
0
            m_back2X = c1x;
350
0
            m_back2Y = c1y;
351
0
        }
352
0
    } else {
353
0
        m_back2X = c2x;
354
0
        m_back2Y = c2y;
355
0
    }
356
0
    m_back1X = ex;
357
0
    m_back1Y = ey;
358
0
    QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey);
359
0
}
360
361
/*******************************************************************************
362
 * QDashStroker inline members
363
 */
364
inline void QDashStroker::begin(void *data)
365
0
{
366
0
    if (m_stroker)
367
0
        m_stroker->begin(data);
368
0
    QStrokerOps::begin(data);
369
0
}
370
371
inline void QDashStroker::end()
372
0
{
373
0
    QStrokerOps::end();
374
0
    if (m_stroker)
375
0
        m_stroker->end();
376
0
}
377
378
QT_END_NAMESPACE
379
380
#endif // QSTROKER_P_H