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

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