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
59QT_BEGIN_NAMESPACE
60
61// #define QFIXED_IS_26_6
62
63#if defined QFIXED_IS_26_6
64typedef 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)
69struct 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
77typedef 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))
80struct 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
88typedef 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))
91struct 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
99typedef qreal qfixed;
100#define qt_real_to_fixed(real) qfixed(real)
101#define qt_fixed_to_real(fixed) fixed
102struct qfixed2d
103{
104 qfixed x;
105 qfixed y;
106
107 bool isFinite() { return qIsFinite(d: x) && qIsFinite(d: y); }
108 bool operator==(const qfixed2d &other) const { return qFuzzyCompare(p1: x, p2: other.x)
109 && qFuzzyCompare(p1: y, p2: other.y); }
110};
111#endif
112
113#define QT_PATH_KAPPA 0.5522847498
114
115QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
116 QPointF *controlPoints, int *point_count);
117
118qreal qt_t_for_arc_angle(qreal angle);
119
120typedef void (*qStrokerMoveToHook)(qfixed x, qfixed y, void *data);
121typedef void (*qStrokerLineToHook)(qfixed x, qfixed y, void *data);
122typedef void (*qStrokerCubicToHook)(qfixed c1x, qfixed c1y,
123 qfixed c2x, qfixed c2y,
124 qfixed ex, qfixed ey,
125 void *data);
126
127// qtransform.cpp
128Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
129
130class Q_GUI_EXPORT QStrokerOps
131{
132public:
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: x, .y: 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: &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
177protected:
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
196class Q_GUI_EXPORT QStroker : public QStrokerOps
197{
198public:
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(mode: m_capStyle); }
221 LineJoinMode capStyleMode() const { return m_capStyle; }
222
223 void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(joinStyle: style); }
224 Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(mode: 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
238protected:
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
262class Q_GUI_EXPORT QDashStroker : public QStrokerOps
263{
264public:
265 QDashStroker(QStroker *stroker);
266 ~QDashStroker();
267
268 QStroker *stroker() const { return m_stroker; }
269
270 static QVector<qfixed> patternForStyle(Qt::PenStyle style);
271 static int repetitionLimit() { return 10000; }
272
273 void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
274 QVector<qfixed> dashPattern() const { return m_dashPattern; }
275
276 void setDashOffset(qreal offset) { m_dashOffset = offset; }
277 qreal dashOffset() const { return m_dashOffset; }
278
279 void begin(void *data) override;
280 void end() override;
281
282 inline void setStrokeWidth(qreal width) { m_stroke_width = width; }
283 inline void setMiterLimit(qreal limit) { m_miter_limit = limit; }
284
285protected:
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
301inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y)
302{
303 Q_ASSERT(m_moveTo);
304 m_moveTo(x, y, m_customData);
305}
306
307inline void QStrokerOps::emitLineTo(qfixed x, qfixed y)
308{
309 Q_ASSERT(m_lineTo);
310 m_lineTo(x, y, m_customData);
311}
312
313inline void QStrokerOps::emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey)
314{
315 Q_ASSERT(m_cubicTo);
316 m_cubicTo(c1x, c1y, c2x, c2y, ex, ey, m_customData);
317}
318
319inline void QStrokerOps::moveTo(qfixed x, qfixed y)
320{
321 if (m_elements.size()>1)
322 processCurrentSubpath();
323 m_elements.reset();
324 Element e = { .type: QPainterPath::MoveToElement, .x: x, .y: y };
325 m_elements.add(t: e);
326}
327
328inline void QStrokerOps::lineTo(qfixed x, qfixed y)
329{
330 Element e = { .type: QPainterPath::LineToElement, .x: x, .y: y };
331 m_elements.add(t: e);
332}
333
334inline void QStrokerOps::cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey)
335{
336 Element c1 = { .type: QPainterPath::CurveToElement, .x: x1, .y: y1 };
337 Element c2 = { .type: QPainterPath::CurveToDataElement, .x: x2, .y: y2 };
338 Element e = { .type: QPainterPath::CurveToDataElement, .x: ex, .y: ey };
339 m_elements.add(t: c1);
340 m_elements.add(t: c2);
341 m_elements.add(t: e);
342}
343
344/*******************************************************************************
345 * QStroker inline members
346 */
347inline void QStroker::emitMoveTo(qfixed x, qfixed y)
348{
349 m_back2X = m_back1X;
350 m_back2Y = m_back1Y;
351 m_back1X = x;
352 m_back1Y = y;
353 QStrokerOps::emitMoveTo(x, y);
354}
355
356inline void QStroker::emitLineTo(qfixed x, qfixed y)
357{
358 m_back2X = m_back1X;
359 m_back2Y = m_back1Y;
360 m_back1X = x;
361 m_back1Y = y;
362 QStrokerOps::emitLineTo(x, y);
363}
364
365inline void QStroker::emitCubicTo(qfixed c1x, qfixed c1y,
366 qfixed c2x, qfixed c2y,
367 qfixed ex, qfixed ey)
368{
369 if (c2x == ex && c2y == ey) {
370 if (c1x == ex && c1y == ey) {
371 m_back2X = m_back1X;
372 m_back2Y = m_back1Y;
373 } else {
374 m_back2X = c1x;
375 m_back2Y = c1y;
376 }
377 } else {
378 m_back2X = c2x;
379 m_back2Y = c2y;
380 }
381 m_back1X = ex;
382 m_back1Y = ey;
383 QStrokerOps::emitCubicTo(c1x, c1y, c2x, c2y, ex, ey);
384}
385
386/*******************************************************************************
387 * QDashStroker inline members
388 */
389inline void QDashStroker::begin(void *data)
390{
391 if (m_stroker)
392 m_stroker->begin(customData: data);
393 QStrokerOps::begin(customData: data);
394}
395
396inline void QDashStroker::end()
397{
398 QStrokerOps::end();
399 if (m_stroker)
400 m_stroker->end();
401}
402
403QT_END_NAMESPACE
404
405#endif // QSTROKER_P_H
406

source code of qtbase/src/gui/painting/qstroker_p.h