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 
isMoveToElement138         inline bool isMoveTo() const { return type == QPainterPath::MoveToElement; }
isLineToElement139         inline bool isLineTo() const { return type == QPainterPath::LineToElement; }
isCurveToElement140         inline bool isCurveTo() const { return type == QPainterPath::CurveToElement; }
141 
qfixed2dElement142         operator qfixed2d () { qfixed2d pt = { x, y }; return pt; }
143     };
144 
145     QStrokerOps();
146     virtual ~QStrokerOps();
147 
setMoveToHook(qStrokerMoveToHook moveToHook)148     void setMoveToHook(qStrokerMoveToHook moveToHook) { m_moveTo = moveToHook; }
setLineToHook(qStrokerLineToHook lineToHook)149     void setLineToHook(qStrokerLineToHook lineToHook) { m_lineTo = lineToHook; }
setCubicToHook(qStrokerCubicToHook cubicToHook)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 
clipRect()164     QRectF clipRect() const { return m_clip_rect; }
setClipRect(const QRectF & clip)165     void setClipRect(const QRectF &clip) { m_clip_rect = clip; }
166 
setCurveThresholdFromTransform(const QTransform & transform)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 
setCurveThreshold(qfixed threshold)174     void setCurveThreshold(qfixed threshold) { m_curveThreshold = threshold; }
curveThreshold()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 
setStrokeWidth(qfixed width)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     }
strokeWidth()217     qfixed strokeWidth() const { return m_strokeWidth; }
218 
setCapStyle(Qt::PenCapStyle capStyle)219     void setCapStyle(Qt::PenCapStyle capStyle) { m_capStyle = joinModeForCap(capStyle); }
capStyle()220     Qt::PenCapStyle capStyle() const { return capForJoinMode(m_capStyle); }
capStyleMode()221     LineJoinMode capStyleMode() const { return m_capStyle; }
222 
setJoinStyle(Qt::PenJoinStyle style)223     void setJoinStyle(Qt::PenJoinStyle style) { m_joinStyle = joinModeForJoin(style); }
joinStyle()224     Qt::PenJoinStyle joinStyle() const { return joinForJoinMode(m_joinStyle); }
joinStyleMode()225     LineJoinMode joinStyleMode() const { return m_joinStyle; }
226 
setMiterLimit(qfixed length)227     void setMiterLimit(qfixed length) { m_miterLimit = length; }
miterLimit()228     qfixed miterLimit() const { return m_miterLimit; }
229 
setForceOpen(bool state)230     void setForceOpen(bool state) { m_forceOpen = state; }
forceOpen()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 
stroker()268     QStroker *stroker() const { return m_stroker; }
269 
270     static QVector<qfixed> patternForStyle(Qt::PenStyle style);
271 
setDashPattern(const QVector<qfixed> & dashPattern)272     void setDashPattern(const QVector<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
dashPattern()273     QVector<qfixed> dashPattern() const { return m_dashPattern; }
274 
setDashOffset(qreal offset)275     void setDashOffset(qreal offset) { m_dashOffset = offset; }
dashOffset()276     qreal dashOffset() const { return m_dashOffset; }
277 
278     void begin(void *data) override;
279     void end() override;
280 
setStrokeWidth(qreal width)281     inline void setStrokeWidth(qreal width) { m_stroke_width = width; }
setMiterLimit(qreal limit)282     inline void setMiterLimit(qreal limit) { m_miter_limit = limit; }
283 
284 protected:
285     void processCurrentSubpath() override;
286 
287     QStroker *m_stroker;
288     QVector<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 
emitMoveTo(qfixed x,qfixed y)300 inline void QStrokerOps::emitMoveTo(qfixed x, qfixed y)
301 {
302     Q_ASSERT(m_moveTo);
303     m_moveTo(x, y, m_customData);
304 }
305 
emitLineTo(qfixed x,qfixed y)306 inline void QStrokerOps::emitLineTo(qfixed x, qfixed y)
307 {
308     Q_ASSERT(m_lineTo);
309     m_lineTo(x, y, m_customData);
310 }
311 
emitCubicTo(qfixed c1x,qfixed c1y,qfixed c2x,qfixed c2y,qfixed ex,qfixed ey)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 
moveTo(qfixed x,qfixed y)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 
lineTo(qfixed x,qfixed y)327 inline void QStrokerOps::lineTo(qfixed x, qfixed y)
328 {
329     Element e = { QPainterPath::LineToElement, x, y };
330     m_elements.add(e);
331 }
332 
cubicTo(qfixed x1,qfixed y1,qfixed x2,qfixed y2,qfixed ex,qfixed ey)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  */
emitMoveTo(qfixed x,qfixed y)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 
emitLineTo(qfixed x,qfixed y)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 
emitCubicTo(qfixed c1x,qfixed c1y,qfixed c2x,qfixed c2y,qfixed ex,qfixed ey)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  */
begin(void * data)388 inline void QDashStroker::begin(void *data)
389 {
390     if (m_stroker)
391         m_stroker->begin(data);
392     QStrokerOps::begin(data);
393 }
394 
end()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