/src/qtbase/src/gui/painting/qstroker_p.h
Line | Count | Source |
1 | | /**************************************************************************** |
2 | | ** |
3 | | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | | ** Contact: https://www.qt.io/licensing/ |
5 | | ** |
6 | | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | | ** |
8 | | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | | ** Commercial License Usage |
10 | | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | | ** accordance with the commercial license agreement provided with the |
12 | | ** Software or, alternatively, in accordance with the terms contained in |
13 | | ** a written agreement between you and The Qt Company. For licensing terms |
14 | | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | | ** information use the contact form at https://www.qt.io/contact-us. |
16 | | ** |
17 | | ** GNU Lesser General Public License Usage |
18 | | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | | ** General Public License version 3 as published by the Free Software |
20 | | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | | ** packaging of this file. Please review the following information to |
22 | | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | | ** |
25 | | ** GNU General Public License Usage |
26 | | ** Alternatively, this file may be used under the terms of the GNU |
27 | | ** General Public License version 2.0 or (at your option) the GNU General |
28 | | ** Public license version 3 or any later version approved by the KDE Free |
29 | | ** Qt Foundation. The licenses are as published by the Free Software |
30 | | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | | ** included in the packaging of this file. Please review the following |
32 | | ** information to ensure the GNU General Public License requirements will |
33 | | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | | ** |
36 | | ** $QT_END_LICENSE$ |
37 | | ** |
38 | | ****************************************************************************/ |
39 | | |
40 | | #ifndef QSTROKER_P_H |
41 | | #define QSTROKER_P_H |
42 | | |
43 | | // |
44 | | // W A R N I N G |
45 | | // ------------- |
46 | | // |
47 | | // This file is not part of the Qt API. It exists purely as an |
48 | | // implementation detail. This header file may change from version to |
49 | | // version without notice, or even be removed. |
50 | | // |
51 | | // We mean it. |
52 | | // |
53 | | |
54 | | #include <QtGui/private/qtguiglobal_p.h> |
55 | | #include "QtGui/qpainterpath.h" |
56 | | #include "private/qdatabuffer_p.h" |
57 | | #include "private/qnumeric_p.h" |
58 | | |
59 | | QT_BEGIN_NAMESPACE |
60 | | |
61 | | // #define QFIXED_IS_26_6 |
62 | | |
63 | | #if defined QFIXED_IS_26_6 |
64 | | typedef int qfixed; |
65 | | #define qt_real_to_fixed(real) qfixed(real * 64) |
66 | | #define qt_int_to_fixed(real) qfixed(int(real) << 6) |
67 | | #define qt_fixed_to_real(fixed) qreal(fixed / qreal(64)) |
68 | | #define qt_fixed_to_int(fixed) int(fixed >> 6) |
69 | | struct qfixed2d |
70 | | { |
71 | | qfixed x; |
72 | | qfixed y; |
73 | | |
74 | | bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
75 | | }; |
76 | | #elif defined QFIXED_IS_32_32 |
77 | | typedef qint64 qfixed; |
78 | | #define qt_real_to_fixed(real) qfixed(real * double(qint64(1) << 32)) |
79 | | #define qt_fixed_to_real(fixed) qreal(fixed / double(qint64(1) << 32)) |
80 | | struct qfixed2d |
81 | | { |
82 | | qfixed x; |
83 | | qfixed y; |
84 | | |
85 | | bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
86 | | }; |
87 | | #elif defined QFIXED_IS_16_16 |
88 | | typedef int qfixed; |
89 | | #define qt_real_to_fixed(real) qfixed(real * qreal(1 << 16)) |
90 | | #define qt_fixed_to_real(fixed) qreal(fixed / qreal(1 << 16)) |
91 | | struct qfixed2d |
92 | | { |
93 | | qfixed x; |
94 | | qfixed y; |
95 | | |
96 | | bool operator==(const qfixed2d &other) const { return x == other.x && y == other.y; } |
97 | | }; |
98 | | #else |
99 | | typedef qreal qfixed; |
100 | 154k | #define qt_real_to_fixed(real) qfixed(real) |
101 | 0 | #define qt_fixed_to_real(fixed) fixed |
102 | | struct qfixed2d |
103 | | { |
104 | | qfixed x; |
105 | | qfixed y; |
106 | | |
107 | 0 | bool isFinite() { return qIsFinite(x) && qIsFinite(y); } |
108 | 0 | bool operator==(const qfixed2d &other) const { return qFuzzyCompare(x, other.x) |
109 | 0 | && qFuzzyCompare(y, other.y); } |
110 | | }; |
111 | | #endif |
112 | | |
113 | 0 | #define QT_PATH_KAPPA 0.5522847498 |
114 | | |
115 | | QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, |
116 | | QPointF *controlPoints, int *point_count); |
117 | | |
118 | | qreal qt_t_for_arc_angle(qreal angle); |
119 | | |
120 | | typedef void (*qStrokerMoveToHook)(qfixed x, qfixed y, void *data); |
121 | | typedef void (*qStrokerLineToHook)(qfixed x, qfixed y, void *data); |
122 | | typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y, |
123 | | qfixed c2x, qfixed c2y, |
124 | | qfixed ex, qfixed ey, |
125 | | void *data); |
126 | | |
127 | | // qtransform.cpp |
128 | | Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); |
129 | | |
130 | | class Q_GUI_EXPORT QStrokerOps |
131 | | { |
132 | | public: |
133 | | struct Element { |
134 | | QPainterPath::ElementType type; |
135 | | qfixed x; |
136 | | qfixed y; |
137 | | |
138 | 0 | inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; } |
139 | 0 | inline bool isLineTo() const { return type == QPainterPath::LineToElement; } |
140 | 0 | inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; } |
141 | | |
142 | 0 | operator qfixed2d () { qfixed2d pt = { x, y }; return pt; } |
143 | | }; |
144 | | |
145 | | QStrokerOps(); |
146 | | virtual ~QStrokerOps(); |
147 | | |
148 | 28.0k | void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; } |
149 | 28.0k | void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; } |
150 | 28.0k | void setCubicToHook(qStrokerCubicToHook cubicToHook) { m_cubicTo = cubicToHook; } |
151 | | |
152 | | virtual void begin(void *customData); |
153 | | virtual void end(); |
154 | | |
155 | | inline void moveTo(qfixed x, qfixed y); |
156 | | inline void lineTo(qfixed x, qfixed y); |
157 | | inline void cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey); |
158 | | |
159 | | void strokePath(const QPainterPath &path, void *data, const QTransform &matrix); |
160 | | void strokePolygon(const QPointF *points, int pointCount, bool implicit_close, |
161 | | void *data, const QTransform &matrix); |
162 | | void strokeEllipse(const QRectF &ellipse, void *data, const QTransform &matrix); |
163 | | |
164 | 0 | QRectF clipRect() const { return m_clip_rect; } |
165 | 14.0k | void setClipRect(const QRectF &clip) { m_clip_rect = clip; } |
166 | | |
167 | | void setCurveThresholdFromTransform(const QTransform &transform) |
168 | 0 | { |
169 | 0 | qreal scale; |
170 | 0 | qt_scaleForTransform(transform, &scale); |
171 | 0 | m_dashThreshold = scale == 0 ? qreal(0.5) : (qreal(0.5) / scale); |
172 | 0 | } |
173 | | |
174 | 0 | void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } |
175 | 0 | qfixed curveThreshold() const { return m_curveThreshold; } |
176 | | |
177 | | protected: |
178 | | inline void emitMoveTo(qfixed x, qfixed y); |
179 | | inline void emitLineTo(qfixed x, qfixed y); |
180 | | inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
181 | | |
182 | | virtual void processCurrentSubpath() = 0; |
183 | | QDataBuffer<Element> m_elements; |
184 | | |
185 | | QRectF m_clip_rect; |
186 | | qfixed m_curveThreshold; |
187 | | qfixed m_dashThreshold; |
188 | | |
189 | | void *m_customData; |
190 | | qStrokerMoveToHook m_moveTo; |
191 | | qStrokerLineToHook m_lineTo; |
192 | | qStrokerCubicToHook m_cubicTo; |
193 | | |
194 | | }; |
195 | | |
196 | | class Q_GUI_EXPORT QStroker : public QStrokerOps |
197 | | { |
198 | | public: |
199 | | |
200 | | enum LineJoinMode { |
201 | | FlatJoin, |
202 | | SquareJoin, |
203 | | MiterJoin, |
204 | | RoundJoin, |
205 | | RoundCap, |
206 | | SvgMiterJoin |
207 | | }; |
208 | | |
209 | | QStroker(); |
210 | | ~QStroker(); |
211 | | |
212 | | void setStrokeWidth(qfixed width) |
213 | 14.0k | { |
214 | 14.0k | m_strokeWidth = width; |
215 | 14.0k | m_curveThreshold = qt_real_to_fixed(qBound(0.00025, 1.0 / qt_fixed_to_real(width), 0.25)); |
216 | 14.0k | } |
217 | 0 | qfixed strokeWidth() const { return m_strokeWidth; } |
218 | | |
219 | 14.0k | void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); } |
220 | 0 | Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); } |
221 | 0 | LineJoinMode capStyleMode() const { return m_capStyle; } |
222 | | |
223 | 14.0k | void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); } |
224 | 0 | Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); } |
225 | 0 | LineJoinMode joinStyleMode() const { return m_joinStyle; } |
226 | | |
227 | 14.0k | void setMiterLimit(qfixed length) { m_miterLimit = length; } |
228 | 0 | qfixed miterLimit() const { return m_miterLimit; } |
229 | | |
230 | 0 | void setForceOpen(bool state) { m_forceOpen = state; } |
231 | 0 | bool forceOpen() { return m_forceOpen; } |
232 | | |
233 | | void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join); |
234 | | inline void emitMoveTo(qfixed x, qfixed y); |
235 | | inline void emitLineTo(qfixed x, qfixed y); |
236 | | inline void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey); |
237 | | |
238 | | protected: |
239 | | static Qt::PenCapStyle capForJoinMode(LineJoinMode mode); |
240 | | static LineJoinMode joinModeForCap(Qt::PenCapStyle); |
241 | | |
242 | | static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode); |
243 | | static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle); |
244 | | |
245 | | void processCurrentSubpath() override; |
246 | | |
247 | | qfixed m_strokeWidth; |
248 | | qfixed m_miterLimit; |
249 | | |
250 | | LineJoinMode m_capStyle; |
251 | | LineJoinMode m_joinStyle; |
252 | | |
253 | | qfixed m_back1X; |
254 | | qfixed m_back1Y; |
255 | | |
256 | | qfixed m_back2X; |
257 | | qfixed m_back2Y; |
258 | | |
259 | | bool m_forceOpen; |
260 | | }; |
261 | | |
262 | | class Q_GUI_EXPORT QDashStroker : public QStrokerOps |
263 | | { |
264 | | public: |
265 | | QDashStroker(QStroker *stroker); |
266 | | ~QDashStroker(); |
267 | | |
268 | 0 | QStroker *stroker() const { return m_stroker; } |
269 | | |
270 | | static QVector<qfixed> patternForStyle(Qt::PenStyle style); |
271 | 0 | static int repetitionLimit() { return 10000; } |
272 | | |
273 | 0 | void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; } |
274 | 0 | QVector<qfixed> dashPattern() const { return m_dashPattern; } |
275 | | |
276 | 0 | void setDashOffset(qreal offset) { m_dashOffset = offset; } |
277 | 0 | qreal dashOffset() const { return m_dashOffset; } |
278 | | |
279 | | void begin(void *data) override; |
280 | | void end() override; |
281 | | |
282 | 0 | inline void setStrokeWidth(qreal width) { m_stroke_width = width; } |
283 | 0 | inline void setMiterLimit(qreal limit) { m_miter_limit = limit; } |
284 | | |
285 | | protected: |
286 | | void processCurrentSubpath() override; |
287 | | |
288 | | QStroker *m_stroker; |
289 | | QVector<qfixed> m_dashPattern; |
290 | | qreal m_dashOffset; |
291 | | |
292 | | qreal m_stroke_width; |
293 | | qreal m_miter_limit; |
294 | | }; |
295 | | |
296 | | |
297 | | /******************************************************************************* |
298 | | * QStrokerOps inline membmers |
299 | | */ |
300 | | |
301 | | inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y) |
302 | 0 | { |
303 | 0 | Q_ASSERT(m_moveTo); |
304 | 0 | m_moveTo(x, y, m_customData); |
305 | 0 | } |
306 | | |
307 | | inline void QStrokerOps::emitLineTo(qfixed x, qfixed y) |
308 | 0 | { |
309 | 0 | Q_ASSERT(m_lineTo); |
310 | 0 | m_lineTo(x, y, m_customData); |
311 | 0 | } |
312 | | |
313 | | inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey) |
314 | 0 | { |
315 | 0 | Q_ASSERT(m_cubicTo); |
316 | 0 | m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData); |
317 | 0 | } |
318 | | |
319 | | inline void QStrokerOps::moveTo(qfixed x, qfixed y) |
320 | 0 | { |
321 | 0 | if (m_elements.size()>1) |
322 | 0 | processCurrentSubpath(); |
323 | 0 | m_elements.reset(); |
324 | 0 | Element e = { QPainterPath::MoveToElement, x, y }; |
325 | 0 | m_elements.add(e); |
326 | 0 | } |
327 | | |
328 | | inline void QStrokerOps::lineTo(qfixed x, qfixed y) |
329 | 0 | { |
330 | 0 | Element e = { QPainterPath::LineToElement, x, y }; |
331 | 0 | m_elements.add(e); |
332 | 0 | } |
333 | | |
334 | | inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey) |
335 | 0 | { |
336 | 0 | Element c1 = { QPainterPath::CurveToElement, x1, y1 }; |
337 | 0 | Element c2 = { QPainterPath::CurveToDataElement, x2, y2 }; |
338 | 0 | Element e = { QPainterPath::CurveToDataElement, ex, ey }; |
339 | 0 | m_elements.add(c1); |
340 | 0 | m_elements.add(c2); |
341 | 0 | m_elements.add(e); |
342 | 0 | } |
343 | | |
344 | | /******************************************************************************* |
345 | | * QStroker inline members |
346 | | */ |
347 | | inline void QStroker::emitMoveTo(qfixed x, qfixed y) |
348 | 0 | { |
349 | 0 | m_back2X = m_back1X; |
350 | 0 | m_back2Y = m_back1Y; |
351 | 0 | m_back1X = x; |
352 | 0 | m_back1Y = y; |
353 | 0 | QStrokerOps::emitMoveTo(x, y); |
354 | 0 | } |
355 | | |
356 | | inline void QStroker::emitLineTo(qfixed x, qfixed y) |
357 | 0 | { |
358 | 0 | m_back2X = m_back1X; |
359 | 0 | m_back2Y = m_back1Y; |
360 | 0 | m_back1X = x; |
361 | 0 | m_back1Y = y; |
362 | 0 | QStrokerOps::emitLineTo(x, y); |
363 | 0 | } |
364 | | |
365 | | inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y, |
366 | | qfixed c2x, qfixed c2y, |
367 | | qfixed ex, qfixed ey) |
368 | 0 | { |
369 | 0 | if (c2x == ex && c2y == ey) { |
370 | 0 | if (c1x == ex && c1y == ey) { |
371 | 0 | m_back2X = m_back1X; |
372 | 0 | m_back2Y = m_back1Y; |
373 | 0 | } else { |
374 | 0 | m_back2X = c1x; |
375 | 0 | m_back2Y = c1y; |
376 | 0 | } |
377 | 0 | } else { |
378 | 0 | m_back2X = c2x; |
379 | 0 | m_back2Y = c2y; |
380 | 0 | } |
381 | 0 | m_back1X = ex; |
382 | 0 | m_back1Y = ey; |
383 | 0 | QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey); |
384 | 0 | } |
385 | | |
386 | | /******************************************************************************* |
387 | | * QDashStroker inline members |
388 | | */ |
389 | | inline void QDashStroker::begin(void *data) |
390 | 0 | { |
391 | 0 | if (m_stroker) |
392 | 0 | m_stroker->begin(data); |
393 | 0 | QStrokerOps::begin(data); |
394 | 0 | } |
395 | | |
396 | | inline void QDashStroker::end() |
397 | 0 | { |
398 | 0 | QStrokerOps::end(); |
399 | 0 | if (m_stroker) |
400 | 0 | m_stroker->end(); |
401 | 0 | } |
402 | | |
403 | | QT_END_NAMESPACE |
404 | | |
405 | | #endif // QSTROKER_P_H |