source: trunk/src/gui/painting/qpainterpath.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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