1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QPAINTERPATH_P_H
5#define QPAINTERPATH_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of other Qt classes. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtGui/private/qtguiglobal_p.h>
19#include "QtGui/qpainterpath.h"
20#include "QtGui/qregion.h"
21#include "QtCore/qlist.h"
22#include "QtCore/qshareddata.h"
23#include "QtCore/qvarlengtharray.h"
24
25#include <qdebug.h>
26
27#include <private/qvectorpath_p.h>
28#include <private/qstroker_p.h>
29
30#include <memory>
31
32QT_BEGIN_NAMESPACE
33
34class QPolygonF;
35class QVectorPathConverter;
36
37class QVectorPathConverter
38{
39public:
40 QVectorPathConverter(const QList<QPainterPath::Element> &path, uint fillRule, bool convex)
41 : pathData(path, fillRule, convex),
42 path(pathData.points.data(), path.size(), pathData.elements.data(), pathData.flags)
43 {
44 }
45
46 const QVectorPath &vectorPath() {
47 return path;
48 }
49
50 struct QVectorPathData {
51 QVectorPathData(const QList<QPainterPath::Element> &path, uint fillRule, bool convex)
52 : elements(path.size()), points(path.size() * 2), flags(0)
53 {
54 int ptsPos = 0;
55 bool isLines = true;
56 for (int i=0; i<path.size(); ++i) {
57 const QPainterPath::Element &e = path.at(i);
58 elements[i] = e.type;
59 points[ptsPos++] = e.x;
60 points[ptsPos++] = e.y;
61 if (e.type == QPainterPath::CurveToElement)
62 flags |= QVectorPath::CurvedShapeMask;
63
64 // This is to check if the path contains only alternating lineTo/moveTo,
65 // in which case we can set the LinesHint in the path. MoveTo is 0 and
66 // LineTo is 1 so the i%2 gets us what we want cheaply.
67 isLines = isLines && e.type == (QPainterPath::ElementType) (i%2);
68 }
69
70 if (fillRule == Qt::WindingFill)
71 flags |= QVectorPath::WindingFill;
72 else
73 flags |= QVectorPath::OddEvenFill;
74
75 if (isLines)
76 flags |= QVectorPath::LinesShapeMask;
77 else {
78 flags |= QVectorPath::AreaShapeMask;
79 if (!convex)
80 flags |= QVectorPath::NonConvexShapeMask;
81 }
82
83 }
84 QVarLengthArray<QPainterPath::ElementType> elements;
85 QVarLengthArray<qreal> points;
86 uint flags;
87 };
88
89 QVectorPathData pathData;
90 QVectorPath path;
91
92private:
93 Q_DISABLE_COPY_MOVE(QVectorPathConverter)
94};
95
96class QPainterPathPrivate : public QSharedData
97{
98public:
99 friend class QPainterPath;
100 friend class QPainterPathStroker;
101 friend class QPainterPathStrokerPrivate;
102 friend class QTransform;
103 friend class QVectorPath;
104 friend struct QPainterPathPrivateDeleter;
105#ifndef QT_NO_DATASTREAM
106 friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPainterPath &);
107 friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPainterPath &);
108#endif
109
110 QPainterPathPrivate() noexcept
111 : QSharedData(),
112 cStart(0),
113 fillRule(Qt::OddEvenFill),
114 require_moveTo(false),
115 dirtyBounds(false),
116 dirtyControlBounds(false),
117 convex(false),
118 pathConverter(nullptr)
119 {
120 }
121
122 QPainterPathPrivate(const QPainterPathPrivate &other) noexcept
123 : QSharedData(other),
124 elements(other.elements),
125 cStart(other.cStart),
126 fillRule(other.fillRule),
127 bounds(other.bounds),
128 controlBounds(other.controlBounds),
129 require_moveTo(false),
130 dirtyBounds(other.dirtyBounds),
131 dirtyControlBounds(other.dirtyControlBounds),
132 convex(other.convex),
133 pathConverter(nullptr)
134 {
135 }
136
137 QPainterPathPrivate &operator=(const QPainterPathPrivate &) = delete;
138 ~QPainterPathPrivate() = default;
139
140 inline bool isClosed() const;
141 inline void close();
142 inline void maybeMoveTo();
143 inline void clear();
144
145 const QVectorPath &vectorPath() {
146 if (!pathConverter)
147 pathConverter.reset(p: new QVectorPathConverter(elements, fillRule, convex));
148 return pathConverter->path;
149 }
150
151private:
152 QList<QPainterPath::Element> elements;
153
154 int cStart;
155 Qt::FillRule fillRule;
156
157 QRectF bounds;
158 QRectF controlBounds;
159
160 uint require_moveTo : 1;
161 uint dirtyBounds : 1;
162 uint dirtyControlBounds : 1;
163 uint convex : 1;
164
165 std::unique_ptr<QVectorPathConverter> pathConverter;
166};
167
168class QPainterPathStrokerPrivate
169{
170public:
171 QPainterPathStrokerPrivate();
172
173 QStroker stroker;
174 QList<qfixed> dashPattern;
175 qreal dashOffset;
176};
177
178inline const QPainterPath QVectorPath::convertToPainterPath() const
179{
180 QPainterPath path;
181 path.ensureData();
182 QPainterPathPrivate *data = path.d_func();
183 data->elements.reserve(asize: m_count);
184 int index = 0;
185 data->elements[0].x = m_points[index++];
186 data->elements[0].y = m_points[index++];
187
188 if (m_elements) {
189 data->elements[0].type = m_elements[0];
190 for (int i=1; i<m_count; ++i) {
191 QPainterPath::Element element;
192 element.x = m_points[index++];
193 element.y = m_points[index++];
194 element.type = m_elements[i];
195 data->elements << element;
196 }
197 } else {
198 data->elements[0].type = QPainterPath::MoveToElement;
199 for (int i=1; i<m_count; ++i) {
200 QPainterPath::Element element;
201 element.x = m_points[index++];
202 element.y = m_points[index++];
203 element.type = QPainterPath::LineToElement;
204 data->elements << element;
205 }
206 }
207
208 if (m_hints & OddEvenFill)
209 data->fillRule = Qt::OddEvenFill;
210 else
211 data->fillRule = Qt::WindingFill;
212 return path;
213}
214
215void Q_GUI_EXPORT qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
216 QPointF* startPoint, QPointF *endPoint);
217
218inline bool QPainterPathPrivate::isClosed() const
219{
220 const QPainterPath::Element &first = elements.at(i: cStart);
221 const QPainterPath::Element &last = elements.last();
222 return first.x == last.x && first.y == last.y;
223}
224
225inline void QPainterPathPrivate::close()
226{
227 Q_ASSERT(ref.loadRelaxed() == 1);
228 require_moveTo = true;
229 const QPainterPath::Element &first = elements.at(i: cStart);
230 QPainterPath::Element &last = elements.last();
231 if (first.x != last.x || first.y != last.y) {
232 if (qFuzzyCompare(p1: first.x, p2: last.x) && qFuzzyCompare(p1: first.y, p2: last.y)) {
233 last.x = first.x;
234 last.y = first.y;
235 } else {
236 QPainterPath::Element e = { .x: first.x, .y: first.y, .type: QPainterPath::LineToElement };
237 elements << e;
238 }
239 }
240}
241
242inline void QPainterPathPrivate::maybeMoveTo()
243{
244 if (require_moveTo) {
245 QPainterPath::Element e = elements.last();
246 e.type = QPainterPath::MoveToElement;
247 elements.append(t: e);
248 require_moveTo = false;
249 }
250}
251
252inline void QPainterPathPrivate::clear()
253{
254 Q_ASSERT(ref.loadRelaxed() == 1);
255
256 elements.clear();
257
258 cStart = 0;
259 bounds = {};
260 controlBounds = {};
261
262 require_moveTo = false;
263 dirtyBounds = false;
264 dirtyControlBounds = false;
265 convex = false;
266
267 pathConverter.reset();
268}
269#define KAPPA qreal(0.5522847498)
270
271
272QT_END_NAMESPACE
273
274#endif // QPAINTERPATH_P_H
275

source code of qtbase/src/gui/painting/qpainterpath_p.h