PageRenderTime 52ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtbase/src/gui/painting/qpainterpath.cpp

https://gitlab.com/x33n/phantomjs
C++ | 1677 lines | 688 code | 197 blank | 792 comment | 158 complexity | d05844663bf298624e8adb45c03f9be9 MD5 | raw file
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
  4. ** Contact: http://www.qt-project.org/legal
  5. **
  6. ** This file is part of the QtGui module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and Digia. For licensing terms and
  14. ** conditions see http://qt.digia.com/licensing. For further information
  15. ** use the contact form at http://qt.digia.com/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 2.1 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 2.1 requirements
  23. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  24. **
  25. ** In addition, as a special exception, Digia gives you certain additional
  26. ** rights. These rights are described in the Digia Qt LGPL Exception
  27. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  28. **
  29. ** GNU General Public License Usage
  30. ** Alternatively, this file may be used under the terms of the GNU
  31. ** General Public License version 3.0 as published by the Free Software
  32. ** Foundation and appearing in the file LICENSE.GPL included in the
  33. ** packaging of this file. Please review the following information to
  34. ** ensure the GNU General Public License version 3.0 requirements will be
  35. ** met: http://www.gnu.org/copyleft/gpl.html.
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qpainterpath.h"
  42. #include "qpainterpath_p.h"
  43. #include <qbitmap.h>
  44. #include <qdebug.h>
  45. #include <qiodevice.h>
  46. #include <qlist.h>
  47. #include <qmatrix.h>
  48. #include <qpen.h>
  49. #include <qpolygon.h>
  50. #include <qtextlayout.h>
  51. #include <qvarlengtharray.h>
  52. #include <qmath.h>
  53. #include <private/qbezier_p.h>
  54. #include <private/qfontengine_p.h>
  55. #include <private/qnumeric_p.h>
  56. #include <private/qobject_p.h>
  57. #include <private/qpathclipper_p.h>
  58. #include <private/qstroker_p.h>
  59. #include <private/qtextengine_p.h>
  60. #include <limits.h>
  61. #if 0
  62. #include <performance.h>
  63. #else
  64. #define PM_INIT
  65. #define PM_MEASURE(x)
  66. #define PM_DISPLAY
  67. #endif
  68. QT_BEGIN_NAMESPACE
  69. struct QPainterPathPrivateDeleter
  70. {
  71. static inline void cleanup(QPainterPathPrivate *d)
  72. {
  73. // note - we must up-cast to QPainterPathData since QPainterPathPrivate
  74. // has a non-virtual destructor!
  75. if (d && !d->ref.deref())
  76. delete static_cast<QPainterPathData *>(d);
  77. }
  78. };
  79. // This value is used to determine the length of control point vectors
  80. // when approximating arc segments as curves. The factor is multiplied
  81. // with the radius of the circle.
  82. // #define QPP_DEBUG
  83. // #define QPP_STROKE_DEBUG
  84. //#define QPP_FILLPOLYGONS_DEBUG
  85. QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount);
  86. void 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. qreal w2 = r.width() / 2;
  97. qreal h2 = r.height() / 2;
  98. qreal angles[2] = { angle, angle + length };
  99. QPointF *points[2] = { startPoint, endPoint };
  100. for (int i = 0; i < 2; ++i) {
  101. if (!points[i])
  102. continue;
  103. qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
  104. qreal t = theta / 90;
  105. // truncate
  106. int quadrant = int(t);
  107. t -= quadrant;
  108. t = qt_t_for_arc_angle(90 * t);
  109. // swap x and y?
  110. if (quadrant & 1)
  111. t = 1 - t;
  112. qreal a, b, c, d;
  113. QBezier::coefficients(t, a, b, c, d);
  114. QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
  115. // left quadrants
  116. if (quadrant == 1 || quadrant == 2)
  117. p.rx() = -p.x();
  118. // top quadrants
  119. if (quadrant == 0 || quadrant == 1)
  120. p.ry() = -p.y();
  121. *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
  122. }
  123. }
  124. #ifdef QPP_DEBUG
  125. static void qt_debug_path(const QPainterPath &path)
  126. {
  127. const char *names[] = {
  128. "MoveTo ",
  129. "LineTo ",
  130. "CurveTo ",
  131. "CurveToData"
  132. };
  133. printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
  134. for (int i=0; i<path.elementCount(); ++i) {
  135. const QPainterPath::Element &e = path.elementAt(i);
  136. Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
  137. printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
  138. }
  139. }
  140. #endif
  141. /*!
  142. \class QPainterPath
  143. \ingroup painting
  144. \ingroup shared
  145. \inmodule QtGui
  146. \brief The QPainterPath class provides a container for painting operations,
  147. enabling graphical shapes to be constructed and reused.
  148. A painter path is an object composed of a number of graphical
  149. building blocks, such as rectangles, ellipses, lines, and curves.
  150. Building blocks can be joined in closed subpaths, for example as a
  151. rectangle or an ellipse. A closed path has coinciding start and
  152. end points. Or they can exist independently as unclosed subpaths,
  153. such as lines and curves.
  154. A QPainterPath object can be used for filling, outlining, and
  155. clipping. To generate fillable outlines for a given painter path,
  156. use the QPainterPathStroker class. The main advantage of painter
  157. paths over normal drawing operations is that complex shapes only
  158. need to be created once; then they can be drawn many times using
  159. only calls to the QPainter::drawPath() function.
  160. QPainterPath provides a collection of functions that can be used
  161. to obtain information about the path and its elements. In addition
  162. it is possible to reverse the order of the elements using the
  163. toReversed() function. There are also several functions to convert
  164. this painter path object into a polygon representation.
  165. \tableofcontents
  166. \section1 Composing a QPainterPath
  167. A QPainterPath object can be constructed as an empty path, with a
  168. given start point, or as a copy of another QPainterPath object.
  169. Once created, lines and curves can be added to the path using the
  170. lineTo(), arcTo(), cubicTo() and quadTo() functions. The lines and
  171. curves stretch from the currentPosition() to the position passed
  172. as argument.
  173. The currentPosition() of the QPainterPath object is always the end
  174. position of the last subpath that was added (or the initial start
  175. point). Use the moveTo() function to move the currentPosition()
  176. without adding a component. The moveTo() function implicitly
  177. starts a new subpath, and closes the previous one. Another way of
  178. starting a new subpath is to call the closeSubpath() function
  179. which closes the current path by adding a line from the
  180. currentPosition() back to the path's start position. Note that the
  181. new path will have (0, 0) as its initial currentPosition().
  182. QPainterPath class also provides several convenience functions to
  183. add closed subpaths to a painter path: addEllipse(), addPath(),
  184. addRect(), addRegion() and addText(). The addPolygon() function
  185. adds an \e unclosed subpath. In fact, these functions are all
  186. collections of moveTo(), lineTo() and cubicTo() operations.
  187. In addition, a path can be added to the current path using the
  188. connectPath() function. But note that this function will connect
  189. the last element of the current path to the first element of given
  190. one by adding a line.
  191. Below is a code snippet that shows how a QPainterPath object can
  192. be used:
  193. \table 100%
  194. \row
  195. \li \inlineimage qpainterpath-construction.png
  196. \li
  197. \snippet code/src_gui_painting_qpainterpath.cpp 0
  198. \endtable
  199. The painter path is initially empty when constructed. We first add
  200. a rectangle, which is a closed subpath. Then we add two bezier
  201. curves which together form a closed subpath even though they are
  202. not closed individually. Finally we draw the entire path. The path
  203. is filled using the default fill rule, Qt::OddEvenFill. Qt
  204. provides two methods for filling paths:
  205. \table
  206. \header
  207. \li Qt::OddEvenFill
  208. \li Qt::WindingFill
  209. \row
  210. \li \inlineimage qt-fillrule-oddeven.png
  211. \li \inlineimage qt-fillrule-winding.png
  212. \endtable
  213. See the Qt::FillRule documentation for the definition of the
  214. rules. A painter path's currently set fill rule can be retrieved
  215. using the fillRule() function, and altered using the setFillRule()
  216. function.
  217. \section1 QPainterPath Information
  218. The QPainterPath class provides a collection of functions that
  219. returns information about the path and its elements.
  220. The currentPosition() function returns the end point of the last
  221. subpath that was added (or the initial start point). The
  222. elementAt() function can be used to retrieve the various subpath
  223. elements, the \e number of elements can be retrieved using the
  224. elementCount() function, and the isEmpty() function tells whether
  225. this QPainterPath object contains any elements at all.
  226. The controlPointRect() function returns the rectangle containing
  227. all the points and control points in this path. This function is
  228. significantly faster to compute than the exact boundingRect()
  229. which returns the bounding rectangle of this painter path with
  230. floating point precision.
  231. Finally, QPainterPath provides the contains() function which can
  232. be used to determine whether a given point or rectangle is inside
  233. the path, and the intersects() function which determines if any of
  234. the points inside a given rectangle also are inside this path.
  235. \section1 QPainterPath Conversion
  236. For compatibility reasons, it might be required to simplify the
  237. representation of a painter path: QPainterPath provides the
  238. toFillPolygon(), toFillPolygons() and toSubpathPolygons()
  239. functions which convert the painter path into a polygon. The
  240. toFillPolygon() returns the painter path as one single polygon,
  241. while the two latter functions return a list of polygons.
  242. The toFillPolygons() and toSubpathPolygons() functions are
  243. provided because it is usually faster to draw several small
  244. polygons than to draw one large polygon, even though the total
  245. number of points drawn is the same. The difference between the two
  246. is the \e number of polygons they return: The toSubpathPolygons()
  247. creates one polygon for each subpath regardless of intersecting
  248. subpaths (i.e. overlapping bounding rectangles), while the
  249. toFillPolygons() functions creates only one polygon for
  250. overlapping subpaths.
  251. The toFillPolygon() and toFillPolygons() functions first convert
  252. all the subpaths to polygons, then uses a rewinding technique to
  253. make sure that overlapping subpaths can be filled using the
  254. correct fill rule. Note that rewinding inserts additional lines in
  255. the polygon so the outline of the fill polygon does not match the
  256. outline of the path.
  257. \section1 Examples
  258. Qt provides the \l {painting/painterpaths}{Painter Paths Example}
  259. and the \l {painting/deform}{Vector Deformation example} which are
  260. located in Qt's example directory.
  261. The \l {painting/painterpaths}{Painter Paths Example} shows how
  262. painter paths can be used to build complex shapes for rendering
  263. and lets the user experiment with the filling and stroking. The
  264. \l {painting/deform}{Vector Deformation Example} shows how to use
  265. QPainterPath to draw text.
  266. \table
  267. \header
  268. \li \l {painting/painterpaths}{Painter Paths Example}
  269. \li \l {painting/deform}{Vector Deformation Example}
  270. \row
  271. \li \inlineimage qpainterpath-example.png
  272. \li \inlineimage qpainterpath-demo.png
  273. \endtable
  274. \sa QPainterPathStroker, QPainter, QRegion, {Painter Paths Example}
  275. */
  276. /*!
  277. \enum QPainterPath::ElementType
  278. This enum describes the types of elements used to connect vertices
  279. in subpaths.
  280. Note that elements added as closed subpaths using the
  281. addEllipse(), addPath(), addPolygon(), addRect(), addRegion() and
  282. addText() convenience functions, is actually added to the path as
  283. a collection of separate elements using the moveTo(), lineTo() and
  284. cubicTo() functions.
  285. \value MoveToElement A new subpath. See also moveTo().
  286. \value LineToElement A line. See also lineTo().
  287. \value CurveToElement A curve. See also cubicTo() and quadTo().
  288. \value CurveToDataElement The extra data required to describe a curve in
  289. a CurveToElement element.
  290. \sa elementAt(), elementCount()
  291. */
  292. /*!
  293. \class QPainterPath::Element
  294. \inmodule QtGui
  295. \brief The QPainterPath::Element class specifies the position and
  296. type of a subpath.
  297. Once a QPainterPath object is constructed, subpaths like lines and
  298. curves can be added to the path (creating
  299. QPainterPath::LineToElement and QPainterPath::CurveToElement
  300. components).
  301. The lines and curves stretch from the currentPosition() to the
  302. position passed as argument. The currentPosition() of the
  303. QPainterPath object is always the end position of the last subpath
  304. that was added (or the initial start point). The moveTo() function
  305. can be used to move the currentPosition() without adding a line or
  306. curve, creating a QPainterPath::MoveToElement component.
  307. \sa QPainterPath
  308. */
  309. /*!
  310. \variable QPainterPath::Element::x
  311. \brief the x coordinate of the element's position.
  312. \sa {operator QPointF()}
  313. */
  314. /*!
  315. \variable QPainterPath::Element::y
  316. \brief the y coordinate of the element's position.
  317. \sa {operator QPointF()}
  318. */
  319. /*!
  320. \variable QPainterPath::Element::type
  321. \brief the type of element
  322. \sa isCurveTo(), isLineTo(), isMoveTo()
  323. */
  324. /*!
  325. \fn bool QPainterPath::Element::operator==(const Element &other) const
  326. \since 4.2
  327. Returns \c true if this element is equal to \a other;
  328. otherwise returns \c false.
  329. \sa operator!=()
  330. */
  331. /*!
  332. \fn bool QPainterPath::Element::operator!=(const Element &other) const
  333. \since 4.2
  334. Returns \c true if this element is not equal to \a other;
  335. otherwise returns \c false.
  336. \sa operator==()
  337. */
  338. /*!
  339. \fn bool QPainterPath::Element::isCurveTo () const
  340. Returns \c true if the element is a curve, otherwise returns \c false.
  341. \sa type, QPainterPath::CurveToElement
  342. */
  343. /*!
  344. \fn bool QPainterPath::Element::isLineTo () const
  345. Returns \c true if the element is a line, otherwise returns \c false.
  346. \sa type, QPainterPath::LineToElement
  347. */
  348. /*!
  349. \fn bool QPainterPath::Element::isMoveTo () const
  350. Returns \c true if the element is moving the current position,
  351. otherwise returns \c false.
  352. \sa type, QPainterPath::MoveToElement
  353. */
  354. /*!
  355. \fn QPainterPath::Element::operator QPointF () const
  356. Returns the element's position.
  357. \sa x, y
  358. */
  359. /*!
  360. \fn void QPainterPath::addEllipse(qreal x, qreal y, qreal width, qreal height)
  361. \overload
  362. Creates an ellipse within the bounding rectangle defined by its top-left
  363. corner at (\a x, \a y), \a width and \a height, and adds it to the
  364. painter path as a closed subpath.
  365. */
  366. /*!
  367. \since 4.4
  368. \fn void QPainterPath::addEllipse(const QPointF &center, qreal rx, qreal ry)
  369. \overload
  370. Creates an ellipse positioned at \a{center} with radii \a{rx} and \a{ry},
  371. and adds it to the painter path as a closed subpath.
  372. */
  373. /*!
  374. \fn void QPainterPath::addText(qreal x, qreal y, const QFont &font, const QString &text)
  375. \overload
  376. Adds the given \a text to this path as a set of closed subpaths created
  377. from the \a font supplied. The subpaths are positioned so that the left
  378. end of the text's baseline lies at the point specified by (\a x, \a y).
  379. */
  380. /*!
  381. \fn int QPainterPath::elementCount() const
  382. Returns the number of path elements in the painter path.
  383. \sa ElementType, elementAt(), isEmpty()
  384. */
  385. int QPainterPath::elementCount() const
  386. {
  387. return d_ptr ? d_ptr->elements.size() : 0;
  388. }
  389. /*!
  390. \fn QPainterPath::Element QPainterPath::elementAt(int index) const
  391. Returns the element at the given \a index in the painter path.
  392. \sa ElementType, elementCount(), isEmpty()
  393. */
  394. QPainterPath::Element QPainterPath::elementAt(int i) const
  395. {
  396. Q_ASSERT(d_ptr);
  397. Q_ASSERT(i >= 0 && i < elementCount());
  398. return d_ptr->elements.at(i);
  399. }
  400. /*!
  401. \fn void QPainterPath::setElementPositionAt(int index, qreal x, qreal y)
  402. \since 4.2
  403. Sets the x and y coordinate of the element at index \a index to \a
  404. x and \a y.
  405. */
  406. void QPainterPath::setElementPositionAt(int i, qreal x, qreal y)
  407. {
  408. Q_ASSERT(d_ptr);
  409. Q_ASSERT(i >= 0 && i < elementCount());
  410. detach();
  411. QPainterPath::Element &e = d_ptr->elements[i];
  412. e.x = x;
  413. e.y = y;
  414. }
  415. /*###
  416. \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
  417. Appends the \a other painter path to this painter path and returns a
  418. reference to the result.
  419. */
  420. /*!
  421. Constructs an empty QPainterPath object.
  422. */
  423. QPainterPath::QPainterPath()
  424. : d_ptr(0)
  425. {
  426. }
  427. /*!
  428. \fn QPainterPath::QPainterPath(const QPainterPath &path)
  429. Creates a QPainterPath object that is a copy of the given \a path.
  430. \sa operator=()
  431. */
  432. QPainterPath::QPainterPath(const QPainterPath &other)
  433. : d_ptr(other.d_ptr.data())
  434. {
  435. if (d_ptr)
  436. d_ptr->ref.ref();
  437. }
  438. /*!
  439. Creates a QPainterPath object with the given \a startPoint as its
  440. current position.
  441. */
  442. QPainterPath::QPainterPath(const QPointF &startPoint)
  443. : d_ptr(new QPainterPathData)
  444. {
  445. Element e = { startPoint.x(), startPoint.y(), MoveToElement };
  446. d_func()->elements << e;
  447. }
  448. void QPainterPath::detach()
  449. {
  450. if (d_ptr->ref.load() != 1)
  451. detach_helper();
  452. setDirty(true);
  453. }
  454. /*!
  455. \internal
  456. */
  457. void QPainterPath::detach_helper()
  458. {
  459. QPainterPathPrivate *data = new QPainterPathData(*d_func());
  460. d_ptr.reset(data);
  461. }
  462. /*!
  463. \internal
  464. */
  465. void QPainterPath::ensureData_helper()
  466. {
  467. QPainterPathPrivate *data = new QPainterPathData;
  468. data->elements.reserve(16);
  469. QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
  470. data->elements << e;
  471. d_ptr.reset(data);
  472. Q_ASSERT(d_ptr != 0);
  473. }
  474. /*!
  475. \fn QPainterPath &QPainterPath::operator=(const QPainterPath &path)
  476. Assigns the given \a path to this painter path.
  477. \sa QPainterPath()
  478. */
  479. QPainterPath &QPainterPath::operator=(const QPainterPath &other)
  480. {
  481. if (other.d_func() != d_func()) {
  482. QPainterPathPrivate *data = other.d_func();
  483. if (data)
  484. data->ref.ref();
  485. d_ptr.reset(data);
  486. }
  487. return *this;
  488. }
  489. /*!
  490. \fn QPainterPath &QPainterPath::operator=(QPainterPath &&other)
  491. Move-assigns \a other to this QPainterPath instance.
  492. \since 5.2
  493. */
  494. /*!
  495. \fn void QPainterPath::swap(QPainterPath &other)
  496. \since 4.8
  497. Swaps painter path \a other with this painter path. This operation is very
  498. fast and never fails.
  499. */
  500. /*!
  501. Destroys this QPainterPath object.
  502. */
  503. QPainterPath::~QPainterPath()
  504. {
  505. }
  506. /*!
  507. Closes the current subpath by drawing a line to the beginning of
  508. the subpath, automatically starting a new path. The current point
  509. of the new path is (0, 0).
  510. If the subpath does not contain any elements, this function does
  511. nothing.
  512. \sa moveTo(), {QPainterPath#Composing a QPainterPath}{Composing
  513. a QPainterPath}
  514. */
  515. void QPainterPath::closeSubpath()
  516. {
  517. #ifdef QPP_DEBUG
  518. printf("QPainterPath::closeSubpath()\n");
  519. #endif
  520. if (isEmpty())
  521. return;
  522. detach();
  523. d_func()->close();
  524. }
  525. /*!
  526. \fn void QPainterPath::moveTo(qreal x, qreal y)
  527. \overload
  528. Moves the current position to (\a{x}, \a{y}) and starts a new
  529. subpath, implicitly closing the previous path.
  530. */
  531. /*!
  532. \fn void QPainterPath::moveTo(const QPointF &point)
  533. Moves the current point to the given \a point, implicitly starting
  534. a new subpath and closing the previous one.
  535. \sa closeSubpath(), {QPainterPath#Composing a
  536. QPainterPath}{Composing a QPainterPath}
  537. */
  538. void QPainterPath::moveTo(const QPointF &p)
  539. {
  540. #ifdef QPP_DEBUG
  541. printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
  542. #endif
  543. if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
  544. #ifndef QT_NO_DEBUG
  545. qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
  546. #endif
  547. return;
  548. }
  549. ensureData();
  550. detach();
  551. QPainterPathData *d = d_func();
  552. Q_ASSERT(!d->elements.isEmpty());
  553. d->require_moveTo = false;
  554. if (d->elements.last().type == MoveToElement) {
  555. d->elements.last().x = p.x();
  556. d->elements.last().y = p.y();
  557. } else {
  558. Element elm = { p.x(), p.y(), MoveToElement };
  559. d->elements.append(elm);
  560. }
  561. d->cStart = d->elements.size() - 1;
  562. }
  563. /*!
  564. \fn void QPainterPath::lineTo(qreal x, qreal y)
  565. \overload
  566. Draws a line from the current position to the point (\a{x},
  567. \a{y}).
  568. */
  569. /*!
  570. \fn void QPainterPath::lineTo(const QPointF &endPoint)
  571. Adds a straight line from the current position to the given \a
  572. endPoint. After the line is drawn, the current position is updated
  573. to be at the end point of the line.
  574. \sa addPolygon(), addRect(), {QPainterPath#Composing a
  575. QPainterPath}{Composing a QPainterPath}
  576. */
  577. void QPainterPath::lineTo(const QPointF &p)
  578. {
  579. #ifdef QPP_DEBUG
  580. printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
  581. #endif
  582. if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
  583. #ifndef QT_NO_DEBUG
  584. qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
  585. #endif
  586. return;
  587. }
  588. ensureData();
  589. detach();
  590. QPainterPathData *d = d_func();
  591. Q_ASSERT(!d->elements.isEmpty());
  592. d->maybeMoveTo();
  593. if (p == QPointF(d->elements.last()))
  594. return;
  595. Element elm = { p.x(), p.y(), LineToElement };
  596. d->elements.append(elm);
  597. d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
  598. }
  599. /*!
  600. \fn void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X,
  601. qreal c2Y, qreal endPointX, qreal endPointY);
  602. \overload
  603. Adds a cubic Bezier curve between the current position and the end
  604. point (\a{endPointX}, \a{endPointY}) with control points specified
  605. by (\a{c1X}, \a{c1Y}) and (\a{c2X}, \a{c2Y}).
  606. */
  607. /*!
  608. \fn void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
  609. Adds a cubic Bezier curve between the current position and the
  610. given \a endPoint using the control points specified by \a c1, and
  611. \a c2.
  612. After the curve is added, the current position is updated to be at
  613. the end point of the curve.
  614. \table 100%
  615. \row
  616. \li \inlineimage qpainterpath-cubicto.png
  617. \li
  618. \snippet code/src_gui_painting_qpainterpath.cpp 1
  619. \endtable
  620. \sa quadTo(), {QPainterPath#Composing a QPainterPath}{Composing
  621. a QPainterPath}
  622. */
  623. void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
  624. {
  625. #ifdef QPP_DEBUG
  626. printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
  627. c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
  628. #endif
  629. if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y())
  630. || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
  631. #ifndef QT_NO_DEBUG
  632. qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call");
  633. #endif
  634. return;
  635. }
  636. ensureData();
  637. detach();
  638. QPainterPathData *d = d_func();
  639. Q_ASSERT(!d->elements.isEmpty());
  640. // Abort on empty curve as a stroker cannot handle this and the
  641. // curve is irrelevant anyway.
  642. if (d->elements.last() == c1 && c1 == c2 && c2 == e)
  643. return;
  644. d->maybeMoveTo();
  645. Element ce1 = { c1.x(), c1.y(), CurveToElement };
  646. Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
  647. Element ee = { e.x(), e.y(), CurveToDataElement };
  648. d->elements << ce1 << ce2 << ee;
  649. }
  650. /*!
  651. \fn void QPainterPath::quadTo(qreal cx, qreal cy, qreal endPointX, qreal endPointY);
  652. \overload
  653. Adds a quadratic Bezier curve between the current point and the endpoint
  654. (\a{endPointX}, \a{endPointY}) with the control point specified by
  655. (\a{cx}, \a{cy}).
  656. */
  657. /*!
  658. \fn void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)
  659. Adds a quadratic Bezier curve between the current position and the
  660. given \a endPoint with the control point specified by \a c.
  661. After the curve is added, the current point is updated to be at
  662. the end point of the curve.
  663. \sa cubicTo(), {QPainterPath#Composing a QPainterPath}{Composing a
  664. QPainterPath}
  665. */
  666. void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
  667. {
  668. #ifdef QPP_DEBUG
  669. printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
  670. c.x(), c.y(), e.x(), e.y());
  671. #endif
  672. if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
  673. #ifndef QT_NO_DEBUG
  674. qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call");
  675. #endif
  676. return;
  677. }
  678. ensureData();
  679. detach();
  680. Q_D(QPainterPath);
  681. Q_ASSERT(!d->elements.isEmpty());
  682. const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
  683. QPointF prev(elm.x, elm.y);
  684. // Abort on empty curve as a stroker cannot handle this and the
  685. // curve is irrelevant anyway.
  686. if (prev == c && c == e)
  687. return;
  688. QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
  689. QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
  690. cubicTo(c1, c2, e);
  691. }
  692. /*!
  693. \fn void QPainterPath::arcTo(qreal x, qreal y, qreal width, qreal
  694. height, qreal startAngle, qreal sweepLength)
  695. \overload
  696. Creates an arc that occupies the rectangle QRectF(\a x, \a y, \a
  697. width, \a height), beginning at the specified \a startAngle and
  698. extending \a sweepLength degrees counter-clockwise.
  699. */
  700. /*!
  701. \fn void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
  702. Creates an arc that occupies the given \a rectangle, beginning at
  703. the specified \a startAngle and extending \a sweepLength degrees
  704. counter-clockwise.
  705. Angles are specified in degrees. Clockwise arcs can be specified
  706. using negative angles.
  707. Note that this function connects the starting point of the arc to
  708. the current position if they are not already connected. After the
  709. arc has been added, the current position is the last point in
  710. arc. To draw a line back to the first point, use the
  711. closeSubpath() function.
  712. \table 100%
  713. \row
  714. \li \inlineimage qpainterpath-arcto.png
  715. \li
  716. \snippet code/src_gui_painting_qpainterpath.cpp 2
  717. \endtable
  718. \sa arcMoveTo(), addEllipse(), QPainter::drawArc(), QPainter::drawPie(),
  719. {QPainterPath#Composing a QPainterPath}{Composing a
  720. QPainterPath}
  721. */
  722. void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
  723. {
  724. #ifdef QPP_DEBUG
  725. printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
  726. rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
  727. #endif
  728. if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height())
  729. || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) {
  730. #ifndef QT_NO_DEBUG
  731. qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call");
  732. #endif
  733. return;
  734. }
  735. if (rect.isNull())
  736. return;
  737. ensureData();
  738. detach();
  739. int point_count;
  740. QPointF pts[15];
  741. QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
  742. lineTo(curve_start);
  743. for (int i=0; i<point_count; i+=3) {
  744. cubicTo(pts[i].x(), pts[i].y(),
  745. pts[i+1].x(), pts[i+1].y(),
  746. pts[i+2].x(), pts[i+2].y());
  747. }
  748. }
  749. /*!
  750. \fn void QPainterPath::arcMoveTo(qreal x, qreal y, qreal width, qreal height, qreal angle)
  751. \overload
  752. \since 4.2
  753. Creates a move to that lies on the arc that occupies the
  754. QRectF(\a x, \a y, \a width, \a height) at \a angle.
  755. */
  756. /*!
  757. \fn void QPainterPath::arcMoveTo(const QRectF &rectangle, qreal angle)
  758. \since 4.2
  759. Creates a move to that lies on the arc that occupies the given \a
  760. rectangle at \a angle.
  761. Angles are specified in degrees. Clockwise arcs can be specified
  762. using negative angles.
  763. \sa moveTo(), arcTo()
  764. */
  765. void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle)
  766. {
  767. if (rect.isNull())
  768. return;
  769. QPointF pt;
  770. qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
  771. moveTo(pt);
  772. }
  773. /*!
  774. \fn QPointF QPainterPath::currentPosition() const
  775. Returns the current position of the path.
  776. */
  777. QPointF QPainterPath::currentPosition() const
  778. {
  779. return !d_ptr || d_func()->elements.isEmpty()
  780. ? QPointF()
  781. : QPointF(d_func()->elements.last().x, d_func()->elements.last().y);
  782. }
  783. /*!
  784. \fn void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
  785. \overload
  786. Adds a rectangle at position (\a{x}, \a{y}), with the given \a
  787. width and \a height, as a closed subpath.
  788. */
  789. /*!
  790. \fn void QPainterPath::addRect(const QRectF &rectangle)
  791. Adds the given \a rectangle to this path as a closed subpath.
  792. The \a rectangle is added as a clockwise set of lines. The painter
  793. path's current position after the \a rectangle has been added is
  794. at the top-left corner of the rectangle.
  795. \table 100%
  796. \row
  797. \li \inlineimage qpainterpath-addrectangle.png
  798. \li
  799. \snippet code/src_gui_painting_qpainterpath.cpp 3
  800. \endtable
  801. \sa addRegion(), lineTo(), {QPainterPath#Composing a
  802. QPainterPath}{Composing a QPainterPath}
  803. */
  804. void QPainterPath::addRect(const QRectF &r)
  805. {
  806. if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) {
  807. #ifndef QT_NO_DEBUG
  808. qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call");
  809. #endif
  810. return;
  811. }
  812. if (r.isNull())
  813. return;
  814. ensureData();
  815. detach();
  816. bool first = d_func()->elements.size() < 2;
  817. d_func()->elements.reserve(d_func()->elements.size() + 5);
  818. moveTo(r.x(), r.y());
  819. Element l1 = { r.x() + r.width(), r.y(), LineToElement };
  820. Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
  821. Element l3 = { r.x(), r.y() + r.height(), LineToElement };
  822. Element l4 = { r.x(), r.y(), LineToElement };
  823. d_func()->elements << l1 << l2 << l3 << l4;
  824. d_func()->require_moveTo = true;
  825. d_func()->convex = first;
  826. }
  827. /*!
  828. Adds the given \a polygon to the path as an (unclosed) subpath.
  829. Note that the current position after the polygon has been added,
  830. is the last point in \a polygon. To draw a line back to the first
  831. point, use the closeSubpath() function.
  832. \table 100%
  833. \row
  834. \li \inlineimage qpainterpath-addpolygon.png
  835. \li
  836. \snippet code/src_gui_painting_qpainterpath.cpp 4
  837. \endtable
  838. \sa lineTo(), {QPainterPath#Composing a QPainterPath}{Composing
  839. a QPainterPath}
  840. */
  841. void QPainterPath::addPolygon(const QPolygonF &polygon)
  842. {
  843. if (polygon.isEmpty())
  844. return;
  845. ensureData();
  846. detach();
  847. d_func()->elements.reserve(d_func()->elements.size() + polygon.size());
  848. moveTo(polygon.first());
  849. for (int i=1; i<polygon.size(); ++i) {
  850. Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
  851. d_func()->elements << elm;
  852. }
  853. }
  854. /*!
  855. \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle)
  856. Creates an ellipse within the specified \a boundingRectangle
  857. and adds it to the painter path as a closed subpath.
  858. The ellipse is composed of a clockwise curve, starting and
  859. finishing at zero degrees (the 3 o'clock position).
  860. \table 100%
  861. \row
  862. \li \inlineimage qpainterpath-addellipse.png
  863. \li
  864. \snippet code/src_gui_painting_qpainterpath.cpp 5
  865. \endtable
  866. \sa arcTo(), QPainter::drawEllipse(), {QPainterPath#Composing a
  867. QPainterPath}{Composing a QPainterPath}
  868. */
  869. void QPainterPath::addEllipse(const QRectF &boundingRect)
  870. {
  871. if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y())
  872. || !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) {
  873. #ifndef QT_NO_DEBUG
  874. qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call");
  875. #endif
  876. return;
  877. }
  878. if (boundingRect.isNull())
  879. return;
  880. ensureData();
  881. detach();
  882. Q_D(QPainterPath);
  883. bool first = d_func()->elements.size() < 2;
  884. d->elements.reserve(d->elements.size() + 13);
  885. QPointF pts[12];
  886. int point_count;
  887. QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
  888. moveTo(start);
  889. cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
  890. cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
  891. cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
  892. cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
  893. d_func()->require_moveTo = true;
  894. d_func()->convex = first;
  895. }
  896. /*!
  897. \fn void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
  898. Adds the given \a text to this path as a set of closed subpaths
  899. created from the \a font supplied. The subpaths are positioned so
  900. that the left end of the text's baseline lies at the specified \a
  901. point.
  902. \table 100%
  903. \row
  904. \li \inlineimage qpainterpath-addtext.png
  905. \li
  906. \snippet code/src_gui_painting_qpainterpath.cpp 6
  907. \endtable
  908. \sa QPainter::drawText(), {QPainterPath#Composing a
  909. QPainterPath}{Composing a QPainterPath}
  910. */
  911. void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
  912. {
  913. if (text.isEmpty())
  914. return;
  915. ensureData();
  916. detach();
  917. QTextLayout layout(text, f);
  918. layout.setCacheEnabled(true);
  919. QTextEngine *eng = layout.engine();
  920. layout.beginLayout();
  921. QTextLine line = layout.createLine();
  922. Q_UNUSED(line);
  923. layout.endLayout();
  924. const QScriptLine &sl = eng->lines[0];
  925. if (!sl.length || !eng->layoutData)
  926. return;
  927. int nItems = eng->layoutData->items.size();
  928. qreal x(point.x());
  929. qreal y(point.y());
  930. QVarLengthArray<int> visualOrder(nItems);
  931. QVarLengthArray<uchar> levels(nItems);
  932. for (int i = 0; i < nItems; ++i)
  933. levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
  934. QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
  935. for (int i = 0; i < nItems; ++i) {
  936. int item = visualOrder[i];
  937. QScriptItem &si = eng->layoutData->items[item];
  938. if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
  939. QGlyphLayout glyphs = eng->shapedGlyphs(&si);
  940. QFontEngine *fe = f.d->engineForScript(si.analysis.script);
  941. Q_ASSERT(fe);
  942. fe->addOutlineToPath(x, y, glyphs, this,
  943. si.analysis.bidiLevel % 2
  944. ? QTextItem::RenderFlags(QTextItem::RightToLeft)
  945. : QTextItem::RenderFlags(0));
  946. const qreal lw = fe->lineThickness().toReal();
  947. if (f.d->underline) {
  948. qreal pos = fe->underlinePosition().toReal();
  949. addRect(x, y + pos, si.width.toReal(), lw);
  950. }
  951. if (f.d->overline) {
  952. qreal pos = fe->ascent().toReal() + 1;
  953. addRect(x, y - pos, si.width.toReal(), lw);
  954. }
  955. if (f.d->strikeOut) {
  956. qreal pos = fe->ascent().toReal() / 3;
  957. addRect(x, y - pos, si.width.toReal(), lw);
  958. }
  959. }
  960. x += si.width.toReal();
  961. }
  962. }
  963. /*!
  964. \fn void QPainterPath::addPath(const QPainterPath &path)
  965. Adds the given \a path to \e this path as a closed subpath.
  966. \sa connectPath(), {QPainterPath#Composing a
  967. QPainterPath}{Composing a QPainterPath}
  968. */
  969. void QPainterPath::addPath(const QPainterPath &other)
  970. {
  971. if (other.isEmpty())
  972. return;
  973. ensureData();
  974. detach();
  975. QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
  976. // Remove last moveto so we don't get multiple moveto's
  977. if (d->elements.last().type == MoveToElement)
  978. d->elements.remove(d->elements.size()-1);
  979. // Locate where our own current subpath will start after the other path is added.
  980. int cStart = d->elements.size() + other.d_func()->cStart;
  981. d->elements += other.d_func()->elements;
  982. d->cStart = cStart;
  983. d->require_moveTo = other.d_func()->isClosed();
  984. }
  985. /*!
  986. \fn void QPainterPath::connectPath(const QPainterPath &path)
  987. Connects the given \a path to \e this path by adding a line from the
  988. last element of this path to the first element of the given path.
  989. \sa addPath(), {QPainterPath#Composing a QPainterPath}{Composing
  990. a QPainterPath}
  991. */
  992. void QPainterPath::connectPath(const QPainterPath &other)
  993. {
  994. if (other.isEmpty())
  995. return;
  996. ensureData();
  997. detach();
  998. QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
  999. // Remove last moveto so we don't get multiple moveto's
  1000. if (d->elements.last().type == MoveToElement)
  1001. d->elements.remove(d->elements.size()-1);
  1002. // Locate where our own current subpath will start after the other path is added.
  1003. int cStart = d->elements.size() + other.d_func()->cStart;
  1004. int first = d->elements.size();
  1005. d->elements += other.d_func()->elements;
  1006. if (first != 0)
  1007. d->elements[first].type = LineToElement;
  1008. // avoid duplicate points
  1009. if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
  1010. d->elements.remove(first--);
  1011. --cStart;
  1012. }
  1013. if (cStart != first)
  1014. d->cStart = cStart;
  1015. }
  1016. /*!
  1017. Adds the given \a region to the path by adding each rectangle in
  1018. the region as a separate closed subpath.
  1019. \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
  1020. a QPainterPath}
  1021. */
  1022. void QPainterPath::addRegion(const QRegion &region)
  1023. {
  1024. ensureData();
  1025. detach();
  1026. QVector<QRect> rects = region.rects();
  1027. d_func()->elements.reserve(rects.size() * 5);
  1028. for (int i=0; i<rects.size(); ++i)
  1029. addRect(rects.at(i));
  1030. }
  1031. /*!
  1032. Returns the painter path's currently set fill rule.
  1033. \sa setFillRule()
  1034. */
  1035. Qt::FillRule QPainterPath::fillRule() const
  1036. {
  1037. return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
  1038. }
  1039. /*!
  1040. \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
  1041. Sets the fill rule of the painter path to the given \a
  1042. fillRule. Qt provides two methods for filling paths:
  1043. \table
  1044. \header
  1045. \li Qt::OddEvenFill (default)
  1046. \li Qt::WindingFill
  1047. \row
  1048. \li \inlineimage qt-fillrule-oddeven.png
  1049. \li \inlineimage qt-fillrule-winding.png
  1050. \endtable
  1051. \sa fillRule()
  1052. */
  1053. void QPainterPath::setFillRule(Qt::FillRule fillRule)
  1054. {
  1055. ensureData();
  1056. if (d_func()->fillRule == fillRule)
  1057. return;
  1058. detach();
  1059. d_func()->fillRule = fillRule;
  1060. }
  1061. #define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
  1062. + 3*bezier.coord##2 \
  1063. - 3*bezier.coord##3 \
  1064. +bezier.coord##4)
  1065. #define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
  1066. - 2*bezier.coord##2 \
  1067. + bezier.coord##3)
  1068. #define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
  1069. + bezier.coord##2)
  1070. #define QT_BEZIER_CHECK_T(bezier, t) \
  1071. if (t >= 0 && t <= 1) { \
  1072. QPointF p(b.pointAt(t)); \
  1073. if (p.x() < minx) minx = p.x(); \
  1074. else if (p.x() > maxx) maxx = p.x(); \
  1075. if (p.y() < miny) miny = p.y(); \
  1076. else if (p.y() > maxy) maxy = p.y(); \
  1077. }
  1078. static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
  1079. {
  1080. qreal minx, miny, maxx, maxy;
  1081. // initialize with end points
  1082. if (b.x1 < b.x4) {
  1083. minx = b.x1;
  1084. maxx = b.x4;
  1085. } else {
  1086. minx = b.x4;
  1087. maxx = b.x1;
  1088. }
  1089. if (b.y1 < b.y4) {
  1090. miny = b.y1;
  1091. maxy = b.y4;
  1092. } else {
  1093. miny = b.y4;
  1094. maxy = b.y1;
  1095. }
  1096. // Update for the X extrema
  1097. {
  1098. qreal ax = QT_BEZIER_A(b, x);
  1099. qreal bx = QT_BEZIER_B(b, x);
  1100. qreal cx = QT_BEZIER_C(b, x);
  1101. // specialcase quadratic curves to avoid div by zero
  1102. if (qFuzzyIsNull(ax)) {
  1103. // linear curves are covered by initialization.
  1104. if (!qFuzzyIsNull(bx)) {
  1105. qreal t = -cx / bx;
  1106. QT_BEZIER_CHECK_T(b, t);
  1107. }
  1108. } else {
  1109. const qreal tx = bx * bx - 4 * ax * cx;
  1110. if (tx >= 0) {
  1111. qreal temp = qSqrt(tx);
  1112. qreal rcp = 1 / (2 * ax);
  1113. qreal t1 = (-bx + temp) * rcp;
  1114. QT_BEZIER_CHECK_T(b, t1);
  1115. qreal t2 = (-bx - temp) * rcp;
  1116. QT_BEZIER_CHECK_T(b, t2);
  1117. }
  1118. }
  1119. }
  1120. // Update for the Y extrema
  1121. {
  1122. qreal ay = QT_BEZIER_A(b, y);
  1123. qreal by = QT_BEZIER_B(b, y);
  1124. qreal cy = QT_BEZIER_C(b, y);
  1125. // specialcase quadratic curves to avoid div by zero
  1126. if (qFuzzyIsNull(ay)) {
  1127. // linear curves are covered by initialization.
  1128. if (!qFuzzyIsNull(by)) {
  1129. qreal t = -cy / by;
  1130. QT_BEZIER_CHECK_T(b, t);
  1131. }
  1132. } else {
  1133. const qreal ty = by * by - 4 * ay * cy;
  1134. if (ty > 0) {
  1135. qreal temp = qSqrt(ty);
  1136. qreal rcp = 1 / (2 * ay);
  1137. qreal t1 = (-by + temp) * rcp;
  1138. QT_BEZIER_CHECK_T(b, t1);
  1139. qreal t2 = (-by - temp) * rcp;
  1140. QT_BEZIER_CHECK_T(b, t2);
  1141. }
  1142. }
  1143. }
  1144. return QRectF(minx, miny, maxx - minx, maxy - miny);
  1145. }
  1146. /*!
  1147. Returns the bounding rectangle of this painter path as a rectangle with
  1148. floating point precision.
  1149. \sa controlPointRect()
  1150. */
  1151. QRectF QPainterPath::boundingRect() const
  1152. {
  1153. if (!d_ptr)
  1154. return QRectF();
  1155. QPainterPathData *d = d_func();
  1156. if (d->dirtyBounds)
  1157. computeBoundingRect();
  1158. return d->bounds;
  1159. }
  1160. /*!
  1161. Returns the rectangle containing all the points and control points
  1162. in this path.
  1163. This function is significantly faster to compute than the exact
  1164. boundingRect(), and the returned rectangle is always a superset of
  1165. the rectangle returned by boundingRect().
  1166. \sa boundingRect()
  1167. */
  1168. QRectF QPainterPath::controlPointRect() const
  1169. {
  1170. if (!d_ptr)
  1171. return QRectF();
  1172. QPainterPathData *d = d_func();
  1173. if (d->dirtyControlBounds)
  1174. computeControlPointRect();
  1175. return d->controlBounds;
  1176. }
  1177. /*!
  1178. \fn bool QPainterPath::isEmpty() const
  1179. Returns \c true if either there are no elements in this path, or if the only
  1180. element is a MoveToElement; otherwise returns \c false.
  1181. \sa elementCount()
  1182. */
  1183. bool QPainterPath::isEmpty() const
  1184. {
  1185. return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
  1186. }
  1187. /*!
  1188. Creates and returns a reversed copy of the path.
  1189. It is the order of the elements that is reversed: If a
  1190. QPainterPath is composed by calling the moveTo(), lineTo() and
  1191. cubicTo() functions in the specified order, the reversed copy is
  1192. composed by calling cubicTo(), lineTo() and moveTo().
  1193. */
  1194. QPainterPath QPainterPath::toReversed() const
  1195. {
  1196. Q_D(const QPainterPath);
  1197. QPainterPath rev;
  1198. if (isEmpty()) {
  1199. rev = *this;
  1200. return rev;
  1201. }
  1202. rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
  1203. for (int i=d->elements.size()-1; i>=1; --i) {
  1204. const QPainterPath::Element &elm = d->elements.at(i);
  1205. const QPainterPath::Element &prev = d->elements.at(i-1);
  1206. switch (elm.type) {
  1207. case LineToElement:
  1208. rev.lineTo(prev.x, prev.y);
  1209. break;
  1210. case MoveToElement:
  1211. rev.moveTo(prev.x, prev.y);
  1212. break;
  1213. case CurveToDataElement:
  1214. {
  1215. Q_ASSERT(i>=3);
  1216. const QPainterPath::Element &cp1 = d->elements.at(i-2);
  1217. const QPainterPath::Element &sp = d->elements.at(i-3);
  1218. Q_ASSERT(prev.type == CurveToDataElement);
  1219. Q_ASSERT(cp1.type == CurveToElement);
  1220. rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
  1221. i -= 2;
  1222. break;
  1223. }
  1224. default:
  1225. Q_ASSERT(!"qt_reversed_path");
  1226. break;
  1227. }
  1228. }
  1229. //qt_debug_path(rev);
  1230. return rev;
  1231. }
  1232. /*!
  1233. Converts the path into a list of polygons using the QTransform
  1234. \a matrix, and returns the list.
  1235. This function creates one polygon for each subpath regardless of
  1236. intersecting subpaths (i.e. overlapping bounding rectangles). To
  1237. make sure that such overlapping subpaths are filled correctly, use
  1238. the toFillPolygons() function instead.
  1239. \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
  1240. Conversion}{QPainterPath Conversion}
  1241. */
  1242. QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
  1243. {
  1244. Q_D(const QPainterPath);
  1245. QList<QPolygonF> flatCurves;
  1246. if (isEmpty())
  1247. return flatCurves;
  1248. QPolygonF current;
  1249. for (int i=0; i<elementCount(); ++i) {
  1250. const QPainterPath::Element &e = d->elements.at(i);
  1251. switch (e.type) {
  1252. case QPainterPath::MoveToElement:
  1253. if (current.size() > 1)
  1254. flatCurves += current;
  1255. current.clear();
  1256. current.reserve(16);
  1257. current += QPointF(e.x, e.y) * matrix;
  1258. break;
  1259. case QPainterPath::LineToElement:
  1260. current += QPointF(e.x, e.y) * matrix;
  1261. break;
  1262. case QPainterPath::CurveToElement: {
  1263. Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
  1264. Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
  1265. QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
  1266. QPointF(e.x, e.y) * matrix,
  1267. QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
  1268. QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
  1269. bezier.addToPolygon(&current);
  1270. i+=2;
  1271. break;
  1272. }
  1273. case QPainterPath::CurveToDataElement:
  1274. Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
  1275. break;
  1276. }
  1277. }
  1278. if (current.size()>1)
  1279. flatCurves += current;
  1280. return flatCurves;
  1281. }
  1282. /*!
  1283. \overload
  1284. */
  1285. QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
  1286. {
  1287. return toSubpathPolygons(QTransform(matrix));
  1288. }
  1289. /*!
  1290. Converts the path into a list of polygons using the
  1291. QTransform \a matrix, and returns the list.
  1292. The function differs from the toFillPolygon() function in that it
  1293. creates several polygons. It is provided because it is usually
  1294. faster to draw several small polygons than to draw one large
  1295. polygon, even though the total number of points drawn is the same.
  1296. The toFillPolygons() function differs from the toSubpathPolygons()
  1297. function in that it create only polygon for subpaths that have
  1298. overlapping bounding rectangles.
  1299. Like the toFillPolygon() function, this function uses a rewinding
  1300. technique to make sure that overlapping subpaths can be filled
  1301. using the correct fill rule. Note that rewinding inserts addition
  1302. lines in the polygons so the outline of the fill polygon does not
  1303. match the outline of the path.
  1304. \sa toSubpathPolygons(), toFillPolygon(),
  1305. {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
  1306. */
  1307. QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
  1308. {
  1309. QList<QPolygonF> polys;
  1310. QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
  1311. int count = subpaths.size();
  1312. if (count == 0)
  1313. return polys;
  1314. QList<QRectF> bounds;
  1315. for (int i=0; i<count; ++i)
  1316. bounds += subpaths.at(i).boundingRect();
  1317. #ifdef QPP_FILLPOLYGONS_DEBUG
  1318. printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
  1319. for (int i=0; i<bounds.size(); ++i)
  1320. qDebug() << " bounds" << i << bounds.at(i);
  1321. #endif
  1322. QVector< QList<int> > isects;
  1323. isects.resize(count);
  1324. // find all intersections
  1325. for (int j=0; j<count; ++j) {
  1326. if (subpaths.at(j).size() <= 2)
  1327. continue;
  1328. QRectF cbounds = bounds.at(j);
  1329. for (int i=0; i<count; ++i) {
  1330. if (cbounds.intersects(bounds.at(i))) {
  1331. isects[j] << i;
  1332. }
  1333. }
  1334. }
  1335. #ifdef QPP_FILLPOLYGONS_DEBUG
  1336. printf("Intersections before flattening:\n");
  1337. for (int i = 0; i < count; ++i) {
  1338. printf("%d: ", i);
  1339. for (int j = 0; j < isects[i].size(); ++j) {
  1340. printf("%d ", isects[i][