/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 | 12.0M | #define qt_real_to_fixed(real) qfixed(real) |
66 | 15.1M | #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 | 161k | bool operator==(const qfixed2d &other) const { return qFuzzyCompare(x, other.x) |
74 | 98.2k | && 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 | 161k | inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; } |
104 | 1.02M | inline bool isLineTo() const { return type == QPainterPath::LineToElement; } |
105 | 598k | inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; } |
106 | | |
107 | 1.18M | operator qfixed2d () { qfixed2d pt = { x, y }; return pt; } |
108 | | }; |
109 | | |
110 | | QStrokerOps(); |
111 | | virtual ~QStrokerOps(); |
112 | | |
113 | 243k | void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; } |
114 | 243k | void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; } |
115 | 243k | 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 | 110k | void setClipRect(const QRectF &clip) { m_clip_rect = clip; } |
131 | | |
132 | | void setCurveThresholdFromTransform(const QTransform &transform) |
133 | 26.6k | { |
134 | 26.6k | qreal scale; |
135 | 26.6k | qt_scaleForTransform(transform, &scale); |
136 | 26.6k | m_dashThreshold = scale == 0 ? qreal(0.5) : (qreal(0.5) / scale); |
137 | 26.6k | } |
138 | | |
139 | 0 | void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } |
140 | 598k | qfixed curveThreshold() const { return m_curveThreshold; } |
141 | | |
142 | | protected: |
143 | | inline void emitMoveTo(qfixed x, qfixed y); |
144 | | inline void emitLineTo(qfixed x, qfixed y); |
145 | | inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
146 | | |
147 | | virtual void processCurrentSubpath() = 0; |
148 | | QDataBuffer<Element> m_elements; |
149 | | |
150 | | QRectF m_clip_rect; |
151 | | qfixed m_curveThreshold; |
152 | | qfixed m_dashThreshold; |
153 | | |
154 | | void *m_customData; |
155 | | qStrokerMoveToHook m_moveTo; |
156 | | qStrokerLineToHook m_lineTo; |
157 | | qStrokerCubicToHook m_cubicTo; |
158 | | |
159 | | }; |
160 | | |
161 | | class Q_GUI_EXPORT QStroker : public QStrokerOps |
162 | | { |
163 | | public: |
164 | | |
165 | | enum LineJoinMode { |
166 | | FlatJoin, |
167 | | SquareJoin, |
168 | | MiterJoin, |
169 | | RoundJoin, |
170 | | RoundCap, |
171 | | SvgMiterJoin |
172 | | }; |
173 | | |
174 | | QStroker(); |
175 | | ~QStroker(); |
176 | | |
177 | | void setStrokeWidth(qfixed width) |
178 | 168k | { |
179 | 168k | m_strokeWidth = width; |
180 | 168k | m_curveThreshold = qt_real_to_fixed(qBound(0.00025, 1.0 / qt_fixed_to_real(width), 0.25)); |
181 | 168k | } |
182 | 161k | qfixed strokeWidth() const { return m_strokeWidth; } |
183 | | |
184 | 145k | void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); } |
185 | 11.9k | Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); } |
186 | 32.0k | LineJoinMode capStyleMode() const { return m_capStyle; } |
187 | | |
188 | 145k | void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); } |
189 | 11.9k | Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); } |
190 | 958k | LineJoinMode joinStyleMode() const { return m_joinStyle; } |
191 | | |
192 | 145k | void setMiterLimit(qfixed length) { m_miterLimit = length; } |
193 | 0 | qfixed miterLimit() const { return m_miterLimit; } |
194 | | |
195 | 11.9k | void setForceOpen(bool state) { m_forceOpen = state; } |
196 | 96.8k | bool forceOpen() const { return m_forceOpen; } |
197 | | |
198 | | void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join); |
199 | | inline void emitMoveTo(qfixed x, qfixed y); |
200 | | inline void emitLineTo(qfixed x, qfixed y); |
201 | | inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
202 | | |
203 | | protected: |
204 | | static Qt::PenCapStyle capForJoinMode(LineJoinMode mode); |
205 | | static LineJoinMode joinModeForCap(Qt::PenCapStyle); |
206 | | |
207 | | static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode); |
208 | | static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle); |
209 | | |
210 | | void processCurrentSubpath() override; |
211 | | |
212 | | qfixed m_strokeWidth; |
213 | | qfixed m_miterLimit; |
214 | | |
215 | | LineJoinMode m_capStyle; |
216 | | LineJoinMode m_joinStyle; |
217 | | |
218 | | qfixed m_back1X; |
219 | | qfixed m_back1Y; |
220 | | |
221 | | qfixed m_back2X; |
222 | | qfixed m_back2Y; |
223 | | |
224 | | bool m_forceOpen; |
225 | | }; |
226 | | |
227 | | class Q_GUI_EXPORT QDashStroker : public QStrokerOps |
228 | | { |
229 | | public: |
230 | | QDashStroker(QStroker *stroker); |
231 | | ~QDashStroker(); |
232 | | |
233 | 0 | QStroker *stroker() const { return m_stroker; } |
234 | | |
235 | | static QList<qfixed> patternForStyle(Qt::PenStyle style); |
236 | 0 | static int repetitionLimit() { return 10000; } |
237 | | |
238 | 0 | void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; } |
239 | 0 | QList<qfixed> dashPattern() const { return m_dashPattern; } |
240 | | |
241 | 0 | void setDashOffset(qreal offset) { m_dashOffset = offset; } |
242 | 0 | qreal dashOffset() const { return m_dashOffset; } |
243 | | |
244 | | void begin(void *data) override; |
245 | | void end() override; |
246 | | |
247 | 0 | inline void setStrokeWidth(qreal width) { m_stroke_width = width; } |
248 | 0 | inline void setMiterLimit(qreal limit) { m_miter_limit = limit; } |
249 | | |
250 | | protected: |
251 | | void processCurrentSubpath() override; |
252 | | |
253 | | QStroker *m_stroker; |
254 | | QList<qfixed> m_dashPattern; |
255 | | qreal m_dashOffset; |
256 | | |
257 | | qreal m_stroke_width; |
258 | | qreal m_miter_limit; |
259 | | }; |
260 | | |
261 | | |
262 | | /******************************************************************************* |
263 | | * QStrokerOps inline membmers |
264 | | */ |
265 | | |
266 | | inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y) |
267 | 128k | { |
268 | 128k | Q_ASSERT(m_moveTo); |
269 | 128k | m_moveTo(x, y, m_customData); |
270 | 128k | } |
271 | | |
272 | | inline void QStrokerOps::emitLineTo(qfixed x, qfixed y) |
273 | 1.59M | { |
274 | 1.59M | Q_ASSERT(m_lineTo); |
275 | 1.59M | m_lineTo(x, y, m_customData); |
276 | 1.59M | } |
277 | | |
278 | | inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey) |
279 | 1.08M | { |
280 | 1.08M | Q_ASSERT(m_cubicTo); |
281 | 1.08M | m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData); |
282 | 1.08M | } |
283 | | |
284 | | inline void QStrokerOps::moveTo(qfixed x, qfixed y) |
285 | 87.2k | { |
286 | 87.2k | if (m_elements.size()>1) |
287 | 60.6k | processCurrentSubpath(); |
288 | 87.2k | m_elements.reset(); |
289 | 87.2k | Element e = { QPainterPath::MoveToElement, x, y }; |
290 | 87.2k | m_elements.add(e); |
291 | 87.2k | } |
292 | | |
293 | | inline void QStrokerOps::lineTo(qfixed x, qfixed y) |
294 | 212k | { |
295 | 212k | Element e = { QPainterPath::LineToElement, x, y }; |
296 | 212k | m_elements.add(e); |
297 | 212k | } |
298 | | |
299 | | inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey) |
300 | 299k | { |
301 | 299k | Element c1 = { QPainterPath::CurveToElement, x1, y1 }; |
302 | 299k | Element c2 = { QPainterPath::CurveToDataElement, x2, y2 }; |
303 | 299k | Element e = { QPainterPath::CurveToDataElement, ex, ey }; |
304 | 299k | m_elements.add(c1); |
305 | 299k | m_elements.add(c2); |
306 | 299k | m_elements.add(e); |
307 | 299k | } |
308 | | |
309 | | /******************************************************************************* |
310 | | * QStroker inline members |
311 | | */ |
312 | | inline void QStroker::emitMoveTo(qfixed x, qfixed y) |
313 | 128k | { |
314 | 128k | m_back2X = m_back1X; |
315 | 128k | m_back2Y = m_back1Y; |
316 | 128k | m_back1X = x; |
317 | 128k | m_back1Y = y; |
318 | 128k | QStrokerOps::emitMoveTo(x, y); |
319 | 128k | } |
320 | | |
321 | | inline void QStroker::emitLineTo(qfixed x, qfixed y) |
322 | 1.59M | { |
323 | 1.59M | m_back2X = m_back1X; |
324 | 1.59M | m_back2Y = m_back1Y; |
325 | 1.59M | m_back1X = x; |
326 | 1.59M | m_back1Y = y; |
327 | 1.59M | QStrokerOps::emitLineTo(x, y); |
328 | 1.59M | } |
329 | | |
330 | | inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y, |
331 | | qfixed c2x, qfixed c2y, |
332 | | qfixed ex, qfixed ey) |
333 | 1.08M | { |
334 | 1.08M | if (c2x == ex && c2y == ey) { |
335 | 78.0k | if (c1x == ex && c1y == ey) { |
336 | 214 | m_back2X = m_back1X; |
337 | 214 | m_back2Y = m_back1Y; |
338 | 77.7k | } else { |
339 | 77.7k | m_back2X = c1x; |
340 | 77.7k | m_back2Y = c1y; |
341 | 77.7k | } |
342 | 1.00M | } else { |
343 | 1.00M | m_back2X = c2x; |
344 | 1.00M | m_back2Y = c2y; |
345 | 1.00M | } |
346 | 1.08M | m_back1X = ex; |
347 | 1.08M | m_back1Y = ey; |
348 | 1.08M | QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey); |
349 | 1.08M | } |
350 | | |
351 | | /******************************************************************************* |
352 | | * QDashStroker inline members |
353 | | */ |
354 | | inline void QDashStroker::begin(void *data) |
355 | 0 | { |
356 | 0 | if (m_stroker) |
357 | 0 | m_stroker->begin(data); |
358 | 0 | QStrokerOps::begin(data); |
359 | 0 | } |
360 | | |
361 | | inline void QDashStroker::end() |
362 | 0 | { |
363 | 0 | QStrokerOps::end(); |
364 | 0 | if (m_stroker) |
365 | 0 | m_stroker->end(); |
366 | 0 | } |
367 | | |
368 | | QT_END_NAMESPACE |
369 | | |
370 | | #endif // QSTROKER_P_H |