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