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 "qpainterpath.h"
41#include "qpainterpath_p.h"
42
43#include <qbitmap.h>
44#include <qdebug.h>
45#include <qiodevice.h>
46#include <qlist.h>
47#include <qmatrix.h>
48#include <qpen.h>
49#include <qpolygon.h>
50#include <qtextlayout.h>
51#include <qvarlengtharray.h>
52#include <qmath.h>
53
54#include <private/qbezier_p.h>
55#include <private/qfontengine_p.h>
56#include <private/qnumeric_p.h>
57#include <private/qobject_p.h>
58#include <private/qpathclipper_p.h>
59#include <private/qstroker_p.h>
60#include <private/qtextengine_p.h>
61
62#include <limits.h>
63
64#if 0
65#include <performance.h>
66#else
67#define PM_INIT
68#define PM_MEASURE(x)
69#define PM_DISPLAY
70#endif
71
72QT_BEGIN_NAMESPACE
73
74static inline bool isValidCoord(qreal c)
75{
76 if (sizeof(qreal) >= sizeof(double))
77 return qIsFinite(c) && fabs(c) < 1e128;
78 else
79 return qIsFinite(c) && fabsf(float(c)) < 1e16f;
80}
81
82static bool hasValidCoords(QPointF p)
83{
84 return isValidCoord(p.x()) && isValidCoord(p.y());
85}
86
87static bool hasValidCoords(QRectF r)
88{
89 return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
90}
91
92struct QPainterPathPrivateDeleter
93{
94 static inline void cleanup(QPainterPathPrivate *d)
95 {
96 // note - we must downcast to QPainterPathData since QPainterPathPrivate
97 // has a non-virtual destructor!
98 if (d && !d->ref.deref())
99 delete static_cast<QPainterPathData *>(d);
100 }
101};
102
103// This value is used to determine the length of control point vectors
104// when approximating arc segments as curves. The factor is multiplied
105// with the radius of the circle.
106
107// #define QPP_DEBUG
108// #define QPP_STROKE_DEBUG
109//#define QPP_FILLPOLYGONS_DEBUG
110
111QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount);
112
113void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
114 QPointF* startPoint, QPointF *endPoint)
115{
116 if (r.isNull()) {
117 if (startPoint)
118 *startPoint = QPointF();
119 if (endPoint)
120 *endPoint = QPointF();
121 return;
122 }
123
124 qreal w2 = r.width() / 2;
125 qreal h2 = r.height() / 2;
126
127 qreal angles[2] = { angle, angle + length };
128 QPointF *points[2] = { startPoint, endPoint };
129
130 for (int i = 0; i < 2; ++i) {
131 if (!points[i])
132 continue;
133
134 qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
135 qreal t = theta / 90;
136 // truncate
137 int quadrant = int(t);
138 t -= quadrant;
139
140 t = qt_t_for_arc_angle(90 * t);
141
142 // swap x and y?
143 if (quadrant & 1)
144 t = 1 - t;
145
146 qreal a, b, c, d;
147 QBezier::coefficients(t, a, b, c, d);
148 QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
149
150 // left quadrants
151 if (quadrant == 1 || quadrant == 2)
152 p.rx() = -p.x();
153
154 // top quadrants
155 if (quadrant == 0 || quadrant == 1)
156 p.ry() = -p.y();
157
158 *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
159 }
160}
161
162#ifdef QPP_DEBUG
163static void qt_debug_path(const QPainterPath &path)
164{
165 const char *names[] = {
166 "MoveTo ",
167 "LineTo ",
168 "CurveTo ",
169 "CurveToData"
170 };
171
172 printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
173 for (int i=0; i<path.elementCount(); ++i) {
174 const QPainterPath::Element &e = path.elementAt(i);
175 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
176 printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
177 }
178}
179#endif
180
181/*!
182 \class QPainterPath
183 \ingroup painting
184 \ingroup shared
185 \inmodule QtGui
186
187 \brief The QPainterPath class provides a container for painting operations,
188 enabling graphical shapes to be constructed and reused.
189
190 A painter path is an object composed of a number of graphical
191 building blocks, such as rectangles, ellipses, lines, and curves.
192 Building blocks can be joined in closed subpaths, for example as a
193 rectangle or an ellipse. A closed path has coinciding start and
194 end points. Or they can exist independently as unclosed subpaths,
195 such as lines and curves.
196
197 A QPainterPath object can be used for filling, outlining, and
198 clipping. To generate fillable outlines for a given painter path,
199 use the QPainterPathStroker class. The main advantage of painter
200 paths over normal drawing operations is that complex shapes only
201 need to be created once; then they can be drawn many times using
202 only calls to the QPainter::drawPath() function.
203
204 QPainterPath provides a collection of functions that can be used
205 to obtain information about the path and its elements. In addition
206 it is possible to reverse the order of the elements using the
207 toReversed() function. There are also several functions to convert
208 this painter path object into a polygon representation.
209
210 \tableofcontents
211
212 \section1 Composing a QPainterPath
213
214 A QPainterPath object can be constructed as an empty path, with a
215 given start point, or as a copy of another QPainterPath object.
216 Once created, lines and curves can be added to the path using the
217 lineTo(), arcTo(), cubicTo() and quadTo() functions. The lines and
218 curves stretch from the currentPosition() to the position passed
219 as argument.
220
221 The currentPosition() of the QPainterPath object is always the end
222 position of the last subpath that was added (or the initial start
223 point). Use the moveTo() function to move the currentPosition()
224 without adding a component. The moveTo() function implicitly
225 starts a new subpath, and closes the previous one. Another way of
226 starting a new subpath is to call the closeSubpath() function
227 which closes the current path by adding a line from the
228 currentPosition() back to the path's start position. Note that the
229 new path will have (0, 0) as its initial currentPosition().
230
231 QPainterPath class also provides several convenience functions to
232 add closed subpaths to a painter path: addEllipse(), addPath(),
233 addRect(), addRegion() and addText(). The addPolygon() function
234 adds an \e unclosed subpath. In fact, these functions are all
235 collections of moveTo(), lineTo() and cubicTo() operations.
236
237 In addition, a path can be added to the current path using the
238 connectPath() function. But note that this function will connect
239 the last element of the current path to the first element of given
240 one by adding a line.
241
242 Below is a code snippet that shows how a QPainterPath object can
243 be used:
244
245 \table 70%
246 \row
247 \li \inlineimage qpainterpath-construction.png
248 \li
249 \snippet code/src_gui_painting_qpainterpath.cpp 0
250 \endtable
251
252 The painter path is initially empty when constructed. We first add
253 a rectangle, which is a closed subpath. Then we add two bezier
254 curves which together form a closed subpath even though they are
255 not closed individually. Finally we draw the entire path. The path
256 is filled using the default fill rule, Qt::OddEvenFill. Qt
257 provides two methods for filling paths:
258
259 \table
260 \header
261 \li Qt::OddEvenFill
262 \li Qt::WindingFill
263 \row
264 \li \inlineimage qt-fillrule-oddeven.png
265 \li \inlineimage qt-fillrule-winding.png
266 \endtable
267
268 See the Qt::FillRule documentation for the definition of the
269 rules. A painter path's currently set fill rule can be retrieved
270 using the fillRule() function, and altered using the setFillRule()
271 function.
272
273 \section1 QPainterPath Information
274
275 The QPainterPath class provides a collection of functions that
276 returns information about the path and its elements.
277
278 The currentPosition() function returns the end point of the last
279 subpath that was added (or the initial start point). The
280 elementAt() function can be used to retrieve the various subpath
281 elements, the \e number of elements can be retrieved using the
282 elementCount() function, and the isEmpty() function tells whether
283 this QPainterPath object contains any elements at all.
284
285 The controlPointRect() function returns the rectangle containing
286 all the points and control points in this path. This function is
287 significantly faster to compute than the exact boundingRect()
288 which returns the bounding rectangle of this painter path with
289 floating point precision.
290
291 Finally, QPainterPath provides the contains() function which can
292 be used to determine whether a given point or rectangle is inside
293 the path, and the intersects() function which determines if any of
294 the points inside a given rectangle also are inside this path.
295
296 \section1 QPainterPath Conversion
297
298 For compatibility reasons, it might be required to simplify the
299 representation of a painter path: QPainterPath provides the
300 toFillPolygon(), toFillPolygons() and toSubpathPolygons()
301 functions which convert the painter path into a polygon. The
302 toFillPolygon() returns the painter path as one single polygon,
303 while the two latter functions return a list of polygons.
304
305 The toFillPolygons() and toSubpathPolygons() functions are
306 provided because it is usually faster to draw several small
307 polygons than to draw one large polygon, even though the total
308 number of points drawn is the same. The difference between the two
309 is the \e number of polygons they return: The toSubpathPolygons()
310 creates one polygon for each subpath regardless of intersecting
311 subpaths (i.e. overlapping bounding rectangles), while the
312 toFillPolygons() functions creates only one polygon for
313 overlapping subpaths.
314
315 The toFillPolygon() and toFillPolygons() functions first convert
316 all the subpaths to polygons, then uses a rewinding technique to
317 make sure that overlapping subpaths can be filled using the
318 correct fill rule. Note that rewinding inserts additional lines in
319 the polygon so the outline of the fill polygon does not match the
320 outline of the path.
321
322 \section1 Examples
323
324 Qt provides the \l {painting/painterpaths}{Painter Paths Example}
325 and the \l {painting/deform}{Vector Deformation example} which are
326 located in Qt's example directory.
327
328 The \l {painting/painterpaths}{Painter Paths Example} shows how
329 painter paths can be used to build complex shapes for rendering
330 and lets the user experiment with the filling and stroking. The
331 \l {painting/deform}{Vector Deformation Example} shows how to use
332 QPainterPath to draw text.
333
334 \table
335 \header
336 \li \l {painting/painterpaths}{Painter Paths Example}
337 \li \l {painting/deform}{Vector Deformation Example}
338 \row
339 \li \inlineimage qpainterpath-example.png
340 \li \inlineimage qpainterpath-demo.png
341 \endtable
342
343 \sa QPainterPathStroker, QPainter, QRegion, {Painter Paths Example}
344*/
345
346/*!
347 \enum QPainterPath::ElementType
348
349 This enum describes the types of elements used to connect vertices
350 in subpaths.
351
352 Note that elements added as closed subpaths using the
353 addEllipse(), addPath(), addPolygon(), addRect(), addRegion() and
354 addText() convenience functions, is actually added to the path as
355 a collection of separate elements using the moveTo(), lineTo() and
356 cubicTo() functions.
357
358 \value MoveToElement A new subpath. See also moveTo().
359 \value LineToElement A line. See also lineTo().
360 \value CurveToElement A curve. See also cubicTo() and quadTo().
361 \value CurveToDataElement The extra data required to describe a curve in
362 a CurveToElement element.
363
364 \sa elementAt(), elementCount()
365*/
366
367/*!
368 \class QPainterPath::Element
369 \inmodule QtGui
370
371 \brief The QPainterPath::Element class specifies the position and
372 type of a subpath.
373
374 Once a QPainterPath object is constructed, subpaths like lines and
375 curves can be added to the path (creating
376 QPainterPath::LineToElement and QPainterPath::CurveToElement
377 components).
378
379 The lines and curves stretch from the currentPosition() to the
380 position passed as argument. The currentPosition() of the
381 QPainterPath object is always the end position of the last subpath
382 that was added (or the initial start point). The moveTo() function
383 can be used to move the currentPosition() without adding a line or
384 curve, creating a QPainterPath::MoveToElement component.
385
386 \sa QPainterPath
387*/
388
389/*!
390 \variable QPainterPath::Element::x
391 \brief the x coordinate of the element's position.
392
393 \sa {operator QPointF()}
394*/
395
396/*!
397 \variable QPainterPath::Element::y
398 \brief the y coordinate of the element's position.
399
400 \sa {operator QPointF()}
401*/
402
403/*!
404 \variable QPainterPath::Element::type
405 \brief the type of element
406
407 \sa isCurveTo(), isLineTo(), isMoveTo()
408*/
409
410/*!
411 \fn bool QPainterPath::Element::operator==(const Element &other) const
412 \since 4.2
413
414 Returns \c true if this element is equal to \a other;
415 otherwise returns \c false.
416
417 \sa operator!=()
418*/
419
420/*!
421 \fn bool QPainterPath::Element::operator!=(const Element &other) const
422 \since 4.2
423
424 Returns \c true if this element is not equal to \a other;
425 otherwise returns \c false.
426
427 \sa operator==()
428*/
429
430/*!
431 \fn bool QPainterPath::Element::isCurveTo () const
432
433 Returns \c true if the element is a curve, otherwise returns \c false.
434
435 \sa type, QPainterPath::CurveToElement
436*/
437
438/*!
439 \fn bool QPainterPath::Element::isLineTo () const
440
441 Returns \c true if the element is a line, otherwise returns \c false.
442
443 \sa type, QPainterPath::LineToElement
444*/
445
446/*!
447 \fn bool QPainterPath::Element::isMoveTo () const
448
449 Returns \c true if the element is moving the current position,
450 otherwise returns \c false.
451
452 \sa type, QPainterPath::MoveToElement
453*/
454
455/*!
456 \fn QPainterPath::Element::operator QPointF () const
457
458 Returns the element's position.
459
460 \sa x, y
461*/
462
463/*!
464 \fn void QPainterPath::addEllipse(qreal x, qreal y, qreal width, qreal height)
465 \overload
466
467 Creates an ellipse within the bounding rectangle defined by its top-left
468 corner at (\a x, \a y), \a width and \a height, and adds it to the
469 painter path as a closed subpath.
470*/
471
472/*!
473 \since 4.4
474
475 \fn void QPainterPath::addEllipse(const QPointF &center, qreal rx, qreal ry)
476 \overload
477
478 Creates an ellipse positioned at \a{center} with radii \a{rx} and \a{ry},
479 and adds it to the painter path as a closed subpath.
480*/
481
482/*!
483 \fn void QPainterPath::addText(qreal x, qreal y, const QFont &font, const QString &text)
484 \overload
485
486 Adds the given \a text to this path as a set of closed subpaths created
487 from the \a font supplied. The subpaths are positioned so that the left
488 end of the text's baseline lies at the point specified by (\a x, \a y).
489*/
490
491/*!
492 \fn int QPainterPath::elementCount() const
493
494 Returns the number of path elements in the painter path.
495
496 \sa ElementType, elementAt(), isEmpty()
497*/
498
499int QPainterPath::elementCount() const
500{
501 return d_ptr ? d_ptr->elements.size() : 0;
502}
503
504/*!
505 \fn QPainterPath::Element QPainterPath::elementAt(int index) const
506
507 Returns the element at the given \a index in the painter path.
508
509 \sa ElementType, elementCount(), isEmpty()
510*/
511
512QPainterPath::Element QPainterPath::elementAt(int i) const
513{
514 Q_ASSERT(d_ptr);
515 Q_ASSERT(i >= 0 && i < elementCount());
516 return d_ptr->elements.at(i);
517}
518
519/*!
520 \fn void QPainterPath::setElementPositionAt(int index, qreal x, qreal y)
521 \since 4.2
522
523 Sets the x and y coordinate of the element at index \a index to \a
524 x and \a y.
525*/
526
527void QPainterPath::setElementPositionAt(int i, qreal x, qreal y)
528{
529 Q_ASSERT(d_ptr);
530 Q_ASSERT(i >= 0 && i < elementCount());
531 detach();
532 QPainterPath::Element &e = d_ptr->elements[i];
533 e.x = x;
534 e.y = y;
535}
536
537
538/*###
539 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
540
541 Appends the \a other painter path to this painter path and returns a
542 reference to the result.
543*/
544
545/*!
546 Constructs an empty QPainterPath object.
547*/
548QPainterPath::QPainterPath() noexcept
549 : d_ptr(0)
550{
551}
552
553/*!
554 \fn QPainterPath::QPainterPath(const QPainterPath &path)
555
556 Creates a QPainterPath object that is a copy of the given \a path.
557
558 \sa operator=()
559*/
560QPainterPath::QPainterPath(const QPainterPath &other)
561 : d_ptr(other.d_ptr.data())
562{
563 if (d_ptr)
564 d_ptr->ref.ref();
565}
566
567/*!
568 Creates a QPainterPath object with the given \a startPoint as its
569 current position.
570*/
571
572QPainterPath::QPainterPath(const QPointF &startPoint)
573 : d_ptr(new QPainterPathData)
574{
575 Element e = { startPoint.x(), startPoint.y(), MoveToElement };
576 d_func()->elements << e;
577}
578
579void QPainterPath::detach()
580{
581 if (d_ptr->ref.loadRelaxed() != 1)
582 detach_helper();
583 setDirty(true);
584}
585
586/*!
587 \internal
588*/
589void QPainterPath::detach_helper()
590{
591 QPainterPathPrivate *data = new QPainterPathData(*d_func());
592 d_ptr.reset(data);
593}
594
595/*!
596 \internal
597*/
598void QPainterPath::ensureData_helper()
599{
600 QPainterPathPrivate *data = new QPainterPathData;
601 data->elements.reserve(16);
602 QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
603 data->elements << e;
604 d_ptr.reset(data);
605 Q_ASSERT(d_ptr != 0);
606}
607
608/*!
609 \fn QPainterPath &QPainterPath::operator=(const QPainterPath &path)
610
611 Assigns the given \a path to this painter path.
612
613 \sa QPainterPath()
614*/
615QPainterPath &QPainterPath::operator=(const QPainterPath &other)
616{
617 if (other.d_func() != d_func()) {
618 QPainterPathPrivate *data = other.d_func();
619 if (data)
620 data->ref.ref();
621 d_ptr.reset(data);
622 }
623 return *this;
624}
625
626/*!
627 \fn QPainterPath &QPainterPath::operator=(QPainterPath &&other)
628
629 Move-assigns \a other to this QPainterPath instance.
630
631 \since 5.2
632*/
633
634/*!
635 \fn void QPainterPath::swap(QPainterPath &other)
636 \since 4.8
637
638 Swaps painter path \a other with this painter path. This operation is very
639 fast and never fails.
640*/
641
642/*!
643 Destroys this QPainterPath object.
644*/
645QPainterPath::~QPainterPath()
646{
647}
648
649/*!
650 Clears the path elements stored.
651
652 This allows the path to reuse previous memory allocations.
653
654 \sa reserve(), capacity()
655 \since 5.13
656*/
657void QPainterPath::clear()
658{
659 if (!d_ptr)
660 return;
661
662 detach();
663 d_func()->clear();
664 d_func()->elements.append( {0, 0, MoveToElement} );
665}
666
667/*!
668 Reserves a given amount of elements in QPainterPath's internal memory.
669
670 Attempts to allocate memory for at least \a size elements.
671
672 \sa clear(), capacity(), QVector::reserve()
673 \since 5.13
674*/
675void QPainterPath::reserve(int size)
676{
677 Q_D(QPainterPath);
678 if ((!d && size > 0) || (d && d->elements.capacity() < size)) {
679 ensureData();
680 detach();
681 d_func()->elements.reserve(size);
682 }
683}
684
685/*!
686 Returns the number of elements allocated by the QPainterPath.
687
688 \sa clear(), reserve()
689 \since 5.13
690*/
691int QPainterPath::capacity() const
692{
693 Q_D(QPainterPath);
694 if (d)
695 return d->elements.capacity();
696
697 return 0;
698}
699
700/*!
701 Closes the current subpath by drawing a line to the beginning of
702 the subpath, automatically starting a new path. The current point
703 of the new path is (0, 0).
704
705 If the subpath does not contain any elements, this function does
706 nothing.
707
708 \sa moveTo(), {QPainterPath#Composing a QPainterPath}{Composing
709 a QPainterPath}
710 */
711void QPainterPath::closeSubpath()
712{
713#ifdef QPP_DEBUG
714 printf("QPainterPath::closeSubpath()\n");
715#endif
716 if (isEmpty())
717 return;
718 detach();
719
720 d_func()->close();
721}
722
723/*!
724 \fn void QPainterPath::moveTo(qreal x, qreal y)
725
726 \overload
727
728 Moves the current position to (\a{x}, \a{y}) and starts a new
729 subpath, implicitly closing the previous path.
730*/
731
732/*!
733 \fn void QPainterPath::moveTo(const QPointF &point)
734
735 Moves the current point to the given \a point, implicitly starting
736 a new subpath and closing the previous one.
737
738 \sa closeSubpath(), {QPainterPath#Composing a
739 QPainterPath}{Composing a QPainterPath}
740*/
741void QPainterPath::moveTo(const QPointF &p)
742{
743#ifdef QPP_DEBUG
744 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
745#endif
746
747 if (!hasValidCoords(p)) {
748#ifndef QT_NO_DEBUG
749 qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call");
750#endif
751 return;
752 }
753
754 ensureData();
755 detach();
756
757 QPainterPathData *d = d_func();
758 Q_ASSERT(!d->elements.isEmpty());
759
760 d->require_moveTo = false;
761
762 if (d->elements.constLast().type == MoveToElement) {
763 d->elements.last().x = p.x();
764 d->elements.last().y = p.y();
765 } else {
766 Element elm = { p.x(), p.y(), MoveToElement };
767 d->elements.append(elm);
768 }
769 d->cStart = d->elements.size() - 1;
770}
771
772/*!
773 \fn void QPainterPath::lineTo(qreal x, qreal y)
774
775 \overload
776
777 Draws a line from the current position to the point (\a{x},
778 \a{y}).
779*/
780
781/*!
782 \fn void QPainterPath::lineTo(const QPointF &endPoint)
783
784 Adds a straight line from the current position to the given \a
785 endPoint. After the line is drawn, the current position is updated
786 to be at the end point of the line.
787
788 \sa addPolygon(), addRect(), {QPainterPath#Composing a
789 QPainterPath}{Composing a QPainterPath}
790 */
791void QPainterPath::lineTo(const QPointF &p)
792{
793#ifdef QPP_DEBUG
794 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
795#endif
796
797 if (!hasValidCoords(p)) {
798#ifndef QT_NO_DEBUG
799 qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call");
800#endif
801 return;
802 }
803
804 ensureData();
805 detach();
806
807 QPainterPathData *d = d_func();
808 Q_ASSERT(!d->elements.isEmpty());
809 d->maybeMoveTo();
810 if (p == QPointF(d->elements.constLast()))
811 return;
812 Element elm = { p.x(), p.y(), LineToElement };
813 d->elements.append(elm);
814
815 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
816}
817
818/*!
819 \fn void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X,
820 qreal c2Y, qreal endPointX, qreal endPointY);
821
822 \overload
823
824 Adds a cubic Bezier curve between the current position and the end
825 point (\a{endPointX}, \a{endPointY}) with control points specified
826 by (\a{c1X}, \a{c1Y}) and (\a{c2X}, \a{c2Y}).
827*/
828
829/*!
830 \fn void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
831
832 Adds a cubic Bezier curve between the current position and the
833 given \a endPoint using the control points specified by \a c1, and
834 \a c2.
835
836 After the curve is added, the current position is updated to be at
837 the end point of the curve.
838
839 \table 100%
840 \row
841 \li \inlineimage qpainterpath-cubicto.png
842 \li
843 \snippet code/src_gui_painting_qpainterpath.cpp 1
844 \endtable
845
846 \sa quadTo(), {QPainterPath#Composing a QPainterPath}{Composing
847 a QPainterPath}
848*/
849void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
850{
851#ifdef QPP_DEBUG
852 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
853 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
854#endif
855
856 if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) {
857#ifndef QT_NO_DEBUG
858 qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call");
859#endif
860 return;
861 }
862
863 ensureData();
864 detach();
865
866 QPainterPathData *d = d_func();
867 Q_ASSERT(!d->elements.isEmpty());
868
869
870 // Abort on empty curve as a stroker cannot handle this and the
871 // curve is irrelevant anyway.
872 if (d->elements.constLast() == c1 && c1 == c2 && c2 == e)
873 return;
874
875 d->maybeMoveTo();
876
877 Element ce1 = { c1.x(), c1.y(), CurveToElement };
878 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
879 Element ee = { e.x(), e.y(), CurveToDataElement };
880 d->elements << ce1 << ce2 << ee;
881}
882
883/*!
884 \fn void QPainterPath::quadTo(qreal cx, qreal cy, qreal endPointX, qreal endPointY);
885
886 \overload
887
888 Adds a quadratic Bezier curve between the current point and the endpoint
889 (\a{endPointX}, \a{endPointY}) with the control point specified by
890 (\a{cx}, \a{cy}).
891*/
892
893/*!
894 \fn void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)
895
896 Adds a quadratic Bezier curve between the current position and the
897 given \a endPoint with the control point specified by \a c.
898
899 After the curve is added, the current point is updated to be at
900 the end point of the curve.
901
902 \sa cubicTo(), {QPainterPath#Composing a QPainterPath}{Composing a
903 QPainterPath}
904*/
905void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
906{
907#ifdef QPP_DEBUG
908 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
909 c.x(), c.y(), e.x(), e.y());
910#endif
911
912 if (!hasValidCoords(c) || !hasValidCoords(e)) {
913#ifndef QT_NO_DEBUG
914 qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call");
915#endif
916 return;
917 }
918
919 ensureData();
920 detach();
921
922 Q_D(QPainterPath);
923 Q_ASSERT(!d->elements.isEmpty());
924 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
925 QPointF prev(elm.x, elm.y);
926
927 // Abort on empty curve as a stroker cannot handle this and the
928 // curve is irrelevant anyway.
929 if (prev == c && c == e)
930 return;
931
932 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
933 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
934 cubicTo(c1, c2, e);
935}
936
937/*!
938 \fn void QPainterPath::arcTo(qreal x, qreal y, qreal width, qreal
939 height, qreal startAngle, qreal sweepLength)
940
941 \overload
942
943 Creates an arc that occupies the rectangle QRectF(\a x, \a y, \a
944 width, \a height), beginning at the specified \a startAngle and
945 extending \a sweepLength degrees counter-clockwise.
946
947*/
948
949/*!
950 \fn void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
951
952 Creates an arc that occupies the given \a rectangle, beginning at
953 the specified \a startAngle and extending \a sweepLength degrees
954 counter-clockwise.
955
956 Angles are specified in degrees. Clockwise arcs can be specified
957 using negative angles.
958
959 Note that this function connects the starting point of the arc to
960 the current position if they are not already connected. After the
961 arc has been added, the current position is the last point in
962 arc. To draw a line back to the first point, use the
963 closeSubpath() function.
964
965 \table 100%
966 \row
967 \li \inlineimage qpainterpath-arcto.png
968 \li
969 \snippet code/src_gui_painting_qpainterpath.cpp 2
970 \endtable
971
972 \sa arcMoveTo(), addEllipse(), QPainter::drawArc(), QPainter::drawPie(),
973 {QPainterPath#Composing a QPainterPath}{Composing a
974 QPainterPath}
975*/
976void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
977{
978#ifdef QPP_DEBUG
979 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
980 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
981#endif
982
983 if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) {
984#ifndef QT_NO_DEBUG
985 qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call");
986#endif
987 return;
988 }
989
990 if (rect.isNull())
991 return;
992
993 ensureData();
994 detach();
995
996 int point_count;
997 QPointF pts[15];
998 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
999
1000 lineTo(curve_start);
1001 for (int i=0; i<point_count; i+=3) {
1002 cubicTo(pts[i].x(), pts[i].y(),
1003 pts[i+1].x(), pts[i+1].y(),
1004 pts[i+2].x(), pts[i+2].y());
1005 }
1006
1007}
1008
1009
1010/*!
1011 \fn void QPainterPath::arcMoveTo(qreal x, qreal y, qreal width, qreal height, qreal angle)
1012 \overload
1013 \since 4.2
1014
1015 Creates a move to that lies on the arc that occupies the
1016 QRectF(\a x, \a y, \a width, \a height) at \a angle.
1017*/
1018
1019
1020/*!
1021 \fn void QPainterPath::arcMoveTo(const QRectF &rectangle, qreal angle)
1022 \since 4.2
1023
1024 Creates a move to that lies on the arc that occupies the given \a
1025 rectangle at \a angle.
1026
1027 Angles are specified in degrees. Clockwise arcs can be specified
1028 using negative angles.
1029
1030 \sa moveTo(), arcTo()
1031*/
1032
1033void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle)
1034{
1035 if (rect.isNull())
1036 return;
1037
1038 QPointF pt;
1039 qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
1040 moveTo(pt);
1041}
1042
1043
1044
1045/*!
1046 \fn QPointF QPainterPath::currentPosition() const
1047
1048 Returns the current position of the path.
1049*/
1050QPointF QPainterPath::currentPosition() const
1051{
1052 return !d_ptr || d_func()->elements.isEmpty()
1053 ? QPointF()
1054 : QPointF(d_func()->elements.constLast().x, d_func()->elements.constLast().y);
1055}
1056
1057
1058/*!
1059 \fn void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
1060
1061 \overload
1062
1063 Adds a rectangle at position (\a{x}, \a{y}), with the given \a
1064 width and \a height, as a closed subpath.
1065*/
1066
1067/*!
1068 \fn void QPainterPath::addRect(const QRectF &rectangle)
1069
1070 Adds the given \a rectangle to this path as a closed subpath.
1071
1072 The \a rectangle is added as a clockwise set of lines. The painter
1073 path's current position after the \a rectangle has been added is
1074 at the top-left corner of the rectangle.
1075
1076 \table 100%
1077 \row
1078 \li \inlineimage qpainterpath-addrectangle.png
1079 \li
1080 \snippet code/src_gui_painting_qpainterpath.cpp 3
1081 \endtable
1082
1083 \sa addRegion(), lineTo(), {QPainterPath#Composing a
1084 QPainterPath}{Composing a QPainterPath}
1085*/
1086void QPainterPath::addRect(const QRectF &r)
1087{
1088 if (!hasValidCoords(r)) {
1089#ifndef QT_NO_DEBUG
1090 qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call");
1091#endif
1092 return;
1093 }
1094
1095 if (r.isNull())
1096 return;
1097
1098 ensureData();
1099 detach();
1100
1101 bool first = d_func()->elements.size() < 2;
1102
1103 moveTo(r.x(), r.y());
1104
1105 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1106 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1107 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1108 Element l4 = { r.x(), r.y(), LineToElement };
1109
1110 d_func()->elements << l1 << l2 << l3 << l4;
1111 d_func()->require_moveTo = true;
1112 d_func()->convex = first;
1113}
1114
1115/*!
1116 Adds the given \a polygon to the path as an (unclosed) subpath.
1117
1118 Note that the current position after the polygon has been added,
1119 is the last point in \a polygon. To draw a line back to the first
1120 point, use the closeSubpath() function.
1121
1122 \table 100%
1123 \row
1124 \li \inlineimage qpainterpath-addpolygon.png
1125 \li
1126 \snippet code/src_gui_painting_qpainterpath.cpp 4
1127 \endtable
1128
1129 \sa lineTo(), {QPainterPath#Composing a QPainterPath}{Composing
1130 a QPainterPath}
1131*/
1132void QPainterPath::addPolygon(const QPolygonF &polygon)
1133{
1134 if (polygon.isEmpty())
1135 return;
1136
1137 ensureData();
1138 detach();
1139
1140 moveTo(polygon.constFirst());
1141 for (int i=1; i<polygon.size(); ++i) {
1142 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1143 d_func()->elements << elm;
1144 }
1145}
1146
1147/*!
1148 \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle)
1149
1150 Creates an ellipse within the specified \a boundingRectangle
1151 and adds it to the painter path as a closed subpath.
1152
1153 The ellipse is composed of a clockwise curve, starting and
1154 finishing at zero degrees (the 3 o'clock position).
1155
1156 \table 100%
1157 \row
1158 \li \inlineimage qpainterpath-addellipse.png
1159 \li
1160 \snippet code/src_gui_painting_qpainterpath.cpp 5
1161 \endtable
1162
1163 \sa arcTo(), QPainter::drawEllipse(), {QPainterPath#Composing a
1164 QPainterPath}{Composing a QPainterPath}
1165*/
1166void QPainterPath::addEllipse(const QRectF &boundingRect)
1167{
1168 if (!hasValidCoords(boundingRect)) {
1169#ifndef QT_NO_DEBUG
1170 qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call");
1171#endif
1172 return;
1173 }
1174
1175 if (boundingRect.isNull())
1176 return;
1177
1178 ensureData();
1179 detach();
1180
1181 bool first = d_func()->elements.size() < 2;
1182
1183 QPointF pts[12];
1184 int point_count;
1185 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1186
1187 moveTo(start);
1188 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1189 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1190 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1191 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1192 d_func()->require_moveTo = true;
1193
1194 d_func()->convex = first;
1195}
1196
1197/*!
1198 \fn void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
1199
1200 Adds the given \a text to this path as a set of closed subpaths
1201 created from the \a font supplied. The subpaths are positioned so
1202 that the left end of the text's baseline lies at the specified \a
1203 point.
1204
1205 \table 100%
1206 \row
1207 \li \inlineimage qpainterpath-addtext.png
1208 \li
1209 \snippet code/src_gui_painting_qpainterpath.cpp 6
1210 \endtable
1211
1212 \sa QPainter::drawText(), {QPainterPath#Composing a
1213 QPainterPath}{Composing a QPainterPath}
1214*/
1215void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1216{
1217 if (text.isEmpty())
1218 return;
1219
1220 ensureData();
1221 detach();
1222
1223 QTextLayout layout(text, f);
1224 layout.setCacheEnabled(true);
1225 QTextEngine *eng = layout.engine();
1226 layout.beginLayout();
1227 QTextLine line = layout.createLine();
1228 Q_UNUSED(line);
1229 layout.endLayout();
1230 const QScriptLine &sl = eng->lines[0];
1231 if (!sl.length || !eng->layoutData)
1232 return;
1233
1234 int nItems = eng->layoutData->items.size();
1235
1236 qreal x(point.x());
1237 qreal y(point.y());
1238
1239 QVarLengthArray<int> visualOrder(nItems);
1240 QVarLengthArray<uchar> levels(nItems);
1241 for (int i = 0; i < nItems; ++i)
1242 levels[i] = eng->layoutData->items.at(i).analysis.bidiLevel;
1243 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1244
1245 for (int i = 0; i < nItems; ++i) {
1246 int item = visualOrder[i];
1247 const QScriptItem &si = eng->layoutData->items.at(item);
1248
1249 if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
1250 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1251 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
1252 Q_ASSERT(fe);
1253 fe->addOutlineToPath(x, y, glyphs, this,
1254 si.analysis.bidiLevel % 2
1255 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1256 : QTextItem::RenderFlags(0));
1257
1258 const qreal lw = fe->lineThickness().toReal();
1259 if (f.d->underline) {
1260 qreal pos = fe->underlinePosition().toReal();
1261 addRect(x, y + pos, si.width.toReal(), lw);
1262 }
1263 if (f.d->overline) {
1264 qreal pos = fe->ascent().toReal() + 1;
1265 addRect(x, y - pos, si.width.toReal(), lw);
1266 }
1267 if (f.d->strikeOut) {
1268 qreal pos = fe->ascent().toReal() / 3;
1269 addRect(x, y - pos, si.width.toReal(), lw);
1270 }
1271 }
1272 x += si.width.toReal();
1273 }
1274}
1275
1276/*!
1277 \fn void QPainterPath::addPath(const QPainterPath &path)
1278
1279 Adds the given \a path to \e this path as a closed subpath.
1280
1281 \sa connectPath(), {QPainterPath#Composing a
1282 QPainterPath}{Composing a QPainterPath}
1283*/
1284void QPainterPath::addPath(const QPainterPath &other)
1285{
1286 if (other.isEmpty())
1287 return;
1288
1289 ensureData();
1290 detach();
1291
1292 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1293 // Remove last moveto so we don't get multiple moveto's
1294 if (d->elements.constLast().type == MoveToElement)
1295 d->elements.remove(d->elements.size()-1);
1296
1297 // Locate where our own current subpath will start after the other path is added.
1298 int cStart = d->elements.size() + other.d_func()->cStart;
1299 d->elements += other.d_func()->elements;
1300 d->cStart = cStart;
1301
1302 d->require_moveTo = other.d_func()->isClosed();
1303}
1304
1305
1306/*!
1307 \fn void QPainterPath::connectPath(const QPainterPath &path)
1308
1309 Connects the given \a path to \e this path by adding a line from the
1310 last element of this path to the first element of the given path.
1311
1312 \sa addPath(), {QPainterPath#Composing a QPainterPath}{Composing
1313 a QPainterPath}
1314*/
1315void QPainterPath::connectPath(const QPainterPath &other)
1316{
1317 if (other.isEmpty())
1318 return;
1319
1320 ensureData();
1321 detach();
1322
1323 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1324 // Remove last moveto so we don't get multiple moveto's
1325 if (d->elements.constLast().type == MoveToElement)
1326 d->elements.remove(d->elements.size()-1);
1327
1328 // Locate where our own current subpath will start after the other path is added.
1329 int cStart = d->elements.size() + other.d_func()->cStart;
1330 int first = d->elements.size();
1331 d->elements += other.d_func()->elements;
1332
1333 if (first != 0)
1334 d->elements[first].type = LineToElement;
1335
1336 // avoid duplicate points
1337 if (first > 0 && QPointF(d->elements.at(first)) == QPointF(d->elements.at(first - 1))) {
1338 d->elements.remove(first--);
1339 --cStart;
1340 }
1341
1342 if (cStart != first)
1343 d->cStart = cStart;
1344}
1345
1346/*!
1347 Adds the given \a region to the path by adding each rectangle in
1348 the region as a separate closed subpath.
1349
1350 \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
1351 a QPainterPath}
1352*/
1353void QPainterPath::addRegion(const QRegion &region)
1354{
1355 ensureData();
1356 detach();
1357
1358 for (const QRect &rect : region)
1359 addRect(rect);
1360}
1361
1362
1363/*!
1364 Returns the painter path's currently set fill rule.
1365
1366 \sa setFillRule()
1367*/
1368Qt::FillRule QPainterPath::fillRule() const
1369{
1370 return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1371}
1372
1373/*!
1374 \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
1375
1376 Sets the fill rule of the painter path to the given \a
1377 fillRule. Qt provides two methods for filling paths:
1378
1379 \table
1380 \header
1381 \li Qt::OddEvenFill (default)
1382 \li Qt::WindingFill
1383 \row
1384 \li \inlineimage qt-fillrule-oddeven.png
1385 \li \inlineimage qt-fillrule-winding.png
1386 \endtable
1387
1388 \sa fillRule()
1389*/
1390void QPainterPath::setFillRule(Qt::FillRule fillRule)
1391{
1392 ensureData();
1393 if (d_func()->fillRule == fillRule)
1394 return;
1395 detach();
1396
1397 d_func()->fillRule = fillRule;
1398}
1399
1400#define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1401 + 3*bezier.coord##2 \
1402 - 3*bezier.coord##3 \
1403 +bezier.coord##4)
1404
1405#define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1406 - 2*bezier.coord##2 \
1407 + bezier.coord##3)
1408
1409#define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1410 + bezier.coord##2)
1411
1412#define QT_BEZIER_CHECK_T(bezier, t) \
1413 if (t >= 0 && t <= 1) { \
1414 QPointF p(b.pointAt(t)); \
1415 if (p.x() < minx) minx = p.x(); \
1416 else if (p.x() > maxx) maxx = p.x(); \
1417 if (p.y() < miny) miny = p.y(); \
1418 else if (p.y() > maxy) maxy = p.y(); \
1419 }
1420
1421
1422static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1423{
1424 qreal minx, miny, maxx, maxy;
1425
1426 // initialize with end points
1427 if (b.x1 < b.x4) {
1428 minx = b.x1;
1429 maxx = b.x4;
1430 } else {
1431 minx = b.x4;
1432 maxx = b.x1;
1433 }
1434 if (b.y1 < b.y4) {
1435 miny = b.y1;
1436 maxy = b.y4;
1437 } else {
1438 miny = b.y4;
1439 maxy = b.y1;
1440 }
1441
1442 // Update for the X extrema
1443 {
1444 qreal ax = QT_BEZIER_A(b, x);
1445 qreal bx = QT_BEZIER_B(b, x);
1446 qreal cx = QT_BEZIER_C(b, x);
1447 // specialcase quadratic curves to avoid div by zero
1448 if (qFuzzyIsNull(ax)) {
1449
1450 // linear curves are covered by initialization.
1451 if (!qFuzzyIsNull(bx)) {
1452 qreal t = -cx / bx;
1453 QT_BEZIER_CHECK_T(b, t);
1454 }
1455
1456 } else {
1457 const qreal tx = bx * bx - 4 * ax * cx;
1458
1459 if (tx >= 0) {
1460 qreal temp = qSqrt(tx);
1461 qreal rcp = 1 / (2 * ax);
1462 qreal t1 = (-bx + temp) * rcp;
1463 QT_BEZIER_CHECK_T(b, t1);
1464
1465 qreal t2 = (-bx - temp) * rcp;
1466 QT_BEZIER_CHECK_T(b, t2);
1467 }
1468 }
1469 }
1470
1471 // Update for the Y extrema
1472 {
1473 qreal ay = QT_BEZIER_A(b, y);
1474 qreal by = QT_BEZIER_B(b, y);
1475 qreal cy = QT_BEZIER_C(b, y);
1476
1477 // specialcase quadratic curves to avoid div by zero
1478 if (qFuzzyIsNull(ay)) {
1479
1480 // linear curves are covered by initialization.
1481 if (!qFuzzyIsNull(by)) {
1482 qreal t = -cy / by;
1483 QT_BEZIER_CHECK_T(b, t);
1484 }
1485
1486 } else {
1487 const qreal ty = by * by - 4 * ay * cy;
1488
1489 if (ty > 0) {
1490 qreal temp = qSqrt(ty);
1491 qreal rcp = 1 / (2 * ay);
1492 qreal t1 = (-by + temp) * rcp;
1493 QT_BEZIER_CHECK_T(b, t1);
1494
1495 qreal t2 = (-by - temp) * rcp;
1496 QT_BEZIER_CHECK_T(b, t2);
1497 }
1498 }
1499 }
1500 return QRectF(minx, miny, maxx - minx, maxy - miny);
1501}
1502
1503/*!
1504 Returns the bounding rectangle of this painter path as a rectangle with
1505 floating point precision.
1506
1507 \sa controlPointRect()
1508*/
1509QRectF QPainterPath::boundingRect() const
1510{
1511 if (!d_ptr)
1512 return QRectF();
1513 QPainterPathData *d = d_func();
1514
1515 if (d->dirtyBounds)
1516 computeBoundingRect();
1517 return d->bounds;
1518}
1519
1520/*!
1521 Returns the rectangle containing all the points and control points
1522 in this path.
1523
1524 This function is significantly faster to compute than the exact
1525 boundingRect(), and the returned rectangle is always a superset of
1526 the rectangle returned by boundingRect().
1527
1528 \sa boundingRect()
1529*/
1530QRectF QPainterPath::controlPointRect() const
1531{
1532 if (!d_ptr)
1533 return QRectF();
1534 QPainterPathData *d = d_func();
1535
1536 if (d->dirtyControlBounds)
1537 computeControlPointRect();
1538 return d->controlBounds;
1539}
1540
1541
1542/*!
1543 \fn bool QPainterPath::isEmpty() const
1544
1545 Returns \c true if either there are no elements in this path, or if the only
1546 element is a MoveToElement; otherwise returns \c false.
1547
1548 \sa elementCount()
1549*/
1550
1551bool QPainterPath::isEmpty() const
1552{
1553 return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
1554}
1555
1556/*!
1557 Creates and returns a reversed copy of the path.
1558
1559 It is the order of the elements that is reversed: If a
1560 QPainterPath is composed by calling the moveTo(), lineTo() and
1561 cubicTo() functions in the specified order, the reversed copy is
1562 composed by calling cubicTo(), lineTo() and moveTo().
1563*/
1564QPainterPath QPainterPath::toReversed() const
1565{
1566 Q_D(const QPainterPath);
1567 QPainterPath rev;
1568
1569 if (isEmpty()) {
1570 rev = *this;
1571 return rev;
1572 }
1573
1574 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1575
1576 for (int i=d->elements.size()-1; i>=1; --i) {
1577 const QPainterPath::Element &elm = d->elements.at(i);
1578 const QPainterPath::Element &prev = d->elements.at(i-1);
1579 switch (elm.type) {
1580 case LineToElement:
1581 rev.lineTo(prev.x, prev.y);
1582 break;
1583 case MoveToElement:
1584 rev.moveTo(prev.x, prev.y);
1585 break;
1586 case CurveToDataElement:
1587 {
1588 Q_ASSERT(i>=3);
1589 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1590 const QPainterPath::Element &sp = d->elements.at(i-3);
1591 Q_ASSERT(prev.type == CurveToDataElement);
1592 Q_ASSERT(cp1.type == CurveToElement);
1593 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1594 i -= 2;
1595 break;
1596 }
1597 default:
1598 Q_ASSERT(!"qt_reversed_path");
1599 break;
1600 }
1601 }
1602 //qt_debug_path(rev);
1603 return rev;
1604}
1605
1606/*!
1607 Converts the path into a list of polygons using the QTransform
1608 \a matrix, and returns the list.
1609
1610 This function creates one polygon for each subpath regardless of
1611 intersecting subpaths (i.e. overlapping bounding rectangles). To
1612 make sure that such overlapping subpaths are filled correctly, use
1613 the toFillPolygons() function instead.
1614
1615 \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
1616 Conversion}{QPainterPath Conversion}
1617*/
1618QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
1619{
1620
1621 Q_D(const QPainterPath);
1622 QList<QPolygonF> flatCurves;
1623 if (isEmpty())
1624 return flatCurves;
1625
1626 QPolygonF current;
1627 for (int i=0; i<elementCount(); ++i) {
1628 const QPainterPath::Element &e = d->elements.at(i);
1629 switch (e.type) {
1630 case QPainterPath::MoveToElement:
1631 if (current.size() > 1)
1632 flatCurves += current;
1633 current.clear();
1634 current.reserve(16);
1635 current += QPointF(e.x, e.y) * matrix;
1636 break;
1637 case QPainterPath::LineToElement:
1638 current += QPointF(e.x, e.y) * matrix;
1639 break;
1640 case QPainterPath::CurveToElement: {
1641 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1642 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1643 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1644 QPointF(e.x, e.y) * matrix,
1645 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1646 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1647 bezier.addToPolygon(&current);
1648 i+=2;
1649 break;
1650 }
1651 case QPainterPath::CurveToDataElement:
1652 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1653 break;
1654 }
1655 }
1656
1657 if (current.size()>1)
1658 flatCurves += current;
1659
1660 return flatCurves;
1661}
1662
1663/*!
1664 \overload
1665 */
1666QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
1667{
1668 return toSubpathPolygons(QTransform(matrix));
1669}
1670
1671/*!
1672 Converts the path into a list of polygons using the
1673 QTransform \a matrix, and returns the list.
1674
1675 The function differs from the toFillPolygon() function in that it
1676 creates several polygons. It is provided because it is usually
1677 faster to draw several small polygons than to draw one large
1678 polygon, even though the total number of points drawn is the same.
1679
1680 The toFillPolygons() function differs from the toSubpathPolygons()
1681 function in that it create only polygon for subpaths that have
1682 overlapping bounding rectangles.
1683
1684 Like the toFillPolygon() function, this function uses a rewinding
1685 technique to make sure that overlapping subpaths can be filled
1686 using the correct fill rule. Note that rewinding inserts addition
1687 lines in the polygons so the outline of the fill polygon does not
1688 match the outline of the path.
1689
1690 \sa toSubpathPolygons(), toFillPolygon(),
1691 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
1692*/
1693QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1694{
1695
1696 QList<QPolygonF> polys;
1697
1698 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1699 int count = subpaths.size();
1700
1701 if (count == 0)
1702 return polys;
1703
1704 QVector<QRectF> bounds;
1705 bounds.reserve(count);
1706 for (int i=0; i<count; ++i)
1707 bounds += subpaths.at(i).boundingRect();
1708
1709#ifdef QPP_FILLPOLYGONS_DEBUG
1710 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1711 for (int i=0; i<bounds.size(); ++i)
1712 qDebug() << " bounds" << i << bounds.at(i);
1713#endif
1714
1715 QVector< QVector<int> > isects;
1716 isects.resize(count);
1717
1718 // find all intersections
1719 for (int j=0; j<count; ++j) {
1720 if (subpaths.at(j).size() <= 2)
1721 continue;
1722 QRectF cbounds = bounds.at(j);
1723 for (int i=0; i<count; ++i) {
1724 if (cbounds.intersects(bounds.at(i))) {
1725 isects[j] << i;
1726 }
1727 }
1728 }
1729
1730#ifdef QPP_FILLPOLYGONS_DEBUG
1731 printf("Intersections before flattening:\n");
1732 for (int i = 0; i < count; ++i) {
1733 printf("%d: ", i);
1734 for (int j = 0; j < isects[i].size(); ++j) {
1735 printf("%d ", isects[i][j]);
1736 }
1737 printf("\n");
1738 }
1739#endif
1740
1741 // flatten the sets of intersections
1742 for (int i=0; i<count; ++i) {
1743 const QVector<int> &current_isects = isects.at(i);
1744 for (int j=0; j<current_isects.size(); ++j) {
1745 int isect_j = current_isects.at(j);
1746 if (isect_j == i)
1747 continue;
1748 const QVector<int> &isects_j = isects.at(isect_j);
1749 for (int k = 0, size = isects_j.size(); k < size; ++k) {
1750 int isect_k = isects_j.at(k);
1751 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1752 isects[i] += isect_k;
1753 }
1754 }
1755 isects[isect_j].clear();
1756 }
1757 }
1758
1759#ifdef QPP_FILLPOLYGONS_DEBUG
1760 printf("Intersections after flattening:\n");
1761 for (int i = 0; i < count; ++i) {
1762 printf("%d: ", i);
1763 for (int j = 0; j < isects[i].size(); ++j) {
1764 printf("%d ", isects[i][j]);
1765 }
1766 printf("\n");
1767 }
1768#endif
1769
1770 // Join the intersected subpaths as rewinded polygons
1771 for (int i=0; i<count; ++i) {
1772 const QVector<int> &subpath_list = isects.at(i);
1773 if (!subpath_list.isEmpty()) {
1774 QPolygonF buildUp;
1775 for (int j=0; j<subpath_list.size(); ++j) {
1776 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1777 buildUp += subpath;
1778 if (!subpath.isClosed())
1779 buildUp += subpath.first();
1780 if (!buildUp.isClosed())
1781 buildUp += buildUp.constFirst();
1782 }
1783 polys += buildUp;
1784 }
1785 }
1786
1787 return polys;
1788}
1789
1790/*!
1791 \overload
1792 */
1793QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
1794{
1795 return toFillPolygons(QTransform(matrix));
1796}
1797
1798//same as qt_polygon_isect_line in qpolygon.cpp
1799static void qt_painterpath_isect_line(const QPointF &p1,
1800 const QPointF &p2,
1801 const QPointF &pos,
1802 int *winding)
1803{
1804 qreal x1 = p1.x();
1805 qreal y1 = p1.y();
1806 qreal x2 = p2.x();
1807 qreal y2 = p2.y();
1808 qreal y = pos.y();
1809
1810 int dir = 1;
1811
1812 if (qFuzzyCompare(y1, y2)) {
1813 // ignore horizontal lines according to scan conversion rule
1814 return;
1815 } else if (y2 < y1) {
1816 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1817 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1818 dir = -1;
1819 }
1820
1821 if (y >= y1 && y < y2) {
1822 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1823
1824 // count up the winding number if we're
1825 if (x<=pos.x()) {
1826 (*winding) += dir;
1827 }
1828 }
1829}
1830
1831static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1832 int *winding, int depth = 0)
1833{
1834 qreal y = pt.y();
1835 qreal x = pt.x();
1836 QRectF bounds = bezier.bounds();
1837
1838 // potential intersection, divide and try again...
1839 // Please note that a sideeffect of the bottom exclusion is that
1840 // horizontal lines are dropped, but this is correct according to
1841 // scan conversion rules.
1842 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1843
1844 // hit lower limit... This is a rough threshold, but its a
1845 // tradeoff between speed and precision.
1846 const qreal lower_bound = qreal(.001);
1847 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1848 // We make the assumption here that the curve starts to
1849 // approximate a line after while (i.e. that it doesn't
1850 // change direction drastically during its slope)
1851 if (bezier.pt1().x() <= x) {
1852 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1853 }
1854 return;
1855 }
1856
1857 // split curve and try again...
1858 QBezier first_half, second_half;
1859 bezier.split(&first_half, &second_half);
1860 qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
1861 qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
1862 }
1863}
1864
1865/*!
1866 \fn bool QPainterPath::contains(const QPointF &point) const
1867
1868 Returns \c true if the given \a point is inside the path, otherwise
1869 returns \c false.
1870
1871 \sa intersects()
1872*/
1873bool QPainterPath::contains(const QPointF &pt) const
1874{
1875 if (isEmpty() || !controlPointRect().contains(pt))
1876 return false;
1877
1878 QPainterPathData *d = d_func();
1879
1880 int winding_number = 0;
1881
1882 QPointF last_pt;
1883 QPointF last_start;
1884 for (int i=0; i<d->elements.size(); ++i) {
1885 const Element &e = d->elements.at(i);
1886
1887 switch (e.type) {
1888
1889 case MoveToElement:
1890 if (i > 0) // implicitly close all paths.
1891 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1892 last_start = last_pt = e;
1893 break;
1894
1895 case LineToElement:
1896 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1897 last_pt = e;
1898 break;
1899
1900 case CurveToElement:
1901 {
1902 const QPainterPath::Element &cp2 = d->elements.at(++i);
1903 const QPainterPath::Element &ep = d->elements.at(++i);
1904 qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1905 pt, &winding_number);
1906 last_pt = ep;
1907
1908 }
1909 break;
1910
1911 default:
1912 break;
1913 }
1914 }
1915
1916 // implicitly close last subpath
1917 if (last_pt != last_start)
1918 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1919
1920 return (d->fillRule == Qt::WindingFill
1921 ? (winding_number != 0)
1922 : ((winding_number % 2) != 0));
1923}
1924
1925enum PainterDirections { Left, Right, Top, Bottom };
1926
1927static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1928 const QRectF &rect)
1929{
1930 qreal left = rect.left();
1931 qreal right = rect.right();
1932 qreal top = rect.top();
1933 qreal bottom = rect.bottom();
1934
1935 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1936 int p1 = ((x1 < left) << Left)
1937 | ((x1 > right) << Right)
1938 | ((y1 < top) << Top)
1939 | ((y1 > bottom) << Bottom);
1940 int p2 = ((x2 < left) << Left)
1941 | ((x2 > right) << Right)
1942 | ((y2 < top) << Top)
1943 | ((y2 > bottom) << Bottom);
1944
1945 if (p1 & p2)
1946 // completely inside
1947 return false;
1948
1949 if (p1 | p2) {
1950 qreal dx = x2 - x1;
1951 qreal dy = y2 - y1;
1952
1953 // clip x coordinates
1954 if (x1 < left) {
1955 y1 += dy/dx * (left - x1);
1956 x1 = left;
1957 } else if (x1 > right) {
1958 y1 -= dy/dx * (x1 - right);
1959 x1 = right;
1960 }
1961 if (x2 < left) {
1962 y2 += dy/dx * (left - x2);
1963 x2 = left;
1964 } else if (x2 > right) {
1965 y2 -= dy/dx * (x2 - right);
1966 x2 = right;
1967 }
1968
1969 p1 = ((y1 < top) << Top)
1970 | ((y1 > bottom) << Bottom);
1971 p2 = ((y2 < top) << Top)
1972 | ((y2 > bottom) << Bottom);
1973
1974 if (p1 & p2)
1975 return false;
1976
1977 // clip y coordinates
1978 if (y1 < top) {
1979 x1 += dx/dy * (top - y1);
1980 y1 = top;
1981 } else if (y1 > bottom) {
1982 x1 -= dx/dy * (y1 - bottom);
1983 y1 = bottom;
1984 }
1985 if (y2 < top) {
1986 x2 += dx/dy * (top - y2);
1987 y2 = top;
1988 } else if (y2 > bottom) {
1989 x2 -= dx/dy * (y2 - bottom);
1990 y2 = bottom;
1991 }
1992
1993 p1 = ((x1 < left) << Left)
1994 | ((x1 > right) << Right);
1995 p2 = ((x2 < left) << Left)
1996 | ((x2 > right) << Right);
1997
1998 if (p1 & p2)
1999 return false;
2000
2001 return true;
2002 }
2003 return false;
2004}
2005
2006static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
2007{
2008 QRectF bounds = bezier.bounds();
2009
2010 if (y >= bounds.top() && y < bounds.bottom()
2011 && bounds.right() >= x1 && bounds.left() < x2) {
2012 const qreal lower_bound = qreal(.01);
2013 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
2014 return true;
2015
2016 QBezier first_half, second_half;
2017 bezier.split(&first_half, &second_half);
2018 if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1)
2019 || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1))
2020 return true;
2021 }
2022 return false;
2023}
2024
2025static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
2026{
2027 QRectF bounds = bezier.bounds();
2028
2029 if (x >= bounds.left() && x < bounds.right()
2030 && bounds.bottom() >= y1 && bounds.top() < y2) {
2031 const qreal lower_bound = qreal(.01);
2032 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
2033 return true;
2034
2035 QBezier first_half, second_half;
2036 bezier.split(&first_half, &second_half);
2037 if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1)
2038 || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1))
2039 return true;
2040 }
2041 return false;
2042}
2043
2044static bool pointOnEdge(const QRectF &rect, const QPointF &point)
2045{
2046 if ((point.x() == rect.left() || point.x() == rect.right()) &&
2047 (point.y() >= rect.top() && point.y() <= rect.bottom()))
2048 return true;
2049 if ((point.y() == rect.top() || point.y() == rect.bottom()) &&
2050 (point.x() >= rect.left() && point.x() <= rect.right()))
2051 return true;
2052 return false;
2053}
2054
2055/*
2056 Returns \c true if any lines or curves cross the four edges in of rect
2057*/
2058static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
2059{
2060 QPointF last_pt;
2061 QPointF last_start;
2062 enum { OnRect, InsideRect, OutsideRect} edgeStatus = OnRect;
2063 for (int i=0; i<path->elementCount(); ++i) {
2064 const QPainterPath::Element &e = path->elementAt(i);
2065
2066 switch (e.type) {
2067
2068 case QPainterPath::MoveToElement:
2069 if (i > 0
2070 && qFuzzyCompare(last_pt.x(), last_start.x())
2071 && qFuzzyCompare(last_pt.y(), last_start.y())
2072 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2073 last_start.x(), last_start.y(), rect))
2074 return true;
2075 last_start = last_pt = e;
2076 break;
2077
2078 case QPainterPath::LineToElement:
2079 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2080 return true;
2081 last_pt = e;
2082 break;
2083
2084 case QPainterPath::CurveToElement:
2085 {
2086 QPointF cp2 = path->elementAt(++i);
2087 QPointF ep = path->elementAt(++i);
2088 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2089 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2090 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2091 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2092 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2093 return true;
2094 last_pt = ep;
2095 }
2096 break;
2097
2098 default:
2099 break;
2100 }
2101 // Handle crossing the edges of the rect at the end-points of individual sub-paths.
2102 // A point on on the edge itself is considered neither inside nor outside for this purpose.
2103 if (!pointOnEdge(rect, last_pt)) {
2104 bool contained = rect.contains(last_pt);
2105 switch (edgeStatus) {
2106 case OutsideRect:
2107 if (contained)
2108 return true;
2109 break;
2110 case InsideRect:
2111 if (!contained)
2112 return true;
2113 break;
2114 case OnRect:
2115 edgeStatus = contained ? InsideRect : OutsideRect;
2116 break;
2117 }
2118 } else {
2119 if (last_pt == last_start)
2120 edgeStatus = OnRect;
2121 }
2122 }
2123
2124 // implicitly close last subpath
2125 if (last_pt != last_start
2126 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2127 last_start.x(), last_start.y(), rect))
2128 return true;
2129
2130 return false;
2131}
2132
2133/*!
2134 \fn bool QPainterPath::intersects(const QRectF &rectangle) const
2135
2136 Returns \c true if any point in the given \a rectangle intersects the
2137 path; otherwise returns \c false.
2138
2139 There is an intersection if any of the lines making up the
2140 rectangle crosses a part of the path or if any part of the
2141 rectangle overlaps with any area enclosed by the path. This
2142 function respects the current fillRule to determine what is
2143 considered inside the path.
2144
2145 \sa contains()
2146*/
2147bool QPainterPath::intersects(const QRectF &rect) const
2148{
2149 if (elementCount() == 1 && rect.contains(elementAt(0)))
2150 return true;
2151
2152 if (isEmpty())
2153 return false;
2154
2155 QRectF cp = controlPointRect();
2156 QRectF rn = rect.normalized();
2157
2158 // QRectF::intersects returns false if one of the rects is a null rect
2159 // which would happen for a painter path consisting of a vertical or
2160 // horizontal line
2161 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2162 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2163 return false;
2164
2165 // If any path element cross the rect its bound to be an intersection
2166 if (qt_painterpath_check_crossing(this, rect))
2167 return true;
2168
2169 if (contains(rect.center()))
2170 return true;
2171
2172 Q_D(QPainterPath);
2173
2174 // Check if the rectangle surounds any subpath...
2175 for (int i=0; i<d->elements.size(); ++i) {
2176 const Element &e = d->elements.at(i);
2177 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2178 return true;
2179 }
2180
2181 return false;
2182}
2183
2184/*!
2185 Translates all elements in the path by (\a{dx}, \a{dy}).
2186
2187 \since 4.6
2188 \sa translated()
2189*/
2190void QPainterPath::translate(qreal dx, qreal dy)
2191{
2192 if (!d_ptr || (dx == 0 && dy == 0))
2193 return;
2194
2195 int elementsLeft = d_ptr->elements.size();
2196 if (elementsLeft <= 0)
2197 return;
2198
2199 detach();
2200 QPainterPath::Element *element = d_func()->elements.data();
2201 Q_ASSERT(element);
2202 while (elementsLeft--) {
2203 element->x += dx;
2204 element->y += dy;
2205 ++element;
2206 }
2207}
2208
2209/*!
2210 \fn void QPainterPath::translate(const QPointF &offset)
2211 \overload
2212 \since 4.6
2213
2214 Translates all elements in the path by the given \a offset.
2215
2216 \sa translated()
2217*/
2218
2219/*!
2220 Returns a copy of the path that is translated by (\a{dx}, \a{dy}).
2221
2222 \since 4.6
2223 \sa translate()
2224*/
2225QPainterPath QPainterPath::translated(qreal dx, qreal dy) const
2226{
2227 QPainterPath copy(*this);
2228 copy.translate(dx, dy);
2229 return copy;
2230}
2231
2232/*!
2233 \fn QPainterPath QPainterPath::translated(const QPointF &offset) const;
2234 \overload
2235 \since 4.6
2236
2237 Returns a copy of the path that is translated by the given \a offset.
2238
2239 \sa translate()
2240*/
2241
2242/*!
2243 \fn bool QPainterPath::contains(const QRectF &rectangle) const
2244
2245 Returns \c true if the given \a rectangle is inside the path,
2246 otherwise returns \c false.
2247*/
2248bool QPainterPath::contains(const QRectF &rect) const
2249{
2250 Q_D(QPainterPath);
2251
2252 // the path is empty or the control point rect doesn't completely
2253 // cover the rectangle we abort stratight away.
2254 if (isEmpty() || !controlPointRect().contains(rect))
2255 return false;
2256
2257 // if there are intersections, chances are that the rect is not
2258 // contained, except if we have winding rule, in which case it
2259 // still might.
2260 if (qt_painterpath_check_crossing(this, rect)) {
2261 if (fillRule() == Qt::OddEvenFill) {
2262 return false;
2263 } else {
2264 // Do some wague sampling in the winding case. This is not
2265 // precise but it should mostly be good enough.
2266 if (!contains(rect.topLeft()) ||
2267 !contains(rect.topRight()) ||
2268 !contains(rect.bottomRight()) ||
2269 !contains(rect.bottomLeft()))
2270 return false;
2271 }
2272 }
2273
2274 // If there exists a point inside that is not part of the path its
2275 // because: rectangle lies completely outside path or a subpath
2276 // excludes parts of the rectangle. Both cases mean that the rect
2277 // is not contained
2278 if (!contains(rect.center()))
2279 return false;
2280
2281 // If there are any subpaths inside this rectangle we need to
2282 // check if they are still contained as a result of the fill
2283 // rule. This can only be the case for WindingFill though. For
2284 // OddEvenFill the rect will never be contained if it surrounds a
2285 // subpath. (the case where two subpaths are completely identical
2286 // can be argued but we choose to neglect it).
2287 for (int i=0; i<d->elements.size(); ++i) {
2288 const Element &e = d->elements.at(i);
2289 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2290 if (fillRule() == Qt::OddEvenFill)
2291 return false;
2292
2293 bool stop = false;
2294 for (; !stop && i<d->elements.size(); ++i) {
2295 const Element &el = d->elements.at(i);
2296 switch (el.type) {
2297 case MoveToElement:
2298 stop = true;
2299 break;
2300 case LineToElement:
2301 if (!contains(el))
2302 return false;
2303 break;
2304 case CurveToElement:
2305 if (!contains(d->elements.at(i+2)))
2306 return false;
2307 i += 2;
2308 break;
2309 default:
2310 break;
2311 }
2312 }
2313
2314 // compensate for the last ++i in the inner for
2315 --i;
2316 }
2317 }
2318
2319 return true;
2320}
2321
2322static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2323{
2324 return qAbs(a.x() - b.x()) <= epsilon.width()
2325 && qAbs(a.y() - b.y()) <= epsilon.height();
2326}
2327
2328/*!
2329 Returns \c true if this painterpath is equal to the given \a path.
2330
2331 Note that comparing paths may involve a per element comparison
2332 which can be slow for complex paths.
2333
2334 \sa operator!=()
2335*/
2336
2337bool QPainterPath::operator==(const QPainterPath &path) const
2338{
2339 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2340 QPainterPathData *other_d = path.d_func();
2341 if (other_d == d) {
2342 return true;
2343 } else if (!d || !other_d) {
2344 if (!other_d && isEmpty() && elementAt(0) == QPointF() && d->fillRule == Qt::OddEvenFill)
2345 return true;
2346 if (!d && path.isEmpty() && path.elementAt(0) == QPointF() && other_d->fillRule == Qt::OddEvenFill)
2347 return true;
2348 return false;
2349 }
2350 else if (d->fillRule != other_d->fillRule)
2351 return false;
2352 else if (d->elements.size() != other_d->elements.size())
2353 return false;
2354
2355 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2356
2357 QSizeF epsilon = boundingRect().size();
2358 epsilon.rwidth() *= qt_epsilon;
2359 epsilon.rheight() *= qt_epsilon;
2360
2361 for (int i = 0; i < d->elements.size(); ++i)
2362 if (d->elements.at(i).type != other_d->elements.at(i).type
2363 || !epsilonCompare(d->elements.at(i), other_d->elements.at(i), epsilon))
2364 return false;
2365
2366 return true;
2367}
2368
2369/*!
2370 Returns \c true if this painter path differs from the given \a path.
2371
2372 Note that comparing paths may involve a per element comparison
2373 which can be slow for complex paths.
2374
2375 \sa operator==()
2376*/
2377
2378bool QPainterPath::operator!=(const QPainterPath &path) const
2379{
2380 return !(*this==path);
2381}
2382
2383/*!
2384 \since 4.5
2385
2386 Returns the intersection of this path and the \a other path.
2387
2388 \sa intersected(), operator&=(), united(), operator|()
2389*/
2390QPainterPath QPainterPath::operator&(const QPainterPath &other) const
2391{
2392 return intersected(other);
2393}
2394
2395/*!
2396 \since 4.5
2397
2398 Returns the union of this path and the \a other path.
2399
2400 \sa united(), operator|=(), intersected(), operator&()
2401*/
2402QPainterPath QPainterPath::operator|(const QPainterPath &other) const
2403{
2404 return united(other);
2405}
2406
2407/*!
2408 \since 4.5
2409
2410 Returns the union of this path and the \a other path. This function is equivalent
2411 to operator|().
2412
2413 \sa united(), operator+=(), operator-()
2414*/
2415QPainterPath QPainterPath::operator+(const QPainterPath &other) const
2416{
2417 return united(other);
2418}
2419
2420/*!
2421 \since 4.5
2422
2423 Subtracts the \a other path from a copy of this path, and returns the copy.
2424
2425 \sa subtracted(), operator-=(), operator+()
2426*/
2427QPainterPath QPainterPath::operator-(const QPainterPath &other) const
2428{
2429 return subtracted(other);
2430}
2431
2432/*!
2433 \since 4.5
2434
2435 Intersects this path with \a other and returns a reference to this path.
2436
2437 \sa intersected(), operator&(), operator|=()
2438*/
2439QPainterPath &QPainterPath::operator&=(const QPainterPath &other)
2440{
2441 return *this = (*this & other);
2442}
2443
2444/*!
2445 \since 4.5
2446
2447 Unites this path with \a other and returns a reference to this path.
2448
2449 \sa united(), operator|(), operator&=()
2450*/
2451QPainterPath &QPainterPath::operator|=(const QPainterPath &other)
2452{
2453 return *this = (*this | other);
2454}
2455
2456/*!
2457 \since 4.5
2458
2459 Unites this path with \a other, and returns a reference to this path. This
2460 is equivalent to operator|=().
2461
2462 \sa united(), operator+(), operator-=()
2463*/
2464QPainterPath &QPainterPath::operator+=(const QPainterPath &other)
2465{
2466 return *this = (*this + other);
2467}
2468
2469/*!
2470 \since 4.5
2471
2472 Subtracts \a other from this path, and returns a reference to this
2473 path.
2474
2475 \sa subtracted(), operator-(), operator+=()
2476*/
2477QPainterPath &QPainterPath::operator-=(const QPainterPath &other)
2478{
2479 return *this = (*this - other);
2480}
2481
2482#ifndef QT_NO_DATASTREAM
2483/*!
2484 \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path)
2485 \relates QPainterPath
2486
2487 Writes the given painter \a path to the given \a stream, and
2488 returns a reference to the \a stream.
2489
2490 \sa {Serializing Qt Data Types}
2491*/
2492QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
2493{
2494 if (p.isEmpty()) {
2495 s << 0;
2496 return s;
2497 }
2498
2499 s << p.elementCount();
2500 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2501 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2502 s << int(e.type);
2503 s << double(e.x) << double(e.y);
2504 }
2505 s << p.d_func()->cStart;
2506 s << int(p.d_func()->fillRule);
2507 return s;
2508}
2509
2510/*!
2511 \fn QDataStream &operator>>(QDataStream &stream, QPainterPath &path)
2512 \relates QPainterPath
2513
2514 Reads a painter path from the given \a stream into the specified \a path,
2515 and returns a reference to the \a stream.
2516
2517 \sa {Serializing Qt Data Types}
2518*/
2519QDataStream &operator>>(QDataStream &s, QPainterPath &p)
2520{
2521 bool errorDetected = false;
2522 int size;
2523 s >> size;
2524
2525 if (size == 0)
2526 return s;
2527
2528 p.ensureData(); // in case if p.d_func() == 0
2529 if (p.d_func()->elements.size() == 1) {
2530 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2531 p.d_func()->elements.clear();
2532 }
2533 for (int i=0; i<size; ++i) {
2534 int type;
2535 double x, y;
2536 s >> type;
2537 s >> x;
2538 s >> y;
2539 Q_ASSERT(type >= 0 && type <= 3);
2540 if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) {
2541#ifndef QT_NO_DEBUG
2542 qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it");
2543#endif
2544 errorDetected = true;
2545 continue;
2546 }
2547 QPainterPath::Element elm = { qreal(x), qreal(y), QPainterPath::ElementType(type) };
2548 p.d_func()->elements.append(elm);
2549 }
2550 s >> p.d_func()->cStart;
2551 int fillRule;
2552 s >> fillRule;
2553 Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
2554 p.d_func()->fillRule = Qt::FillRule(fillRule);
2555 p.d_func()->dirtyBounds = true;
2556 p.d_func()->dirtyControlBounds = true;
2557 if (errorDetected)
2558 p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
2559 return s;
2560}
2561#endif // QT_NO_DATASTREAM
2562
2563
2564/*******************************************************************************
2565 * class QPainterPathStroker
2566 */
2567
2568void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
2569{
2570 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2571}
2572
2573void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
2574{
2575 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2576}
2577
2578void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
2579 qfixed c2x, qfixed c2y,
2580 qfixed ex, qfixed ey,
2581 void *data)
2582{
2583 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2584 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
2585 qt_fixed_to_real(ex), qt_fixed_to_real(ey));
2586}
2587
2588/*!
2589 \since 4.1
2590 \class QPainterPathStroker
2591 \ingroup painting
2592 \inmodule QtGui
2593
2594 \brief The QPainterPathStroker class is used to generate fillable
2595 outlines for a given painter path.
2596
2597 By calling the createStroke() function, passing a given
2598 QPainterPath as argument, a new painter path representing the
2599 outline of the given path is created. The newly created painter
2600 path can then be filled to draw the original painter path's
2601 outline.
2602
2603 You can control the various design aspects (width, cap styles,
2604 join styles and dash pattern) of the outlining using the following
2605 functions:
2606
2607 \list
2608 \li setWidth()
2609 \li setCapStyle()
2610 \li setJoinStyle()
2611 \li setDashPattern()
2612 \endlist
2613
2614 The setDashPattern() function accepts both a Qt::PenStyle object
2615 and a vector representation of the pattern as argument.
2616
2617 In addition you can specify a curve's threshold, controlling the
2618 granularity with which a curve is drawn, using the
2619 setCurveThreshold() function. The default threshold is a well
2620 adjusted value (0.25), and normally you should not need to modify
2621 it. However, you can make the curve's appearance smoother by
2622 decreasing its value.
2623
2624 You can also control the miter limit for the generated outline
2625 using the setMiterLimit() function. The miter limit describes how
2626 far from each join the miter join can extend. The limit is
2627 specified in the units of width so the pixelwise miter limit will
2628 be \c {miterlimit * width}. This value is only used if the join
2629 style is Qt::MiterJoin.
2630
2631 The painter path generated by the createStroke() function should
2632 only be used for outlining the given painter path. Otherwise it
2633 may cause unexpected behavior. Generated outlines also require the
2634 Qt::WindingFill rule which is set by default.
2635
2636 \sa QPen, QBrush
2637*/
2638
2639QPainterPathStrokerPrivate::QPainterPathStrokerPrivate()
2640 : dashOffset(0)
2641{
2642 stroker.setMoveToHook(qt_path_stroke_move_to);
2643 stroker.setLineToHook(qt_path_stroke_line_to);
2644 stroker.setCubicToHook(qt_path_stroke_cubic_to);
2645}
2646
2647/*!
2648 Creates a new stroker.
2649 */
2650QPainterPathStroker::QPainterPathStroker()
2651 : d_ptr(new QPainterPathStrokerPrivate)
2652{
2653}
2654
2655/*!
2656 Creates a new stroker based on \a pen.
2657
2658 \since 5.3
2659 */
2660QPainterPathStroker::QPainterPathStroker(const QPen &pen)
2661 : d_ptr(new QPainterPathStrokerPrivate)
2662{
2663 setWidth(pen.widthF());
2664 setCapStyle(pen.capStyle());
2665 setJoinStyle(pen.joinStyle());
2666 setMiterLimit(pen.miterLimit());
2667 setDashOffset(pen.dashOffset());
2668
2669 if (pen.style() == Qt::CustomDashLine)
2670 setDashPattern(pen.dashPattern());
2671 else
2672 setDashPattern(pen.style());
2673}
2674
2675/*!
2676 Destroys the stroker.
2677*/
2678QPainterPathStroker::~QPainterPathStroker()
2679{
2680}
2681
2682
2683/*!
2684 Generates a new path that is a fillable area representing the
2685 outline of the given \a path.
2686
2687 The various design aspects of the outline are based on the
2688 stroker's properties: width(), capStyle(), joinStyle(),
2689 dashPattern(), curveThreshold() and miterLimit().
2690
2691 The generated path should only be used for outlining the given
2692 painter path. Otherwise it may cause unexpected
2693 behavior. Generated outlines also require the Qt::WindingFill rule
2694 which is set by default.
2695*/
2696QPainterPath QPainterPathStroker::createStroke(const QPainterPath &path) const
2697{
2698 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2699 QPainterPath stroke;
2700 if (path.isEmpty())
2701 return path;
2702 if (d->dashPattern.isEmpty()) {
2703 d->stroker.strokePath(path, &stroke, QTransform());
2704 } else {
2705 QDashStroker dashStroker(&d->stroker);
2706 dashStroker.setDashPattern(d->dashPattern);
2707 dashStroker.setDashOffset(d->dashOffset);
2708 dashStroker.setClipRect(d->stroker.clipRect());
2709 dashStroker.strokePath(path, &stroke, QTransform());
2710 }
2711 stroke.setFillRule(Qt::WindingFill);
2712 return stroke;
2713}
2714
2715/*!
2716 Sets the width of the generated outline painter path to \a width.
2717
2718 The generated outlines will extend approximately 50% of \a width
2719 to each side of the given input path's original outline.
2720*/
2721void QPainterPathStroker::setWidth(qreal width)
2722{
2723 Q_D(QPainterPathStroker);
2724 if (width <= 0)
2725 width = 1;
2726 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2727}
2728
2729/*!
2730 Returns the width of the generated outlines.
2731*/
2732qreal QPainterPathStroker::width() const
2733{
2734 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2735}
2736
2737
2738/*!
2739 Sets the cap style of the generated outlines to \a style. If a
2740 dash pattern is set, each segment of the pattern is subject to the
2741 cap \a style.
2742*/
2743void QPainterPathStroker::setCapStyle(Qt::PenCapStyle style)
2744{
2745 d_func()->stroker.setCapStyle(style);
2746}
2747
2748
2749/*!
2750 Returns the cap style of the generated outlines.
2751*/
2752Qt::PenCapStyle QPainterPathStroker::capStyle() const
2753{
2754 return d_func()->stroker.capStyle();
2755}
2756
2757/*!
2758 Sets the join style of the generated outlines to \a style.
2759*/
2760void QPainterPathStroker::setJoinStyle(Qt::PenJoinStyle style)
2761{
2762 d_func()->stroker.setJoinStyle(style);
2763}
2764
2765/*!
2766 Returns the join style of the generated outlines.
2767*/
2768Qt::PenJoinStyle QPainterPathStroker::joinStyle() const
2769{
2770 return d_func()->stroker.joinStyle();
2771}
2772
2773/*!
2774 Sets the miter limit of the generated outlines to \a limit.
2775
2776 The miter limit describes how far from each join the miter join
2777 can extend. The limit is specified in units of the currently set
2778 width. So the pixelwise miter limit will be \c { miterlimit *
2779 width}.
2780
2781 This value is only used if the join style is Qt::MiterJoin.
2782*/
2783void QPainterPathStroker::setMiterLimit(qreal limit)
2784{
2785 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2786}
2787
2788/*!
2789 Returns the miter limit for the generated outlines.
2790*/
2791qreal QPainterPathStroker::miterLimit() const
2792{
2793 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2794}
2795
2796
2797/*!
2798 Specifies the curve flattening \a threshold, controlling the
2799 granularity with which the generated outlines' curve is drawn.
2800
2801 The default threshold is a well adjusted value (0.25), and
2802 normally you should not need to modify it. However, you can make
2803 the curve's appearance smoother by decreasing its value.
2804*/
2805void QPainterPathStroker::setCurveThreshold(qreal threshold)
2806{
2807 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2808}
2809
2810/*!
2811 Returns the curve flattening threshold for the generated
2812 outlines.
2813*/
2814qreal QPainterPathStroker::curveThreshold() const
2815{
2816 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2817}
2818
2819/*!
2820 Sets the dash pattern for the generated outlines to \a style.
2821*/
2822void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
2823{
2824 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2825}
2826
2827/*!
2828 \overload
2829
2830 Sets the dash pattern for the generated outlines to \a
2831 dashPattern. This function makes it possible to specify custom
2832 dash patterns.
2833
2834 Each element in the vector contains the lengths of the dashes and spaces
2835 in the stroke, beginning with the first dash in the first element, the
2836 first space in the second element, and alternating between dashes and
2837 spaces for each following pair of elements.
2838
2839 The vector can contain an odd number of elements, in which case the last
2840 element will be extended by the length of the first element when the
2841 pattern repeats.
2842*/
2843void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
2844{
2845 d_func()->dashPattern.clear();
2846 for (int i=0; i<dashPattern.size(); ++i)
2847 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2848}
2849
2850/*!
2851 Returns the dash pattern for the generated outlines.
2852*/
2853QVector<qreal> QPainterPathStroker::dashPattern() const
2854{
2855 return d_func()->dashPattern;
2856}
2857
2858/*!
2859 Returns the dash offset for the generated outlines.
2860 */
2861qreal QPainterPathStroker::dashOffset() const
2862{
2863 return d_func()->dashOffset;
2864}
2865
2866/*!
2867 Sets the dash offset for the generated outlines to \a offset.
2868
2869 See the documentation for QPen::setDashOffset() for a description of the
2870 dash offset.
2871 */
2872void QPainterPathStroker::setDashOffset(qreal offset)
2873{
2874 d_func()->dashOffset = offset;
2875}
2876
2877/*!
2878 Converts the path into a polygon using the QTransform
2879 \a matrix, and returns the polygon.
2880
2881 The polygon is created by first converting all subpaths to
2882 polygons, then using a rewinding technique to make sure that
2883 overlapping subpaths can be filled using the correct fill rule.
2884
2885 Note that rewinding inserts addition lines in the polygon so
2886 the outline of the fill polygon does not match the outline of
2887 the path.
2888
2889 \sa toSubpathPolygons(), toFillPolygons(),
2890 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
2891*/
2892QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
2893{
2894
2895 const QList<QPolygonF> flats = toSubpathPolygons(matrix);
2896 QPolygonF polygon;
2897 if (flats.isEmpty())
2898 return polygon;
2899 QPointF first = flats.first().first();
2900 for (int i=0; i<flats.size(); ++i) {
2901 polygon += flats.at(i);
2902 if (!flats.at(i).isClosed())
2903 polygon += flats.at(i).first();
2904 if (i > 0)
2905 polygon += first;
2906 }
2907 return polygon;
2908}
2909
2910/*!
2911 \overload
2912*/
2913QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
2914{
2915 return toFillPolygon(QTransform(matrix));
2916}
2917
2918
2919//derivative of the equation
2920static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2921{
2922 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2923}
2924
2925/*!
2926 Returns the length of the current path.
2927*/
2928qreal QPainterPath::length() const
2929{
2930 Q_D(QPainterPath);
2931 if (isEmpty())
2932 return 0;
2933
2934 qreal len = 0;
2935 for (int i=1; i<d->elements.size(); ++i) {
2936 const Element &e = d->elements.at(i);
2937
2938 switch (e.type) {
2939 case MoveToElement:
2940 break;
2941 case LineToElement:
2942 {
2943 len += QLineF(d->elements.at(i-1), e).length();
2944 break;
2945 }
2946 case CurveToElement:
2947 {
2948 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2949 e,
2950 d->elements.at(i+1),
2951 d->elements.at(i+2));
2952 len += b.length();
2953 i += 2;
2954 break;
2955 }
2956 default:
2957 break;
2958 }
2959 }
2960 return len;
2961}
2962
2963/*!
2964 Returns percentage of the whole path at the specified length \a len.
2965
2966 Note that similarly to other percent methods, the percentage measurement
2967 is not linear with regards to the length, if curves are present
2968 in the path. When curves are present the percentage argument is mapped
2969 to the t parameter of the Bezier equations.
2970*/
2971qreal QPainterPath::percentAtLength(qreal len) const
2972{
2973 Q_D(QPainterPath);
2974 if (isEmpty() || len <= 0)
2975 return 0;
2976
2977 qreal totalLength = length();
2978 if (len > totalLength)
2979 return 1;
2980
2981 qreal curLen = 0;
2982 for (int i=1; i<d->elements.size(); ++i) {
2983 const Element &e = d->elements.at(i);
2984
2985 switch (e.type) {
2986 case MoveToElement:
2987 break;
2988 case LineToElement:
2989 {
2990 QLineF line(d->elements.at(i-1), e);
2991 qreal llen = line.length();
2992 curLen += llen;
2993 if (curLen >= len) {
2994 return len/totalLength ;
2995 }
2996
2997 break;
2998 }
2999 case CurveToElement:
3000 {
3001 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3002 e,
3003 d->elements.at(i+1),
3004 d->elements.at(i+2));
3005 qreal blen = b.length();
3006 qreal prevLen = curLen;
3007 curLen += blen;
3008
3009 if (curLen >= len) {
3010 qreal res = b.tAtLength(len - prevLen);
3011 return (res * blen + prevLen)/totalLength;
3012 }
3013
3014 i += 2;
3015 break;
3016 }
3017 default:
3018 break;
3019 }
3020 }
3021
3022 return 0;
3023}
3024
3025static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
3026{
3027 *startingLength = 0;
3028 if (t > 1)
3029 return QBezier();
3030
3031 qreal curLen = 0;
3032 qreal totalLength = path.length();
3033
3034 const int lastElement = path.elementCount() - 1;
3035 for (int i=0; i <= lastElement; ++i) {
3036 const QPainterPath::Element &e = path.elementAt(i);
3037
3038 switch (e.type) {
3039 case QPainterPath::MoveToElement:
3040 break;
3041 case QPainterPath::LineToElement:
3042 {
3043 QLineF line(path.elementAt(i-1), e);
3044 qreal llen = line.length();
3045 curLen += llen;
3046 if (i == lastElement || curLen/totalLength >= t) {
3047 *bezierLength = llen;
3048 QPointF a = path.elementAt(i-1);
3049 QPointF delta = e - a;
3050 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
3051 }
3052 break;
3053 }
3054 case QPainterPath::CurveToElement:
3055 {
3056 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
3057 e,
3058 path.elementAt(i+1),
3059 path.elementAt(i+2));
3060 qreal blen = b.length();
3061 curLen += blen;
3062
3063 if (i + 2 == lastElement || curLen/totalLength >= t) {
3064 *bezierLength = blen;
3065 return b;
3066 }
3067
3068 i += 2;
3069 break;
3070 }
3071 default:
3072 break;
3073 }
3074 *startingLength = curLen;
3075 }
3076 return QBezier();
3077}
3078
3079/*!
3080 Returns the point at at the percentage \a t of the current path.
3081 The argument \a t has to be between 0 and 1.
3082
3083 Note that similarly to other percent methods, the percentage measurement
3084 is not linear with regards to the length, if curves are present
3085 in the path. When curves are present the percentage argument is mapped
3086 to the t parameter of the Bezier equations.
3087*/
3088QPointF QPainterPath::pointAtPercent(qreal t) const
3089{
3090 if (t < 0 || t > 1) {
3091 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
3092 return QPointF();
3093 }
3094
3095 if (!d_ptr || d_ptr->elements.size() == 0)
3096 return QPointF();
3097
3098 if (d_ptr->elements.size() == 1)
3099 return d_ptr->elements.at(0);
3100
3101 qreal totalLength = length();
3102 qreal curLen = 0;
3103 qreal bezierLen = 0;
3104 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
3105 qreal realT = (totalLength * t - curLen) / bezierLen;
3106
3107 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
3108}
3109
3110/*!
3111 Returns the angle of the path tangent at the percentage \a t.
3112 The argument \a t has to be between 0 and 1.
3113
3114 Positive values for the angles mean counter-clockwise while negative values
3115 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
3116
3117 Note that similarly to the other percent methods, the percentage measurement
3118 is not linear with regards to the length if curves are present
3119 in the path. When curves are present the percentage argument is mapped
3120 to the t parameter of the Bezier equations.
3121*/
3122qreal QPainterPath::angleAtPercent(qreal t) const
3123{
3124 if (t < 0 || t > 1) {
3125 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
3126 return 0;
3127 }
3128
3129 qreal totalLength = length();
3130 qreal curLen = 0;
3131 qreal bezierLen = 0;
3132 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3133 qreal realT = (totalLength * t - curLen) / bezierLen;
3134
3135 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3136 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3137
3138 return QLineF(0, 0, m1, m2).angle();
3139}
3140
3141
3142/*!
3143 Returns the slope of the path at the percentage \a t. The
3144 argument \a t has to be between 0 and 1.
3145
3146 Note that similarly to other percent methods, the percentage measurement
3147 is not linear with regards to the length, if curves are present
3148 in the path. When curves are present the percentage argument is mapped
3149 to the t parameter of the Bezier equations.
3150*/
3151qreal QPainterPath::slopeAtPercent(qreal t) const
3152{
3153 if (t < 0 || t > 1) {
3154 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3155 return 0;
3156 }
3157
3158 qreal totalLength = length();
3159 qreal curLen = 0;
3160 qreal bezierLen = 0;
3161 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3162 qreal realT = (totalLength * t - curLen) / bezierLen;
3163
3164 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3165 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3166 //tangent line
3167 qreal slope = 0;
3168
3169 if (m1)
3170 slope = m2/m1;
3171 else {
3172 if (std::numeric_limits<qreal>::has_infinity) {
3173 slope = (m2 < 0) ? -std::numeric_limits<qreal>::infinity()
3174 : std::numeric_limits<qreal>::infinity();
3175 } else {
3176 if (sizeof(qreal) == sizeof(double)) {
3177 return 1.79769313486231570e+308;
3178 } else {
3179 return ((qreal)3.40282346638528860e+38);
3180 }
3181 }
3182 }
3183
3184 return slope;
3185}
3186
3187/*!
3188 \since 4.4
3189
3190 Adds the given rectangle \a rect with rounded corners to the path.
3191
3192 The \a xRadius and \a yRadius arguments specify the radii of
3193 the ellipses defining the corners of the rounded rectangle.
3194 When \a mode is Qt::RelativeSize, \a xRadius and
3195 \a yRadius are specified in percentage of half the rectangle's
3196 width and height respectively, and should be in the range 0.0 to 100.0.
3197
3198 \sa addRect()
3199*/
3200void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
3201 Qt::SizeMode mode)
3202{
3203 QRectF r = rect.normalized();
3204
3205 if (r.isNull())
3206 return;
3207
3208 if (mode == Qt::AbsoluteSize) {
3209 qreal w = r.width() / 2;
3210 qreal h = r.height() / 2;
3211
3212 if (w == 0) {
3213 xRadius = 0;
3214 } else {
3215 xRadius = 100 * qMin(xRadius, w) / w;
3216 }
3217 if (h == 0) {
3218 yRadius = 0;
3219 } else {
3220 yRadius = 100 * qMin(yRadius, h) / h;
3221 }
3222 } else {
3223 if (xRadius > 100) // fix ranges
3224 xRadius = 100;
3225
3226 if (yRadius > 100)
3227 yRadius = 100;
3228 }
3229
3230 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3231 addRect(r);
3232 return;
3233 }
3234
3235 qreal x = r.x();
3236 qreal y = r.y();
3237 qreal w = r.width();
3238 qreal h = r.height();
3239 qreal rxx2 = w*xRadius/100;
3240 qreal ryy2 = h*yRadius/100;
3241
3242 ensureData();
3243 detach();
3244
3245 bool first = d_func()->elements.size() < 2;
3246
3247 arcMoveTo(x, y, rxx2, ryy2, 180);
3248 arcTo(x, y, rxx2, ryy2, 180, -90);
3249 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3250 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3251 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3252 closeSubpath();
3253
3254 d_func()->require_moveTo = true;
3255 d_func()->convex = first;
3256}
3257
3258/*!
3259 \fn void QPainterPath::addRoundedRect(qreal x, qreal y, qreal w, qreal h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
3260 \since 4.4
3261 \overload
3262
3263 Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
3264 */
3265
3266#if QT_DEPRECATED_SINCE(5, 13)
3267/*!
3268 \obsolete
3269
3270 Adds a rectangle \a r with rounded corners to the path.
3271
3272 The \a xRnd and \a yRnd arguments specify how rounded the corners
3273 should be. 0 is angled corners, 99 is maximum roundedness.
3274
3275 \sa addRoundedRect()
3276*/
3277void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3278{
3279 if(xRnd >= 100) // fix ranges
3280 xRnd = 99;
3281 if(yRnd >= 100)
3282 yRnd = 99;
3283 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3284 addRect(r);
3285 return;
3286 }
3287
3288 QRectF rect = r.normalized();
3289
3290 if (rect.isNull())
3291 return;
3292
3293 qreal x = rect.x();
3294 qreal y = rect.y();
3295 qreal w = rect.width();
3296 qreal h = rect.height();
3297 qreal rxx2 = w*xRnd/100;
3298 qreal ryy2 = h*yRnd/100;
3299
3300 ensureData();
3301 detach();
3302
3303 bool first = d_func()->elements.size() < 2;
3304
3305 arcMoveTo(x, y, rxx2, ryy2, 180);
3306 arcTo(x, y, rxx2, ryy2, 180, -90);
3307 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3308 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3309 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3310 closeSubpath();
3311
3312 d_func()->require_moveTo = true;
3313 d_func()->convex = first;
3314}
3315
3316/*!
3317 \obsolete
3318
3319 \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
3320 \since 4.3
3321 \overload
3322
3323 Adds a rounded rectangle, \a rect, to the path.
3324
3325 The \a roundness argument specifies uniform roundness for the
3326 rectangle. Vertical and horizontal roundness factors will be
3327 adjusted accordingly to act uniformly around both axes. Use this
3328 method if you want a rectangle equally rounded across both the X and
3329 Y axis.
3330
3331 \sa addRoundedRect()
3332*/
3333void QPainterPath::addRoundRect(const QRectF &rect,
3334 int roundness)
3335{
3336 int xRnd = roundness;
3337 int yRnd = roundness;
3338 if (rect.width() > rect.height())
3339 xRnd = int(roundness * rect.height()/rect.width());
3340 else
3341 yRnd = int(roundness * rect.width()/rect.height());
3342 addRoundedRect(rect, xRnd, yRnd, Qt::RelativeSize);
3343}
3344
3345/*!
3346 \obsolete
3347
3348 \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
3349 \overload
3350
3351 Adds a rectangle with rounded corners to the path. The rectangle
3352 is constructed from \a x, \a y, and the width and height \a w
3353 and \a h.
3354
3355 The \a xRnd and \a yRnd arguments specify how rounded the corners
3356 should be. 0 is angled corners, 99 is maximum roundedness.
3357
3358 \sa addRoundedRect()
3359 */
3360void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h,
3361 int xRnd, int yRnd)
3362{
3363 addRoundedRect(QRectF(x, y, w, h), xRnd, yRnd, Qt::RelativeSize);
3364}
3365
3366/*!
3367 \obsolete
3368
3369 \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
3370 \since 4.3
3371 \overload
3372
3373 Adds a rounded rectangle to the path, defined by the coordinates \a
3374 x and \a y with the specified \a width and \a height.
3375
3376 The \a roundness argument specifies uniform roundness for the
3377 rectangle. Vertical and horizontal roundness factors will be
3378 adjusted accordingly to act uniformly around both axes. Use this
3379 method if you want a rectangle equally rounded across both the X and
3380 Y axis.
3381
3382 \sa addRoundedRect()
3383*/
3384void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h,
3385 int roundness)
3386{
3387 addRoundedRect(QRectF(x, y, w, h), roundness, Qt::RelativeSize);
3388}
3389#endif
3390
3391/*!
3392 \since 4.3
3393
3394 Returns a path which is the union of this path's fill area and \a p's fill area.
3395
3396 Set operations on paths will treat the paths as areas. Non-closed
3397 paths will be treated as implicitly closed.
3398 Bezier curves may be flattened to line segments due to numerical instability of
3399 doing bezier curve intersections.
3400
3401 \sa intersected(), subtracted()
3402*/
3403QPainterPath QPainterPath::united(const QPainterPath &p) const
3404{
3405 if (isEmpty() || p.isEmpty())
3406 return isEmpty() ? p : *this;
3407 QPathClipper clipper(*this, p);
3408 return clipper.clip(QPathClipper::BoolOr);
3409}
3410
3411/*!
3412 \since 4.3
3413
3414 Returns a path which is the intersection of this path's fill area and \a p's fill area.
3415 Bezier curves may be flattened to line segments due to numerical instability of
3416 doing bezier curve intersections.
3417*/
3418QPainterPath QPainterPath::intersected(const QPainterPath &p) const
3419{
3420 if (isEmpty() || p.isEmpty())
3421 return QPainterPath();
3422 QPathClipper clipper(*this, p);
3423 return clipper.clip(QPathClipper::BoolAnd);
3424}
3425
3426/*!
3427 \since 4.3
3428
3429 Returns a path which is \a p's fill area subtracted from this path's fill area.
3430
3431 Set operations on paths will treat the paths as areas. Non-closed
3432 paths will be treated as implicitly closed.
3433 Bezier curves may be flattened to line segments due to numerical instability of
3434 doing bezier curve intersections.
3435*/
3436QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
3437{
3438 if (isEmpty() || p.isEmpty())
3439 return *this;
3440 QPathClipper clipper(*this, p);
3441 return clipper.clip(QPathClipper::BoolSub);
3442}
3443
3444#if QT_DEPRECATED_SINCE(5, 13)
3445/*!
3446 \since 4.3
3447 \obsolete
3448
3449 Use subtracted() instead.
3450
3451 \sa subtracted()
3452*/
3453QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
3454{
3455 return p.subtracted(*this);
3456}
3457#endif
3458
3459/*!
3460 \since 4.4
3461
3462 Returns a simplified version of this path. This implies merging all subpaths that intersect,
3463 and returning a path containing no intersecting edges. Consecutive parallel lines will also
3464 be merged. The simplified path will always use the default fill rule, Qt::OddEvenFill.
3465 Bezier curves may be flattened to line segments due to numerical instability of
3466 doing bezier curve intersections.
3467*/
3468QPainterPath QPainterPath::simplified() const
3469{
3470 if(isEmpty())
3471 return *this;
3472 QPathClipper clipper(*this, QPainterPath());
3473 return clipper.clip(QPathClipper::Simplify);
3474}
3475
3476/*!
3477 \since 4.3
3478
3479 Returns \c true if the current path intersects at any point the given path \a p.
3480 Also returns \c true if the current path contains or is contained by any part of \a p.
3481
3482 Set operations on paths will treat the paths as areas. Non-closed
3483 paths will be treated as implicitly closed.
3484
3485 \sa contains()
3486 */
3487bool QPainterPath::intersects(const QPainterPath &p) const
3488{
3489 if (p.elementCount() == 1)
3490 return contains(p.elementAt(0));
3491 if (isEmpty() || p.isEmpty())
3492 return false;
3493 QPathClipper clipper(*this, p);
3494 return clipper.intersect();
3495}
3496
3497/*!
3498 \since 4.3
3499
3500 Returns \c true if the given path \a p is contained within
3501 the current path. Returns \c false if any edges of the current path and
3502 \a p intersect.
3503
3504 Set operations on paths will treat the paths as areas. Non-closed
3505 paths will be treated as implicitly closed.
3506
3507 \sa intersects()
3508 */
3509bool QPainterPath::contains(const QPainterPath &p) const
3510{
3511 if (p.elementCount() == 1)
3512 return contains(p.elementAt(0));
3513 if (isEmpty() || p.isEmpty())
3514 return false;
3515 QPathClipper clipper(*this, p);
3516 return clipper.contains();
3517}
3518
3519void QPainterPath::setDirty(bool dirty)
3520{
3521 d_func()->dirtyBounds = dirty;
3522 d_func()->dirtyControlBounds = dirty;
3523 d_func()->pathConverter.reset();
3524 d_func()->convex = false;
3525}
3526
3527void QPainterPath::computeBoundingRect() const
3528{
3529 QPainterPathData *d = d_func();
3530 d->dirtyBounds = false;
3531 if (!d_ptr) {
3532 d->bounds = QRect();
3533 return;
3534 }
3535
3536 qreal minx, maxx, miny, maxy;
3537 minx = maxx = d->elements.at(0).x;
3538 miny = maxy = d->elements.at(0).y;
3539 for (int i=1; i<d->elements.size(); ++i) {
3540 const Element &e = d->elements.at(i);
3541
3542 switch (e.type) {
3543 case MoveToElement:
3544 case LineToElement:
3545 if (e.x > maxx) maxx = e.x;
3546 else if (e.x < minx) minx = e.x;
3547 if (e.y > maxy) maxy = e.y;
3548 else if (e.y < miny) miny = e.y;
3549 break;
3550 case CurveToElement:
3551 {
3552 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3553 e,
3554 d->elements.at(i+1),
3555 d->elements.at(i+2));
3556 QRectF r = qt_painterpath_bezier_extrema(b);
3557 qreal right = r.right();
3558 qreal bottom = r.bottom();
3559 if (r.x() < minx) minx = r.x();
3560 if (right > maxx) maxx = right;
3561 if (r.y() < miny) miny = r.y();
3562 if (bottom > maxy) maxy = bottom;
3563 i += 2;
3564 }
3565 break;
3566 default:
3567 break;
3568 }
3569 }
3570 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3571}
3572
3573
3574void QPainterPath::computeControlPointRect() const
3575{
3576 QPainterPathData *d = d_func();
3577 d->dirtyControlBounds = false;
3578 if (!d_ptr) {
3579 d->controlBounds = QRect();
3580 return;
3581 }
3582
3583 qreal minx, maxx, miny, maxy;
3584 minx = maxx = d->elements.at(0).x;
3585 miny = maxy = d->elements.at(0).y;
3586 for (int i=1; i<d->elements.size(); ++i) {
3587 const Element &e = d->elements.at(i);
3588 if (e.x > maxx) maxx = e.x;
3589 else if (e.x < minx) minx = e.x;
3590 if (e.y > maxy) maxy = e.y;
3591 else if (e.y < miny) miny = e.y;
3592 }
3593 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3594}
3595
3596#ifndef QT_NO_DEBUG_STREAM
3597QDebug operator<<(QDebug s, const QPainterPath &p)
3598{
3599 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << Qt::endl;
3600 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3601 for (int i=0; i<p.elementCount(); ++i) {
3602 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << Qt::endl;
3603
3604 }
3605 return s;
3606}
3607#endif
3608
3609QT_END_NAMESPACE
3610