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 | #define qt_real_to_fixed(real) qfixed(real) |
101 | #define qt_fixed_to_real(fixed) fixed |
102 | struct qfixed2d |
103 | { |
104 | qfixed x; |
105 | qfixed y; |
106 | |
107 | bool isFinite() { return qIsFinite(x) && qIsFinite(y); } |
108 | bool operator==(const qfixed2d &other) const { return qFuzzyCompare(x, other.x) |
109 | && qFuzzyCompare(y, other.y); } |
110 | }; |
111 | #endif |
112 | |
113 | #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 | inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; } |
139 | inline bool isLineTo() const { return type == QPainterPath::LineToElement; } |
140 | inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; } |
141 | |
142 | operator qfixed2d () { qfixed2d pt = { x, y }; return pt; } |
143 | }; |
144 | |
145 | QStrokerOps(); |
146 | virtual ~QStrokerOps(); |
147 | |
148 | void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; } |
149 | void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; } |
150 | 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 | QRectF clipRect() const { return m_clip_rect; } |
165 | void setClipRect(const QRectF &clip) { m_clip_rect = clip; } |
166 | |
167 | void setCurveThresholdFromTransform(const QTransform &transform) |
168 | { |
169 | qreal scale; |
170 | qt_scaleForTransform(transform, &scale); |
171 | m_dashThreshold = scale == 0 ? qreal(0.5) : (qreal(0.5) / scale); |
172 | } |
173 | |
174 | void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; } |
175 | 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 | { |
214 | m_strokeWidth = width; |
215 | m_curveThreshold = qt_real_to_fixed(qBound(0.00025, 1.0 / qt_fixed_to_real(width), 0.25)); |
216 | } |
217 | qfixed strokeWidth() const { return m_strokeWidth; } |
218 | |
219 | void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); } |
220 | Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); } |
221 | LineJoinMode capStyleMode() const { return m_capStyle; } |
222 | |
223 | void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); } |
224 | Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); } |
225 | LineJoinMode joinStyleMode() const { return m_joinStyle; } |
226 | |
227 | void setMiterLimit(qfixed length) { m_miterLimit = length; } |
228 | qfixed miterLimit() const { return m_miterLimit; } |
229 | |
230 | void setForceOpen(bool state) { m_forceOpen = state; } |
231 | 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 | QStroker *stroker() const { return m_stroker; } |
269 | |
270 | static QList<qfixed> patternForStyle(Qt::PenStyle style); |
271 | |
272 | void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; } |
273 | QList<qfixed> dashPattern() const { return m_dashPattern; } |
274 | |
275 | void setDashOffset(qreal offset) { m_dashOffset = offset; } |
276 | qreal dashOffset() const { return m_dashOffset; } |
277 | |
278 | void begin(void *data) override; |
279 | void end() override; |
280 | |
281 | inline void setStrokeWidth(qreal width) { m_stroke_width = width; } |
282 | inline void setMiterLimit(qreal limit) { m_miter_limit = limit; } |
283 | |
284 | protected: |
285 | void processCurrentSubpath() override; |
286 | |
287 | QStroker *m_stroker; |
288 | QList<qfixed> m_dashPattern; |
289 | qreal m_dashOffset; |
290 | |
291 | qreal m_stroke_width; |
292 | qreal m_miter_limit; |
293 | }; |
294 | |
295 | |
296 | /******************************************************************************* |
297 | * QStrokerOps inline membmers |
298 | */ |
299 | |
300 | inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y) |
301 | { |
302 | Q_ASSERT(m_moveTo); |
303 | m_moveTo(x, y, m_customData); |
304 | } |
305 | |
306 | inline void QStrokerOps::emitLineTo(qfixed x, qfixed y) |
307 | { |
308 | Q_ASSERT(m_lineTo); |
309 | m_lineTo(x, y, m_customData); |
310 | } |
311 | |
312 | inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey) |
313 | { |
314 | Q_ASSERT(m_cubicTo); |
315 | m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData); |
316 | } |
317 | |
318 | inline void QStrokerOps::moveTo(qfixed x, qfixed y) |
319 | { |
320 | if (m_elements.size()>1) |
321 | processCurrentSubpath(); |
322 | m_elements.reset(); |
323 | Element e = { QPainterPath::MoveToElement, x, y }; |
324 | m_elements.add(e); |
325 | } |
326 | |
327 | inline void QStrokerOps::lineTo(qfixed x, qfixed y) |
328 | { |
329 | Element e = { QPainterPath::LineToElement, x, y }; |
330 | m_elements.add(e); |
331 | } |
332 | |
333 | inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey) |
334 | { |
335 | Element c1 = { QPainterPath::CurveToElement, x1, y1 }; |
336 | Element c2 = { QPainterPath::CurveToDataElement, x2, y2 }; |
337 | Element e = { QPainterPath::CurveToDataElement, ex, ey }; |
338 | m_elements.add(c1); |
339 | m_elements.add(c2); |
340 | m_elements.add(e); |
341 | } |
342 | |
343 | /******************************************************************************* |
344 | * QStroker inline members |
345 | */ |
346 | inline void QStroker::emitMoveTo(qfixed x, qfixed y) |
347 | { |
348 | m_back2X = m_back1X; |
349 | m_back2Y = m_back1Y; |
350 | m_back1X = x; |
351 | m_back1Y = y; |
352 | QStrokerOps::emitMoveTo(x, y); |
353 | } |
354 | |
355 | inline void QStroker::emitLineTo(qfixed x, qfixed y) |
356 | { |
357 | m_back2X = m_back1X; |
358 | m_back2Y = m_back1Y; |
359 | m_back1X = x; |
360 | m_back1Y = y; |
361 | QStrokerOps::emitLineTo(x, y); |
362 | } |
363 | |
364 | inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y, |
365 | qfixed c2x, qfixed c2y, |
366 | qfixed ex, qfixed ey) |
367 | { |
368 | if (c2x == ex && c2y == ey) { |
369 | if (c1x == ex && c1y == ey) { |
370 | m_back2X = m_back1X; |
371 | m_back2Y = m_back1Y; |
372 | } else { |
373 | m_back2X = c1x; |
374 | m_back2Y = c1y; |
375 | } |
376 | } else { |
377 | m_back2X = c2x; |
378 | m_back2Y = c2y; |
379 | } |
380 | m_back1X = ex; |
381 | m_back1Y = ey; |
382 | QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey); |
383 | } |
384 | |
385 | /******************************************************************************* |
386 | * QDashStroker inline members |
387 | */ |
388 | inline void QDashStroker::begin(void *data) |
389 | { |
390 | if (m_stroker) |
391 | m_stroker->begin(data); |
392 | QStrokerOps::begin(data); |
393 | } |
394 | |
395 | inline void QDashStroker::end() |
396 | { |
397 | QStrokerOps::end(); |
398 | if (m_stroker) |
399 | m_stroker->end(); |
400 | } |
401 | |
402 | QT_END_NAMESPACE |
403 | |
404 | #endif // QSTROKER_P_H |
405 | |