qstroker.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/painting/qstroker.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
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#include "private/qstroker_p.h"-
41#include "private/qbezier_p.h"-
42#include "qline.h"-
43#include "qtransform.h"-
44#include <qmath.h>-
45-
46QT_BEGIN_NAMESPACE-
47-
48// #define QPP_STROKE_DEBUG-
49-
50class QSubpathForwardIterator-
51{-
52public:-
53 QSubpathForwardIterator(const QDataBuffer<QStrokerOps::Element> *path)-
54 : m_path(path), m_pos(0) { }
never executed: end of block
0
55 inline int position() const { return m_pos; }
never executed: return m_pos;
0
56 inline bool hasNext() const { return m_pos < m_path->size(); }
never executed: return m_pos < m_path->size();
0
57 inline QStrokerOps::Element next() { Q_ASSERT(hasNext()); return m_path->at(m_pos++); }
never executed: return m_path->at(m_pos++);
0
58-
59private:-
60 const QDataBuffer<QStrokerOps::Element> *m_path;-
61 int m_pos;-
62};-
63-
64class QSubpathBackwardIterator-
65{-
66public:-
67 QSubpathBackwardIterator(const QDataBuffer<QStrokerOps::Element> *path)-
68 : m_path(path), m_pos(path->size() - 1) { }
never executed: end of block
0
69-
70 inline int position() const { return m_pos; }
never executed: return m_pos;
0
71-
72 inline bool hasNext() const { return m_pos >= 0; }
never executed: return m_pos >= 0;
0
73-
74 inline QStrokerOps::Element next()-
75 {-
76 Q_ASSERT(hasNext());-
77-
78 QStrokerOps::Element ce = m_path->at(m_pos); // current element-
79-
80 if (m_pos == m_path->size() - 1) {
m_pos == m_path->size() - 1Description
TRUEnever evaluated
FALSEnever evaluated
0
81 --m_pos;-
82 ce.type = QPainterPath::MoveToElement;-
83 return ce;
never executed: return ce;
0
84 }-
85-
86 const QStrokerOps::Element &pe = m_path->at(m_pos + 1); // previous element-
87-
88 switch (pe.type) {-
89 case QPainterPath::LineToElement:
never executed: case QPainterPath::LineToElement:
0
90 ce.type = QPainterPath::LineToElement;-
91 break;
never executed: break;
0
92 case QPainterPath::CurveToDataElement:
never executed: case QPainterPath::CurveToDataElement:
0
93 // First control point?-
94 if (ce.type == QPainterPath::CurveToElement) {
ce.type == QPa...CurveToElementDescription
TRUEnever evaluated
FALSEnever evaluated
0
95 ce.type = QPainterPath::CurveToDataElement;-
96 } else { // Second control point then
never executed: end of block
0
97 ce.type = QPainterPath::CurveToElement;-
98 }
never executed: end of block
0
99 break;
never executed: break;
0
100 case QPainterPath::CurveToElement:
never executed: case QPainterPath::CurveToElement:
0
101 ce.type = QPainterPath::CurveToDataElement;-
102 break;
never executed: break;
0
103 default:
never executed: default:
0
104 qWarning("QSubpathReverseIterator::next: Case %d unhandled", ce.type);-
105 break;
never executed: break;
0
106 }-
107 --m_pos;-
108-
109 return ce;
never executed: return ce;
0
110 }-
111-
112private:-
113 const QDataBuffer<QStrokerOps::Element> *m_path;-
114 int m_pos;-
115};-
116-
117class QSubpathFlatIterator-
118{-
119public:-
120 QSubpathFlatIterator(const QDataBuffer<QStrokerOps::Element> *path, qreal threshold)-
121 : m_path(path), m_pos(0), m_curve_index(-1), m_curve_threshold(threshold) { }
never executed: end of block
0
122-
123 inline bool hasNext() const { return m_curve_index >= 0 || m_pos < m_path->size(); }
never executed: return m_curve_index >= 0 || m_pos < m_path->size();
0
124-
125 QStrokerOps::Element next()-
126 {-
127 Q_ASSERT(hasNext());-
128-
129 if (m_curve_index >= 0) {
m_curve_index >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
130 QStrokerOps::Element e = { QPainterPath::LineToElement,-
131 qt_real_to_fixed(m_curve.at(m_curve_index).x()),-
132 qt_real_to_fixed(m_curve.at(m_curve_index).y())-
133 };-
134 ++m_curve_index;-
135 if (m_curve_index >= m_curve.size())
m_curve_index ...m_curve.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
136 m_curve_index = -1;
never executed: m_curve_index = -1;
0
137 return e;
never executed: return e;
0
138 }-
139-
140 QStrokerOps::Element e = m_path->at(m_pos);-
141 if (e.isCurveTo()) {
e.isCurveTo()Description
TRUEnever evaluated
FALSEnever evaluated
0
142 Q_ASSERT(m_pos > 0);-
143 Q_ASSERT(m_pos < m_path->size());-
144-
145 m_curve = QBezier::fromPoints(QPointF(qt_fixed_to_real(m_path->at(m_pos-1).x),-
146 qt_fixed_to_real(m_path->at(m_pos-1).y)),-
147 QPointF(qt_fixed_to_real(e.x),-
148 qt_fixed_to_real(e.y)),-
149 QPointF(qt_fixed_to_real(m_path->at(m_pos+1).x),-
150 qt_fixed_to_real(m_path->at(m_pos+1).y)),-
151 QPointF(qt_fixed_to_real(m_path->at(m_pos+2).x),-
152 qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(m_curve_threshold);-
153 m_curve_index = 1;-
154 e.type = QPainterPath::LineToElement;-
155 e.x = m_curve.at(0).x();-
156 e.y = m_curve.at(0).y();-
157 m_pos += 2;-
158 }
never executed: end of block
0
159 Q_ASSERT(e.isLineTo() || e.isMoveTo());-
160 ++m_pos;-
161 return e;
never executed: return e;
0
162 }-
163-
164private:-
165 const QDataBuffer<QStrokerOps::Element> *m_path;-
166 int m_pos;-
167 QPolygonF m_curve;-
168 int m_curve_index;-
169 qreal m_curve_threshold;-
170};-
171-
172template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker,-
173 bool capFirst, QLineF *startTangent);-
174-
175/*******************************************************************************-
176 * QLineF::angle gives us the smalles angle between two lines. Here we-
177 * want to identify the line's angle direction on the unit circle.-
178 */-
179static inline qreal adapted_angle_on_x(const QLineF &line)-
180{-
181 qreal angle = line.angle(QLineF(0, 0, 1, 0));-
182 if (line.dy() > 0)
line.dy() > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
183 angle = 360 - angle;
never executed: angle = 360 - angle;
0
184 return angle;
never executed: return angle;
0
185}-
186-
187QStrokerOps::QStrokerOps()-
188 : m_elements(0)-
189 , m_curveThreshold(qt_real_to_fixed(0.25))-
190 , m_dashThreshold(qt_real_to_fixed(0.25))-
191 , m_customData(0)-
192 , m_moveTo(0)-
193 , m_lineTo(0)-
194 , m_cubicTo(0)-
195{-
196}
never executed: end of block
0
197-
198QStrokerOps::~QStrokerOps()-
199{-
200}-
201-
202/*!-
203 Prepares the stroker. Call this function once before starting a-
204 stroke by calling moveTo, lineTo or cubicTo.-
205-
206 The \a customData is passed back through that callback functions-
207 and can be used by the user to for instance maintain state-
208 information.-
209*/-
210void QStrokerOps::begin(void *customData)-
211{-
212 m_customData = customData;-
213 m_elements.reset();-
214}
never executed: end of block
0
215-
216-
217/*!-
218 Finishes the stroke. Call this function once when an entire-
219 primitive has been stroked.-
220*/-
221void QStrokerOps::end()-
222{-
223 if (m_elements.size() > 1)
m_elements.size() > 1Description
TRUEnever evaluated
FALSEnever evaluated
0
224 processCurrentSubpath();
never executed: processCurrentSubpath();
0
225 m_customData = 0;-
226}
never executed: end of block
0
227-
228/*!-
229 Convenience function that decomposes \a path into begin(),-
230 moveTo(), lineTo(), curevTo() and end() calls.-
231-
232 The \a customData parameter is used in the callback functions-
233-
234 The \a matrix is used to transform the points before input to the-
235 stroker.-
236-
237 \sa begin()-
238*/-
239void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const QTransform &matrix)-
240{-
241 if (path.isEmpty())
path.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
242 return;
never executed: return;
0
243-
244 setCurveThresholdFromTransform(QTransform());-
245 begin(customData);-
246 int count = path.elementCount();-
247 if (matrix.isIdentity()) {
matrix.isIdentity()Description
TRUEnever evaluated
FALSEnever evaluated
0
248 for (int i=0; i<count; ++i) {
i<countDescription
TRUEnever evaluated
FALSEnever evaluated
0
249 const QPainterPath::Element &e = path.elementAt(i);-
250 switch (e.type) {-
251 case QPainterPath::MoveToElement:
never executed: case QPainterPath::MoveToElement:
0
252 moveTo(qt_real_to_fixed(e.x), qt_real_to_fixed(e.y));-
253 break;
never executed: break;
0
254 case QPainterPath::LineToElement:
never executed: case QPainterPath::LineToElement:
0
255 lineTo(qt_real_to_fixed(e.x), qt_real_to_fixed(e.y));-
256 break;
never executed: break;
0
257 case QPainterPath::CurveToElement:
never executed: case QPainterPath::CurveToElement:
0
258 {-
259 const QPainterPath::Element &cp2 = path.elementAt(++i);-
260 const QPainterPath::Element &ep = path.elementAt(++i);-
261 cubicTo(qt_real_to_fixed(e.x), qt_real_to_fixed(e.y),-
262 qt_real_to_fixed(cp2.x), qt_real_to_fixed(cp2.y),-
263 qt_real_to_fixed(ep.x), qt_real_to_fixed(ep.y));-
264 }-
265 break;
never executed: break;
0
266 default:
never executed: default:
0
267 break;
never executed: break;
0
268 }-
269 }-
270 } else {
never executed: end of block
0
271 for (int i=0; i<count; ++i) {
i<countDescription
TRUEnever evaluated
FALSEnever evaluated
0
272 const QPainterPath::Element &e = path.elementAt(i);-
273 QPointF pt = QPointF(e.x, e.y) * matrix;-
274 switch (e.type) {-
275 case QPainterPath::MoveToElement:
never executed: case QPainterPath::MoveToElement:
0
276 moveTo(qt_real_to_fixed(pt.x()), qt_real_to_fixed(pt.y()));-
277 break;
never executed: break;
0
278 case QPainterPath::LineToElement:
never executed: case QPainterPath::LineToElement:
0
279 lineTo(qt_real_to_fixed(pt.x()), qt_real_to_fixed(pt.y()));-
280 break;
never executed: break;
0
281 case QPainterPath::CurveToElement:
never executed: case QPainterPath::CurveToElement:
0
282 {-
283 QPointF cp2 = ((QPointF) path.elementAt(++i)) * matrix;-
284 QPointF ep = ((QPointF) path.elementAt(++i)) * matrix;-
285 cubicTo(qt_real_to_fixed(pt.x()), qt_real_to_fixed(pt.y()),-
286 qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),-
287 qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));-
288 }-
289 break;
never executed: break;
0
290 default:
never executed: default:
0
291 break;
never executed: break;
0
292 }-
293 }-
294 }
never executed: end of block
0
295 end();-
296}
never executed: end of block
0
297-
298/*!-
299 Convenience function for stroking a polygon of the \a pointCount-
300 first points in \a points. If \a implicit_close is set to true a-
301 line is implictly drawn between the first and last point in the-
302 polygon. Typically true for polygons and false for polylines.-
303-
304 The \a matrix is used to transform the points before they enter the-
305 stroker.-
306-
307 \sa begin()-
308*/-
309-
310void QStrokerOps::strokePolygon(const QPointF *points, int pointCount, bool implicit_close,-
311 void *data, const QTransform &matrix)-
312{-
313 if (!pointCount)
!pointCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
314 return;
never executed: return;
0
315-
316 setCurveThresholdFromTransform(QTransform());-
317 begin(data);-
318 if (matrix.isIdentity()) {
matrix.isIdentity()Description
TRUEnever evaluated
FALSEnever evaluated
0
319 moveTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y()));-
320 for (int i=1; i<pointCount; ++i)
i<pointCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
321 lineTo(qt_real_to_fixed(points[i].x()),
never executed: lineTo(qfixed(points[i].x()), qfixed(points[i].y()));
0
322 qt_real_to_fixed(points[i].y()));
never executed: lineTo(qfixed(points[i].x()), qfixed(points[i].y()));
0
323 if (implicit_close)
implicit_closeDescription
TRUEnever evaluated
FALSEnever evaluated
0
324 lineTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y()));
never executed: lineTo(qfixed(points[0].x()), qfixed(points[0].y()));
0
325 } else {
never executed: end of block
0
326 QPointF start = points[0] * matrix;-
327 moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));-
328 for (int i=1; i<pointCount; ++i) {
i<pointCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
329 QPointF pt = points[i] * matrix;-
330 lineTo(qt_real_to_fixed(pt.x()), qt_real_to_fixed(pt.y()));-
331 }
never executed: end of block
0
332 if (implicit_close)
implicit_closeDescription
TRUEnever evaluated
FALSEnever evaluated
0
333 lineTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));
never executed: lineTo(qfixed(start.x()), qfixed(start.y()));
0
334 }
never executed: end of block
0
335 end();-
336}
never executed: end of block
0
337-
338/*!-
339 Convenience function for stroking an ellipse with bounding rect \a-
340 rect. The \a matrix is used to transform the coordinates before-
341 they enter the stroker.-
342*/-
343void QStrokerOps::strokeEllipse(const QRectF &rect, void *data, const QTransform &matrix)-
344{-
345 int count = 0;-
346 QPointF pts[12];-
347 QPointF start = qt_curves_for_arc(rect, 0, -360, pts, &count);-
348 Q_ASSERT(count == 12); // a perfect circle..-
349-
350 if (!matrix.isIdentity()) {
!matrix.isIdentity()Description
TRUEnever evaluated
FALSEnever evaluated
0
351 start = start * matrix;-
352 for (int i=0; i<12; ++i) {
i<12Description
TRUEnever evaluated
FALSEnever evaluated
0
353 pts[i] = pts[i] * matrix;-
354 }
never executed: end of block
0
355 }
never executed: end of block
0
356-
357 setCurveThresholdFromTransform(QTransform());-
358 begin(data);-
359 moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));-
360 for (int i=0; i<12; i+=3) {
i<12Description
TRUEnever evaluated
FALSEnever evaluated
0
361 cubicTo(qt_real_to_fixed(pts[i].x()), qt_real_to_fixed(pts[i].y()),-
362 qt_real_to_fixed(pts[i+1].x()), qt_real_to_fixed(pts[i+1].y()),-
363 qt_real_to_fixed(pts[i+2].x()), qt_real_to_fixed(pts[i+2].y()));-
364 }
never executed: end of block
0
365 end();-
366}
never executed: end of block
0
367-
368-
369QStroker::QStroker()-
370 : m_capStyle(SquareJoin), m_joinStyle(FlatJoin),-
371 m_back1X(0), m_back1Y(0),-
372 m_back2X(0), m_back2Y(0)-
373{-
374 m_strokeWidth = qt_real_to_fixed(1);-
375 m_miterLimit = qt_real_to_fixed(2);-
376}
never executed: end of block
0
377-
378QStroker::~QStroker()-
379{-
380}-
381-
382Qt::PenCapStyle QStroker::capForJoinMode(LineJoinMode mode)-
383{-
384 if (mode == FlatJoin) return Qt::FlatCap;
never executed: return Qt::FlatCap;
mode == FlatJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
385 else if (mode == SquareJoin) return Qt::SquareCap;
never executed: return Qt::SquareCap;
mode == SquareJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
386 else return Qt::RoundCap;
never executed: return Qt::RoundCap;
0
387}-
388-
389QStroker::LineJoinMode QStroker::joinModeForCap(Qt::PenCapStyle style)-
390{-
391 if (style == Qt::FlatCap) return FlatJoin;
never executed: return FlatJoin;
style == Qt::FlatCapDescription
TRUEnever evaluated
FALSEnever evaluated
0
392 else if (style == Qt::SquareCap) return SquareJoin;
never executed: return SquareJoin;
style == Qt::SquareCapDescription
TRUEnever evaluated
FALSEnever evaluated
0
393 else return RoundCap;
never executed: return RoundCap;
0
394}-
395-
396Qt::PenJoinStyle QStroker::joinForJoinMode(LineJoinMode mode)-
397{-
398 if (mode == FlatJoin) return Qt::BevelJoin;
never executed: return Qt::BevelJoin;
mode == FlatJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
399 else if (mode == MiterJoin) return Qt::MiterJoin;
never executed: return Qt::MiterJoin;
mode == MiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
400 else if (mode == SvgMiterJoin) return Qt::SvgMiterJoin;
never executed: return Qt::SvgMiterJoin;
mode == SvgMiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
401 else return Qt::RoundJoin;
never executed: return Qt::RoundJoin;
0
402}-
403-
404QStroker::LineJoinMode QStroker::joinModeForJoin(Qt::PenJoinStyle joinStyle)-
405{-
406 if (joinStyle == Qt::BevelJoin) return FlatJoin;
never executed: return FlatJoin;
joinStyle == Qt::BevelJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
407 else if (joinStyle == Qt::MiterJoin) return MiterJoin;
never executed: return MiterJoin;
joinStyle == Qt::MiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
408 else if (joinStyle == Qt::SvgMiterJoin) return SvgMiterJoin;
never executed: return SvgMiterJoin;
joinStyle == Qt::SvgMiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
409 else return RoundJoin;
never executed: return RoundJoin;
0
410}-
411-
412-
413/*!-
414 This function is called to stroke the currently built up-
415 subpath. The subpath is cleared when the function completes.-
416*/-
417void QStroker::processCurrentSubpath()-
418{-
419 Q_ASSERT(!m_elements.isEmpty());-
420 Q_ASSERT(m_elements.first().type == QPainterPath::MoveToElement);-
421 Q_ASSERT(m_elements.size() > 1);-
422-
423 QSubpathForwardIterator fwit(&m_elements);-
424 QSubpathBackwardIterator bwit(&m_elements);-
425-
426 QLineF fwStartTangent, bwStartTangent;-
427-
428 bool fwclosed = qt_stroke_side(&fwit, this, false, &fwStartTangent);-
429 bool bwclosed = qt_stroke_side(&bwit, this, !fwclosed, &bwStartTangent);-
430-
431 if (!bwclosed && !fwStartTangent.isNull())
!bwclosedDescription
TRUEnever evaluated
FALSEnever evaluated
!fwStartTangent.isNull()Description
TRUEnever evaluated
FALSEnever evaluated
0
432 joinPoints(m_elements.at(0).x, m_elements.at(0).y, fwStartTangent, m_capStyle);
never executed: joinPoints(m_elements.at(0).x, m_elements.at(0).y, fwStartTangent, m_capStyle);
0
433}
never executed: end of block
0
434-
435-
436/*!-
437 \internal-
438*/-
439void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine, LineJoinMode join)-
440{-
441#ifdef QPP_STROKE_DEBUG-
442 printf(" -----> joinPoints: around=(%.0f, %.0f), next_p1=(%.0f, %.f) next_p2=(%.0f, %.f)\n",-
443 qt_fixed_to_real(focal_x),-
444 qt_fixed_to_real(focal_y),-
445 nextLine.x1(), nextLine.y1(), nextLine.x2(), nextLine.y2());-
446#endif-
447 // points connected already, don't join-
448-
449#if !defined (QFIXED_26_6) && !defined (Q_FIXED_32_32)-
450 if (qFuzzyCompare(m_back1X, nextLine.x1()) && qFuzzyCompare(m_back1Y, nextLine.y1()))
qFuzzyCompare(...nextLine.x1())Description
TRUEnever evaluated
FALSEnever evaluated
qFuzzyCompare(...nextLine.y1())Description
TRUEnever evaluated
FALSEnever evaluated
0
451 return;
never executed: return;
0
452#else-
453 if (m_back1X == qt_real_to_fixed(nextLine.x1())-
454 && m_back1Y == qt_real_to_fixed(nextLine.y1())) {-
455 return;-
456 }-
457#endif-
458-
459 if (join == FlatJoin) {
join == FlatJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
460 QLineF prevLine(qt_fixed_to_real(m_back2X), qt_fixed_to_real(m_back2Y),-
461 qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y));-
462 QPointF isect;-
463 QLineF::IntersectType type = prevLine.intersect(nextLine, &isect);-
464 QLineF shortCut(prevLine.p2(), nextLine.p1());-
465 qreal angle = shortCut.angleTo(prevLine);-
466 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
type == QLineF...edIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
angle > 90Description
TRUEnever evaluated
FALSEnever evaluated
!qFuzzyCompare...le, (qreal)90)Description
TRUEnever evaluated
FALSEnever evaluated
0
467 emitLineTo(focal_x, focal_y);-
468 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
469 return;
never executed: return;
0
470 }-
471 emitLineTo(qt_real_to_fixed(nextLine.x1()),-
472 qt_real_to_fixed(nextLine.y1()));-
473-
474 } else {
never executed: end of block
0
475 QLineF prevLine(qt_fixed_to_real(m_back2X), qt_fixed_to_real(m_back2Y),-
476 qt_fixed_to_real(m_back1X), qt_fixed_to_real(m_back1Y));-
477-
478 QPointF isect;-
479 QLineF::IntersectType type = prevLine.intersect(nextLine, &isect);-
480-
481 if (join == MiterJoin) {
join == MiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
482 qreal appliedMiterLimit = qt_fixed_to_real(m_strokeWidth * m_miterLimit);-
483-
484 // If we are on the inside, do the short cut...-
485 QLineF shortCut(prevLine.p2(), nextLine.p1());-
486 qreal angle = shortCut.angleTo(prevLine);-
487 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
type == QLineF...edIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
angle > 90Description
TRUEnever evaluated
FALSEnever evaluated
!qFuzzyCompare...le, (qreal)90)Description
TRUEnever evaluated
FALSEnever evaluated
0
488 emitLineTo(focal_x, focal_y);-
489 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
490 return;
never executed: return;
0
491 }-
492 QLineF miterLine(QPointF(qt_fixed_to_real(m_back1X),-
493 qt_fixed_to_real(m_back1Y)), isect);-
494 if (type == QLineF::NoIntersection || miterLine.length() > appliedMiterLimit) {
type == QLineF::NoIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
miterLine.leng...liedMiterLimitDescription
TRUEnever evaluated
FALSEnever evaluated
0
495 QLineF l1(prevLine);-
496 l1.setLength(appliedMiterLimit);-
497 l1.translate(prevLine.dx(), prevLine.dy());-
498-
499 QLineF l2(nextLine);-
500 l2.setLength(appliedMiterLimit);-
501 l2.translate(-l2.dx(), -l2.dy());-
502-
503 emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()));-
504 emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1()));-
505 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
506 } else {
never executed: end of block
0
507 emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));-
508 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
509 }
never executed: end of block
0
510-
511 } else if (join == SquareJoin) {
join == SquareJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
512 qfixed offset = m_strokeWidth / 2;-
513-
514 QLineF l1(prevLine);-
515 l1.translate(l1.dx(), l1.dy());-
516 l1.setLength(qt_fixed_to_real(offset));-
517 QLineF l2(nextLine.p2(), nextLine.p1());-
518 l2.translate(l2.dx(), l2.dy());-
519 l2.setLength(qt_fixed_to_real(offset));-
520 emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()));-
521 emitLineTo(qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2()));-
522 emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1()));-
523-
524 } else if (join == RoundJoin) {
never executed: end of block
join == RoundJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
525 qfixed offset = m_strokeWidth / 2;-
526-
527 QLineF shortCut(prevLine.p2(), nextLine.p1());-
528 qreal angle = shortCut.angleTo(prevLine);-
529 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
type == QLineF...edIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
angle > 90Description
TRUEnever evaluated
FALSEnever evaluated
!qFuzzyCompare...le, (qreal)90)Description
TRUEnever evaluated
FALSEnever evaluated
0
530 emitLineTo(focal_x, focal_y);-
531 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
532 return;
never executed: return;
0
533 }-
534 qreal l1_on_x = adapted_angle_on_x(prevLine);-
535 qreal l2_on_x = adapted_angle_on_x(nextLine);-
536-
537 qreal sweepLength = qAbs(l2_on_x - l1_on_x);-
538-
539 int point_count;-
540 QPointF curves[15];-
541-
542 QPointF curve_start =-
543 qt_curves_for_arc(QRectF(qt_fixed_to_real(focal_x - offset),-
544 qt_fixed_to_real(focal_y - offset),-
545 qt_fixed_to_real(offset * 2),-
546 qt_fixed_to_real(offset * 2)),-
547 l1_on_x + 90, -sweepLength,-
548 curves, &point_count);-
549-
550// // line to the beginning of the arc segment, (should not be needed).-
551// emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y()));-
552 Q_UNUSED(curve_start);-
553-
554 for (int i=0; i<point_count; i+=3) {
i<point_countDescription
TRUEnever evaluated
FALSEnever evaluated
0
555 emitCubicTo(qt_real_to_fixed(curves[i].x()),-
556 qt_real_to_fixed(curves[i].y()),-
557 qt_real_to_fixed(curves[i+1].x()),-
558 qt_real_to_fixed(curves[i+1].y()),-
559 qt_real_to_fixed(curves[i+2].x()),-
560 qt_real_to_fixed(curves[i+2].y()));-
561 }
never executed: end of block
0
562-
563 // line to the end of the arc segment, (should also not be needed).-
564 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
565-
566 // Same as round join except we know its 180 degrees. Can also optimize this-
567 // later based on the addEllipse logic-
568 } else if (join == RoundCap) {
never executed: end of block
join == RoundCapDescription
TRUEnever evaluated
FALSEnever evaluated
0
569 qfixed offset = m_strokeWidth / 2;-
570-
571 // first control line-
572 QLineF l1 = prevLine;-
573 l1.translate(l1.dx(), l1.dy());-
574 l1.setLength(QT_PATH_KAPPA * offset);-
575-
576 // second control line, find through normal between prevLine and focal.-
577 QLineF l2(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y),-
578 prevLine.x2(), prevLine.y2());-
579 l2.translate(-l2.dy(), l2.dx());-
580 l2.setLength(QT_PATH_KAPPA * offset);-
581-
582 emitCubicTo(qt_real_to_fixed(l1.x2()),-
583 qt_real_to_fixed(l1.y2()),-
584 qt_real_to_fixed(l2.x2()),-
585 qt_real_to_fixed(l2.y2()),-
586 qt_real_to_fixed(l2.x1()),-
587 qt_real_to_fixed(l2.y1()));-
588-
589 // move so that it matches-
590 l2 = QLineF(l2.x1(), l2.y1(), l2.x1()-l2.dx(), l2.y1()-l2.dy());-
591-
592 // last line is parallel to l1 so just shift it down.-
593 l1.translate(nextLine.x1() - l1.x1(), nextLine.y1() - l1.y1());-
594-
595 emitCubicTo(qt_real_to_fixed(l2.x2()),-
596 qt_real_to_fixed(l2.y2()),-
597 qt_real_to_fixed(l1.x2()),-
598 qt_real_to_fixed(l1.y2()),-
599 qt_real_to_fixed(l1.x1()),-
600 qt_real_to_fixed(l1.y1()));-
601 } else if (join == SvgMiterJoin) {
never executed: end of block
join == SvgMiterJoinDescription
TRUEnever evaluated
FALSEnever evaluated
0
602 QLineF shortCut(prevLine.p2(), nextLine.p1());-
603 qreal angle = shortCut.angleTo(prevLine);-
604 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
type == QLineF...edIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
angle > 90Description
TRUEnever evaluated
FALSEnever evaluated
!qFuzzyCompare...le, (qreal)90)Description
TRUEnever evaluated
FALSEnever evaluated
0
605 emitLineTo(focal_x, focal_y);-
606 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
607 return;
never executed: return;
0
608 }-
609 QLineF miterLine(QPointF(qt_fixed_to_real(focal_x),-
610 qt_fixed_to_real(focal_y)), isect);-
611 if (type == QLineF::NoIntersection || miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) {
type == QLineF::NoIntersectionDescription
TRUEnever evaluated
FALSEnever evaluated
miterLine.leng...miterLimit / 2Description
TRUEnever evaluated
FALSEnever evaluated
0
612 emitLineTo(qt_real_to_fixed(nextLine.x1()),-
613 qt_real_to_fixed(nextLine.y1()));-
614 } else {
never executed: end of block
0
615 emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));-
616 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));-
617 }
never executed: end of block
0
618 } else {-
619 Q_ASSERT(!"QStroker::joinPoints(), bad join style...");-
620 }
never executed: end of block
0
621 }-
622}-
623-
624-
625/*-
626 Strokes a subpath side using the \a it as source. Results are put into-
627 \a stroke. The function returns \c true if the subpath side was closed.-
628 If \a capFirst is true, we will use capPoints instead of joinPoints to-
629 connect the first segment, other segments will be joined using joinPoints.-
630 This is to put capping in order...-
631*/-
632template <class Iterator> bool qt_stroke_side(Iterator *it,-
633 QStroker *stroker,-
634 bool capFirst,-
635 QLineF *startTangent)-
636{-
637 // Used in CurveToElement section below.-
638 const int MAX_OFFSET = 16;-
639 QBezier offsetCurves[MAX_OFFSET];-
640-
641 Q_ASSERT(it->hasNext()); // The initaial move to-
642 QStrokerOps::Element first_element = it->next();-
643 Q_ASSERT(first_element.isMoveTo());-
644-
645 qfixed2d start = first_element;-
646-
647#ifdef QPP_STROKE_DEBUG-
648 qDebug(" -> (side) [%.2f, %.2f], startPos=%d",-
649 qt_fixed_to_real(start.x),-
650 qt_fixed_to_real(start.y));-
651#endif-
652-
653 qfixed2d prev = start;-
654-
655 bool first = true;-
656-
657 qfixed offset = stroker->strokeWidth() / 2;-
658-
659 while (it->hasNext()) {
it->hasNext()Description
TRUEnever evaluated
FALSEnever evaluated
0
660 QStrokerOps::Element e = it->next();-
661-
662 // LineToElement-
663 if (e.isLineTo()) {
e.isLineTo()Description
TRUEnever evaluated
FALSEnever evaluated
0
664#ifdef QPP_STROKE_DEBUG-
665 qDebug("\n ---> (side) lineto [%.2f, %.2f]", e.x, e.y);-
666#endif-
667 QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y),-
668 qt_fixed_to_real(e.x), qt_fixed_to_real(e.y));-
669 if (line.p1() != line.p2()) {
line.p1() != line.p2()Description
TRUEnever evaluated
FALSEnever evaluated
0
670 QLineF normal = line.normalVector();-
671 normal.setLength(offset);-
672 line.translate(normal.dx(), normal.dy());-
673-
674 // If we are starting a new subpath, move to correct starting point.-
675 if (first) {
firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
676 if (capFirst)
capFirstDescription
TRUEnever evaluated
FALSEnever evaluated
0
677 stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode());
never executed: stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode());
0
678 else-
679 stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1()));
never executed: stroker->emitMoveTo(qfixed(line.x1()), qfixed(line.y1()));
0
680 *startTangent = line;-
681 first = false;-
682 } else {
never executed: end of block
0
683 stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode());-
684 }
never executed: end of block
0
685-
686 // Add the stroke for this line.-
687 stroker->emitLineTo(qt_real_to_fixed(line.x2()),-
688 qt_real_to_fixed(line.y2()));-
689 prev = e;-
690 }
never executed: end of block
0
691-
692 // CurveToElement-
693 } else if (e.isCurveTo()) {
never executed: end of block
e.isCurveTo()Description
TRUEnever evaluated
FALSEnever evaluated
0
694 QStrokerOps::Element cp2 = it->next(); // control point 2-
695 QStrokerOps::Element ep = it->next(); // end point-
696-
697#ifdef QPP_STROKE_DEBUG-
698 qDebug("\n ---> (side) cubicTo [%.2f, %.2f]",-
699 qt_fixed_to_real(ep.x),-
700 qt_fixed_to_real(ep.y));-
701#endif-
702-
703 QBezier bezier =-
704 QBezier::fromPoints(QPointF(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y)),-
705 QPointF(qt_fixed_to_real(e.x), qt_fixed_to_real(e.y)),-
706 QPointF(qt_fixed_to_real(cp2.x), qt_fixed_to_real(cp2.y)),-
707 QPointF(qt_fixed_to_real(ep.x), qt_fixed_to_real(ep.y)));-
708-
709 int count = bezier.shifted(offsetCurves,-
710 MAX_OFFSET,-
711 offset,-
712 stroker->curveThreshold());-
713-
714 if (count) {
countDescription
TRUEnever evaluated
FALSEnever evaluated
0
715 // If we are starting a new subpath, move to correct starting point-
716 QLineF tangent = bezier.startTangent();-
717 tangent.translate(offsetCurves[0].pt1() - bezier.pt1());-
718 if (first) {
firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
719 QPointF pt = offsetCurves[0].pt1();-
720 if (capFirst) {
capFirstDescription
TRUEnever evaluated
FALSEnever evaluated
0
721 stroker->joinPoints(prev.x, prev.y,-
722 tangent,-
723 stroker->capStyleMode());-
724 } else {
never executed: end of block
0
725 stroker->emitMoveTo(qt_real_to_fixed(pt.x()),-
726 qt_real_to_fixed(pt.y()));-
727 }
never executed: end of block
0
728 *startTangent = tangent;-
729 first = false;-
730 } else {
never executed: end of block
0
731 stroker->joinPoints(prev.x, prev.y,-
732 tangent,-
733 stroker->joinStyleMode());-
734 }
never executed: end of block
0
735-
736 // Add these beziers-
737 for (int i=0; i<count; ++i) {
i<countDescription
TRUEnever evaluated
FALSEnever evaluated
0
738 QPointF cp1 = offsetCurves[i].pt2();-
739 QPointF cp2 = offsetCurves[i].pt3();-
740 QPointF ep = offsetCurves[i].pt4();-
741 stroker->emitCubicTo(qt_real_to_fixed(cp1.x()), qt_real_to_fixed(cp1.y()),-
742 qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),-
743 qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));-
744 }
never executed: end of block
0
745 }
never executed: end of block
0
746-
747 prev = ep;-
748 }
never executed: end of block
0
749 }
never executed: end of block
0
750-
751 if (start == prev) {
start == prevDescription
TRUEnever evaluated
FALSEnever evaluated
0
752 // closed subpath, join first and last point-
753#ifdef QPP_STROKE_DEBUG-
754 qDebug("\n ---> (side) closed subpath");-
755#endif-
756 // don't join empty subpaths-
757 if (!first)
!firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
758 stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
never executed: stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
0
759 return true;
never executed: return true;
0
760 } else {-
761#ifdef QPP_STROKE_DEBUG-
762 qDebug("\n ---> (side) open subpath");-
763#endif-
764 return false;
never executed: return false;
0
765 }-
766}-
767-
768/*!-
769 \internal-
770-
771 For a given angle in the range [0 .. 90], finds the corresponding parameter t-
772 of the prototype cubic bezier arc segment-
773 b = fromPoints(QPointF(1, 0), QPointF(1, KAPPA), QPointF(KAPPA, 1), QPointF(0, 1));-
774-
775 From the bezier equation:-
776 b.pointAt(t).x() = (1-t)^3 + t*(1-t)^2 + t^2*(1-t)*KAPPA-
777 b.pointAt(t).y() = t*(1-t)^2 * KAPPA + t^2*(1-t) + t^3-
778-
779 Third degree coefficients:-
780 b.pointAt(t).x() = at^3 + bt^2 + ct + d-
781 where a = 2-3*KAPPA, b = 3*(KAPPA-1), c = 0, d = 1-
782-
783 b.pointAt(t).y() = at^3 + bt^2 + ct + d-
784 where a = 3*KAPPA-2, b = 6*KAPPA+3, c = 3*KAPPA, d = 0-
785-
786 Newton's method to find the zero of a function:-
787 given a function f(x) and initial guess x_0-
788 x_1 = f(x_0) / f'(x_0)-
789 x_2 = f(x_1) / f'(x_1)-
790 etc...-
791*/-
792-
793qreal qt_t_for_arc_angle(qreal angle)-
794{-
795 if (qFuzzyIsNull(angle))
qFuzzyIsNull(angle)Description
TRUEnever evaluated
FALSEnever evaluated
0
796 return 0;
never executed: return 0;
0
797-
798 if (qFuzzyCompare(angle, qreal(90)))
qFuzzyCompare(...le, qreal(90))Description
TRUEnever evaluated
FALSEnever evaluated
0
799 return 1;
never executed: return 1;
0
800-
801 qreal radians = qDegreesToRadians(angle);-
802 qreal cosAngle = qCos(radians);-
803 qreal sinAngle = qSin(radians);-
804-
805 // initial guess-
806 qreal tc = angle / 90;-
807 // do some iterations of newton's method to approximate cosAngle-
808 // finds the zero of the function b.pointAt(tc).x() - cosAngle-
809 tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value-
810 / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative-
811 tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value-
812 / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative-
813-
814 // initial guess-
815 qreal ts = tc;-
816 // do some iterations of newton's method to approximate sinAngle-
817 // finds the zero of the function b.pointAt(tc).y() - sinAngle-
818 ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)-
819 / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);-
820 ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)-
821 / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);-
822-
823 // use the average of the t that best approximates cosAngle-
824 // and the t that best approximates sinAngle-
825 qreal t = 0.5 * (tc + ts);-
826-
827#if 0-
828 printf("angle: %f, t: %f\n", angle, t);-
829 qreal a, b, c, d;-
830 bezierCoefficients(t, a, b, c, d);-
831 printf("cosAngle: %.10f, value: %.10f\n", cosAngle, a + b + c * QT_PATH_KAPPA);-
832 printf("sinAngle: %.10f, value: %.10f\n", sinAngle, b * QT_PATH_KAPPA + c + d);-
833#endif-
834-
835 return t;
never executed: return t;
0
836}-
837-
838Q_GUI_EXPORT void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,-
839 QPointF* startPoint, QPointF *endPoint);-
840-
841/*!-
842 \internal-
843-
844 Creates a number of curves for a given arc definition. The arc is-
845 defined an arc along the ellipses that fits into \a rect starting-
846 at \a startAngle and an arc length of \a sweepLength.-
847-
848 The function has three out parameters. The return value is the-
849 starting point of the arc. The \a curves array represents the list-
850 of cubicTo elements up to a maximum of \a point_count. There are of course-
851 3 points pr curve.-
852*/-
853QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,-
854 QPointF *curves, int *point_count)-
855{-
856 Q_ASSERT(point_count);-
857 Q_ASSERT(curves);-
858-
859 *point_count = 0;-
860 if (qt_is_nan(rect.x()) || qt_is_nan(rect.y()) || qt_is_nan(rect.width()) || qt_is_nan(rect.height())
qt_is_nan(rect.x())Description
TRUEnever evaluated
FALSEnever evaluated
qt_is_nan(rect.y())Description
TRUEnever evaluated
FALSEnever evaluated
qt_is_nan(rect.width())Description
TRUEnever evaluated
FALSEnever evaluated
qt_is_nan(rect.height())Description
TRUEnever evaluated
FALSEnever evaluated
0
861 || qt_is_nan(startAngle) || qt_is_nan(sweepLength)) {
qt_is_nan(startAngle)Description
TRUEnever evaluated
FALSEnever evaluated
qt_is_nan(sweepLength)Description
TRUEnever evaluated
FALSEnever evaluated
0
862 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");-
863 return QPointF();
never executed: return QPointF();
0
864 }-
865-
866 if (rect.isNull()) {
rect.isNull()Description
TRUEnever evaluated
FALSEnever evaluated
0
867 return QPointF();
never executed: return QPointF();
0
868 }-
869-
870 qreal x = rect.x();-
871 qreal y = rect.y();-
872-
873 qreal w = rect.width();-
874 qreal w2 = rect.width() / 2;-
875 qreal w2k = w2 * QT_PATH_KAPPA;-
876-
877 qreal h = rect.height();-
878 qreal h2 = rect.height() / 2;-
879 qreal h2k = h2 * QT_PATH_KAPPA;-
880-
881 QPointF points[16] =-
882 {-
883 // start point-
884 QPointF(x + w, y + h2),-
885-
886 // 0 -> 270 degrees-
887 QPointF(x + w, y + h2 + h2k),-
888 QPointF(x + w2 + w2k, y + h),-
889 QPointF(x + w2, y + h),-
890-
891 // 270 -> 180 degrees-
892 QPointF(x + w2 - w2k, y + h),-
893 QPointF(x, y + h2 + h2k),-
894 QPointF(x, y + h2),-
895-
896 // 180 -> 90 degrees-
897 QPointF(x, y + h2 - h2k),-
898 QPointF(x + w2 - w2k, y),-
899 QPointF(x + w2, y),-
900-
901 // 90 -> 0 degrees-
902 QPointF(x + w2 + w2k, y),-
903 QPointF(x + w, y + h2 - h2k),-
904 QPointF(x + w, y + h2)-
905 };-
906-
907 if (sweepLength > 360) sweepLength = 360;
never executed: sweepLength = 360;
sweepLength > 360Description
TRUEnever evaluated
FALSEnever evaluated
0
908 else if (sweepLength < -360) sweepLength = -360;
never executed: sweepLength = -360;
sweepLength < -360Description
TRUEnever evaluated
FALSEnever evaluated
0
909-
910 // Special case fast paths-
911 if (startAngle == 0.0) {
startAngle == 0.0Description
TRUEnever evaluated
FALSEnever evaluated
0
912 if (sweepLength == 360.0) {
sweepLength == 360.0Description
TRUEnever evaluated
FALSEnever evaluated
0
913 for (int i = 11; i >= 0; --i)
i >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
914 curves[(*point_count)++] = points[i];
never executed: curves[(*point_count)++] = points[i];
0
915 return points[12];
never executed: return points[12];
0
916 } else if (sweepLength == -360.0) {
sweepLength == -360.0Description
TRUEnever evaluated
FALSEnever evaluated
0
917 for (int i = 1; i <= 12; ++i)
i <= 12Description
TRUEnever evaluated
FALSEnever evaluated
0
918 curves[(*point_count)++] = points[i];
never executed: curves[(*point_count)++] = points[i];
0
919 return points[0];
never executed: return points[0];
0
920 }-
921 }
never executed: end of block
0
922-
923 int startSegment = int(qFloor(startAngle / 90));-
924 int endSegment = int(qFloor((startAngle + sweepLength) / 90));-
925-
926 qreal startT = (startAngle - startSegment * 90) / 90;-
927 qreal endT = (startAngle + sweepLength - endSegment * 90) / 90;-
928-
929 int delta = sweepLength > 0 ? 1 : -1;
sweepLength > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
930 if (delta < 0) {
delta < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
931 startT = 1 - startT;-
932 endT = 1 - endT;-
933 }
never executed: end of block
0
934-
935 // avoid empty start segment-
936 if (qFuzzyIsNull(startT - qreal(1))) {
qFuzzyIsNull(s...tT - qreal(1))Description
TRUEnever evaluated
FALSEnever evaluated
0
937 startT = 0;-
938 startSegment += delta;-
939 }
never executed: end of block
0
940-
941 // avoid empty end segment-
942 if (qFuzzyIsNull(endT)) {
qFuzzyIsNull(endT)Description
TRUEnever evaluated
FALSEnever evaluated
0
943 endT = 1;-
944 endSegment -= delta;-
945 }
never executed: end of block
0
946-
947 startT = qt_t_for_arc_angle(startT * 90);-
948 endT = qt_t_for_arc_angle(endT * 90);-
949-
950 const bool splitAtStart = !qFuzzyIsNull(startT);-
951 const bool splitAtEnd = !qFuzzyIsNull(endT - qreal(1));-
952-
953 const int end = endSegment + delta;-
954-
955 // empty arc?-
956 if (startSegment == end) {
startSegment == endDescription
TRUEnever evaluated
FALSEnever evaluated
0
957 const int quadrant = 3 - ((startSegment % 4) + 4) % 4;-
958 const int j = 3 * quadrant;-
959 return delta > 0 ? points[j + 3] : points[j];
never executed: return delta > 0 ? points[j + 3] : points[j];
0
960 }-
961-
962 QPointF startPoint, endPoint;-
963 qt_find_ellipse_coords(rect, startAngle, sweepLength, &startPoint, &endPoint);-
964-
965 for (int i = startSegment; i != end; i += delta) {
i != endDescription
TRUEnever evaluated
FALSEnever evaluated
0
966 const int quadrant = 3 - ((i % 4) + 4) % 4;-
967 const int j = 3 * quadrant;-
968-
969 QBezier b;-
970 if (delta > 0)
delta > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
971 b = QBezier::fromPoints(points[j + 3], points[j + 2], points[j + 1], points[j]);
never executed: b = QBezier::fromPoints(points[j + 3], points[j + 2], points[j + 1], points[j]);
0
972 else-
973 b = QBezier::fromPoints(points[j], points[j + 1], points[j + 2], points[j + 3]);
never executed: b = QBezier::fromPoints(points[j], points[j + 1], points[j + 2], points[j + 3]);
0
974-
975 // empty arc?-
976 if (startSegment == endSegment && qFuzzyCompare(startT, endT))
startSegment == endSegmentDescription
TRUEnever evaluated
FALSEnever evaluated
qFuzzyCompare(startT, endT)Description
TRUEnever evaluated
FALSEnever evaluated
0
977 return startPoint;
never executed: return startPoint;
0
978-
979 if (i == startSegment) {
i == startSegmentDescription
TRUEnever evaluated
FALSEnever evaluated
0
980 if (i == endSegment && splitAtEnd)
i == endSegmentDescription
TRUEnever evaluated
FALSEnever evaluated
splitAtEndDescription
TRUEnever evaluated
FALSEnever evaluated
0
981 b = b.bezierOnInterval(startT, endT);
never executed: b = b.bezierOnInterval(startT, endT);
0
982 else if (splitAtStart)
splitAtStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
983 b = b.bezierOnInterval(startT, 1);
never executed: b = b.bezierOnInterval(startT, 1);
0
984 } else if (i == endSegment && splitAtEnd) {
never executed: end of block
i == endSegmentDescription
TRUEnever evaluated
FALSEnever evaluated
splitAtEndDescription
TRUEnever evaluated
FALSEnever evaluated
0
985 b = b.bezierOnInterval(0, endT);-
986 }
never executed: end of block
0
987-
988 // push control points-
989 curves[(*point_count)++] = b.pt2();-
990 curves[(*point_count)++] = b.pt3();-
991 curves[(*point_count)++] = b.pt4();-
992 }
never executed: end of block
0
993-
994 Q_ASSERT(*point_count > 0);-
995 curves[*(point_count)-1] = endPoint;-
996-
997 return startPoint;
never executed: return startPoint;
0
998}-
999-
1000-
1001static inline void qdashstroker_moveTo(qfixed x, qfixed y, void *data) {-
1002 ((QStroker *) data)->moveTo(x, y);-
1003}
never executed: end of block
0
1004-
1005static inline void qdashstroker_lineTo(qfixed x, qfixed y, void *data) {-
1006 ((QStroker *) data)->lineTo(x, y);-
1007}
never executed: end of block
0
1008-
1009static inline void qdashstroker_cubicTo(qfixed, qfixed, qfixed, qfixed, qfixed, qfixed, void *) {-
1010 Q_ASSERT(0);-
1011// ((QStroker *) data)->cubicTo(c1x, c1y, c2x, c2y, ex, ey);-
1012}
never executed: end of block
0
1013-
1014-
1015/*******************************************************************************-
1016 * QDashStroker members-
1017 */-
1018QDashStroker::QDashStroker(QStroker *stroker)-
1019 : m_stroker(stroker), m_dashOffset(0), m_stroke_width(1), m_miter_limit(1)-
1020{-
1021 if (m_stroker) {
m_strokerDescription
TRUEnever evaluated
FALSEnever evaluated
0
1022 setMoveToHook(qdashstroker_moveTo);-
1023 setLineToHook(qdashstroker_lineTo);-
1024 setCubicToHook(qdashstroker_cubicTo);-
1025 }
never executed: end of block
0
1026}
never executed: end of block
0
1027-
1028QDashStroker::~QDashStroker()-
1029{-
1030}-
1031-
1032QVector<qfixed> QDashStroker::patternForStyle(Qt::PenStyle style)-
1033{-
1034 const qfixed space = 2;-
1035 const qfixed dot = 1;-
1036 const qfixed dash = 4;-
1037-
1038 QVector<qfixed> pattern;-
1039-
1040 switch (style) {-
1041 case Qt::DashLine:
never executed: case Qt::DashLine:
0
1042 pattern << dash << space;-
1043 break;
never executed: break;
0
1044 case Qt::DotLine:
never executed: case Qt::DotLine:
0
1045 pattern << dot << space;-
1046 break;
never executed: break;
0
1047 case Qt::DashDotLine:
never executed: case Qt::DashDotLine:
0
1048 pattern << dash << space << dot << space;-
1049 break;
never executed: break;
0
1050 case Qt::DashDotDotLine:
never executed: case Qt::DashDotDotLine:
0
1051 pattern << dash << space << dot << space << dot << space;-
1052 break;
never executed: break;
0
1053 default:
never executed: default:
0
1054 break;
never executed: break;
0
1055 }-
1056-
1057 return pattern;
never executed: return pattern;
0
1058}-
1059-
1060static inline bool lineRectIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)-
1061{-
1062 return ((p1.x > tl.x || p2.x > tl.x) && (p1.x < br.x || p2.x < br.x)
never executed: return ((p1.x > tl.x || p2.x > tl.x) && (p1.x < br.x || p2.x < br.x) && (p1.y > tl.y || p2.y > tl.y) && (p1.y < br.y || p2.y < br.y));
0
1063 && (p1.y > tl.y || p2.y > tl.y) && (p1.y < br.y || p2.y < br.y));
never executed: return ((p1.x > tl.x || p2.x > tl.x) && (p1.x < br.x || p2.x < br.x) && (p1.y > tl.y || p2.y > tl.y) && (p1.y < br.y || p2.y < br.y));
0
1064}-
1065-
1066// If the line intersects the rectangle, this function will return true.-
1067static bool lineIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)-
1068{-
1069 if (!lineRectIntersectsRect(p1, p2, tl, br))
!lineRectInter...1, p2, tl, br)Description
TRUEnever evaluated
FALSEnever evaluated
0
1070 return false;
never executed: return false;
0
1071 if (p1.x == p2.x || p1.y == p2.y)
p1.x == p2.xDescription
TRUEnever evaluated
FALSEnever evaluated
p1.y == p2.yDescription
TRUEnever evaluated
FALSEnever evaluated
0
1072 return true;
never executed: return true;
0
1073-
1074 if (p1.y > p2.y)
p1.y > p2.yDescription
TRUEnever evaluated
FALSEnever evaluated
0
1075 qSwap(p1, p2); // make p1 above p2
never executed: qSwap(p1, p2);
0
1076 qfixed2d u;-
1077 qfixed2d v;-
1078 qfixed2d w = {p2.x - p1.x, p2.y - p1.y};-
1079 if (p1.x < p2.x) {
p1.x < p2.xDescription
TRUEnever evaluated
FALSEnever evaluated
0
1080 // backslash-
1081 u.x = tl.x - p1.x; u.y = br.y - p1.y;-
1082 v.x = br.x - p1.x; v.y = tl.y - p1.y;-
1083 } else {
never executed: end of block
0
1084 // slash-
1085 u.x = tl.x - p1.x; u.y = tl.y - p1.y;-
1086 v.x = br.x - p1.x; v.y = br.y - p1.y;-
1087 }
never executed: end of block
0
1088#if defined(QFIXED_IS_26_6) || defined(QFIXED_IS_16_16)-
1089 qint64 val1 = qint64(u.x) * qint64(w.y) - qint64(u.y) * qint64(w.x);-
1090 qint64 val2 = qint64(v.x) * qint64(w.y) - qint64(v.y) * qint64(w.x);-
1091 return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);-
1092#elif defined(QFIXED_IS_32_32)-
1093 // Cannot do proper test because it may overflow.-
1094 return true;-
1095#else-
1096 qreal val1 = u.x * w.y - u.y * w.x;-
1097 qreal val2 = v.x * w.y - v.y * w.x;-
1098 return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
never executed: return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
0
1099#endif-
1100}-
1101-
1102void QDashStroker::processCurrentSubpath()-
1103{-
1104 int dashCount = qMin(m_dashPattern.size(), 32);-
1105 qfixed dashes[32];-
1106-
1107 if (m_stroker) {
m_strokerDescription
TRUEnever evaluated
FALSEnever evaluated
0
1108 m_customData = m_stroker;-
1109 m_stroke_width = m_stroker->strokeWidth();-
1110 m_miter_limit = m_stroker->miterLimit();-
1111 }
never executed: end of block
0
1112-
1113 qreal longestLength = 0;-
1114 qreal sumLength = 0;-
1115 for (int i=0; i<dashCount; ++i) {
i<dashCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1116 dashes[i] = qMax(m_dashPattern.at(i), qreal(0)) * m_stroke_width;-
1117 sumLength += dashes[i];-
1118 if (dashes[i] > longestLength)
dashes[i] > longestLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1119 longestLength = dashes[i];
never executed: longestLength = dashes[i];
0
1120 }
never executed: end of block
0
1121-
1122 if (qFuzzyIsNull(sumLength))
qFuzzyIsNull(sumLength)Description
TRUEnever evaluated
FALSEnever evaluated
0
1123 return;
never executed: return;
0
1124-
1125 qreal invSumLength = qreal(1) / sumLength;-
1126-
1127 Q_ASSERT(dashCount > 0);-
1128-
1129 dashCount = dashCount & -2; // Round down to even number-
1130-
1131 int idash = 0; // Index to current dash-
1132 qreal pos = 0; // The position on the curve, 0 <= pos <= path.length-
1133 qreal elen = 0; // element length-
1134 qreal doffset = m_dashOffset * m_stroke_width;-
1135-
1136 // make sure doffset is in range [0..sumLength)-
1137 doffset -= qFloor(doffset * invSumLength) * sumLength;-
1138-
1139 while (doffset >= dashes[idash]) {
doffset >= dashes[idash]Description
TRUEnever evaluated
FALSEnever evaluated
0
1140 doffset -= dashes[idash];-
1141 if (++idash >= dashCount)
++idash >= dashCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1142 idash = 0;
never executed: idash = 0;
0
1143 }
never executed: end of block
0
1144-
1145 qreal estart = 0; // The elements starting position-
1146 qreal estop = 0; // The element stop position-
1147-
1148 QLineF cline;-
1149-
1150 QPainterPath dashPath;-
1151-
1152 QSubpathFlatIterator it(&m_elements, m_dashThreshold);-
1153 qfixed2d prev = it.next();-
1154-
1155 bool clipping = !m_clip_rect.isEmpty();-
1156 qfixed2d move_to_pos = prev;-
1157 qfixed2d line_to_pos;-
1158-
1159 // Pad to avoid clipping the borders of thick pens.-
1160 qfixed padding = qt_real_to_fixed(qMax(m_stroke_width, m_miter_limit) * longestLength);-
1161 qfixed2d clip_tl = { qt_real_to_fixed(m_clip_rect.left()) - padding,-
1162 qt_real_to_fixed(m_clip_rect.top()) - padding };-
1163 qfixed2d clip_br = { qt_real_to_fixed(m_clip_rect.right()) + padding ,-
1164 qt_real_to_fixed(m_clip_rect.bottom()) + padding };-
1165-
1166 bool hasMoveTo = false;-
1167 while (it.hasNext()) {
it.hasNext()Description
TRUEnever evaluated
FALSEnever evaluated
0
1168 QStrokerOps::Element e = it.next();-
1169-
1170 Q_ASSERT(e.isLineTo());-
1171 cline = QLineF(qt_fixed_to_real(prev.x),-
1172 qt_fixed_to_real(prev.y),-
1173 qt_fixed_to_real(e.x),-
1174 qt_fixed_to_real(e.y));-
1175 elen = cline.length();-
1176-
1177 estop = estart + elen;-
1178-
1179 bool done = pos >= estop;-
1180-
1181 if (clipping) {
clippingDescription
TRUEnever evaluated
FALSEnever evaluated
0
1182 // Check if the entire line can be clipped away.-
1183 if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
!lineIntersect...p_tl, clip_br)Description
TRUEnever evaluated
FALSEnever evaluated
0
1184 // Cut away full dash sequences.-
1185 elen -= qFloor(elen * invSumLength) * sumLength;-
1186 // Update dash offset.-
1187 while (!done) {
!doneDescription
TRUEnever evaluated
FALSEnever evaluated
0
1188 qreal dpos = pos + dashes[idash] - doffset - estart;-
1189-
1190 Q_ASSERT(dpos >= 0);-
1191-
1192 if (dpos > elen) { // dash extends this line
dpos > elenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1193 doffset = dashes[idash] - (dpos - elen); // subtract the part already used-
1194 pos = estop; // move pos to next path element-
1195 done = true;-
1196 } else { // Dash is on this line
never executed: end of block
0
1197 pos = dpos + estart;-
1198 done = pos >= estop;-
1199 if (++idash >= dashCount)
++idash >= dashCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1200 idash = 0;
never executed: idash = 0;
0
1201 doffset = 0; // full segment so no offset on next.-
1202 }
never executed: end of block
0
1203 }-
1204 hasMoveTo = false;-
1205 move_to_pos = e;-
1206 }
never executed: end of block
0
1207 }
never executed: end of block
0
1208-
1209 // Dash away...-
1210 while (!done) {
!doneDescription
TRUEnever evaluated
FALSEnever evaluated
0
1211 QPointF p2;-
1212-
1213 bool has_offset = doffset > 0;-
1214 bool evenDash = (idash & 1) == 0;-
1215 qreal dpos = pos + dashes[idash] - doffset - estart;-
1216-
1217 Q_ASSERT(dpos >= 0);-
1218-
1219 if (dpos > elen) { // dash extends this line
dpos > elenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1220 doffset = dashes[idash] - (dpos - elen); // subtract the part already used-
1221 pos = estop; // move pos to next path element-
1222 done = true;-
1223 p2 = cline.p2();-
1224 } else { // Dash is on this line
never executed: end of block
0
1225 p2 = cline.pointAt(dpos/elen);-
1226 pos = dpos + estart;-
1227 done = pos >= estop;-
1228 if (++idash >= dashCount)
++idash >= dashCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1229 idash = 0;
never executed: idash = 0;
0
1230 doffset = 0; // full segment so no offset on next.-
1231 }
never executed: end of block
0
1232-
1233 if (evenDash) {
evenDashDescription
TRUEnever evaluated
FALSEnever evaluated
0
1234 line_to_pos.x = qt_real_to_fixed(p2.x());-
1235 line_to_pos.y = qt_real_to_fixed(p2.y());-
1236-
1237 if (!clipping
!clippingDescription
TRUEnever evaluated
FALSEnever evaluated
0
1238 || lineRectIntersectsRect(move_to_pos, line_to_pos, clip_tl, clip_br))
lineRectInters...p_tl, clip_br)Description
TRUEnever evaluated
FALSEnever evaluated
0
1239 {-
1240 // If we have an offset, we're continuing a dash-
1241 // from a previous element and should only-
1242 // continue the current dash, without starting a-
1243 // new subpath.-
1244 if (!has_offset || !hasMoveTo) {
!has_offsetDescription
TRUEnever evaluated
FALSEnever evaluated
!hasMoveToDescription
TRUEnever evaluated
FALSEnever evaluated
0
1245 emitMoveTo(move_to_pos.x, move_to_pos.y);-
1246 hasMoveTo = true;-
1247 }
never executed: end of block
0
1248-
1249 emitLineTo(line_to_pos.x, line_to_pos.y);-
1250 } else {
never executed: end of block
0
1251 hasMoveTo = false;-
1252 }
never executed: end of block
0
1253 move_to_pos = line_to_pos;-
1254 } else {
never executed: end of block
0
1255 move_to_pos.x = qt_real_to_fixed(p2.x());-
1256 move_to_pos.y = qt_real_to_fixed(p2.y());-
1257 }
never executed: end of block
0
1258 }-
1259-
1260 // Shuffle to the next cycle...-
1261 estart = estop;-
1262 prev = e;-
1263 }
never executed: end of block
0
1264-
1265}
never executed: end of block
0
1266-
1267QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9