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(QPointF startPoint)
123 : QSharedData(),
124 elements{ { .x: startPoint.x(), .y: startPoint.y(), .type: QPainterPath::MoveToElement } },
125 cStart(0),
126 fillRule(Qt::OddEvenFill),
127 bounds(startPoint, QSizeF(0, 0)),
128 controlBounds(startPoint, QSizeF(0, 0)),
129 require_moveTo(false),
130 dirtyBounds(false),
131 dirtyControlBounds(false),
132 convex(false),
133 pathConverter(nullptr)
134 {
135 }
136
137 QPainterPathPrivate(const QPainterPathPrivate &other) noexcept
138 : QSharedData(other),
139 elements(other.elements),
140 cStart(other.cStart),
141 fillRule(other.fillRule),
142 bounds(other.bounds),
143 controlBounds(other.controlBounds),
144 require_moveTo(false),
145 dirtyBounds(other.dirtyBounds),
146 dirtyControlBounds(other.dirtyControlBounds),
147 convex(other.convex),
148 pathConverter(nullptr)
149 {
150 }
151
152 QPainterPathPrivate &operator=(const QPainterPathPrivate &) = delete;
153 ~QPainterPathPrivate() = default;
154
155 inline bool isClosed() const;
156 inline void close();
157 inline void maybeMoveTo();
158 inline void clear();
159
160 const QVectorPath &vectorPath() {
161 if (!pathConverter)
162 pathConverter.reset(p: new QVectorPathConverter(elements, fillRule, convex));
163 return pathConverter->path;
164 }
165
166private:
167 QList<QPainterPath::Element> elements;
168
169 int cStart;
170 Qt::FillRule fillRule;
171
172 QRectF bounds;
173 QRectF controlBounds;
174
175 uint require_moveTo : 1;
176 uint dirtyBounds : 1;
177 uint dirtyControlBounds : 1;
178 uint convex : 1;
179
180 std::unique_ptr<QVectorPathConverter> pathConverter;
181};
182
183class QPainterPathStrokerPrivate
184{
185public:
186 QPainterPathStrokerPrivate();
187
188 QStroker stroker;
189 QList<qfixed> dashPattern;
190 qreal dashOffset;
191};
192
193inline const QPainterPath QVectorPath::convertToPainterPath() const
194{
195 QPainterPath path;
196 path.ensureData();
197 QPainterPathPrivate *data = path.d_func();
198 data->elements.reserve(asize: m_count);
199 int index = 0;
200 data->elements[0].x = m_points[index++];
201 data->elements[0].y = m_points[index++];
202
203 if (m_elements) {
204 data->elements[0].type = m_elements[0];
205 for (int i=1; i<m_count; ++i) {
206 QPainterPath::Element element;
207 element.x = m_points[index++];
208 element.y = m_points[index++];
209 element.type = m_elements[i];
210 data->elements << element;
211 }
212 } else {
213 data->elements[0].type = QPainterPath::MoveToElement;
214 for (int i=1; i<m_count; ++i) {
215 QPainterPath::Element element;
216 element.x = m_points[index++];
217 element.y = m_points[index++];
218 element.type = QPainterPath::LineToElement;
219 data->elements << element;
220 }
221 }
222
223 if (m_hints & OddEvenFill)
224 data->fillRule = Qt::OddEvenFill;
225 else
226 data->fillRule = Qt::WindingFill;
227 return path;
228}
229
230void Q_GUI_EXPORT qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
231 QPointF* startPoint, QPointF *endPoint);
232
233inline bool QPainterPathPrivate::isClosed() const
234{
235 const QPainterPath::Element &first = elements.at(i: cStart);
236 const QPainterPath::Element &last = elements.last();
237 return first.x == last.x && first.y == last.y;
238}
239
240inline void QPainterPathPrivate::close()
241{
242 Q_ASSERT(ref.loadRelaxed() == 1);
243 require_moveTo = true;
244 const QPainterPath::Element &first = elements.at(i: cStart);
245 QPainterPath::Element &last = elements.last();
246 if (first.x != last.x || first.y != last.y) {
247 if (qFuzzyCompare(p1: first.x, p2: last.x) && qFuzzyCompare(p1: first.y, p2: last.y)) {
248 last.x = first.x;
249 last.y = first.y;
250 } else {
251 QPainterPath::Element e = { .x: first.x, .y: first.y, .type: QPainterPath::LineToElement };
252 elements << e;
253 }
254 }
255}
256
257inline void QPainterPathPrivate::maybeMoveTo()
258{
259 if (require_moveTo) {
260 QPainterPath::Element e = elements.last();
261 e.type = QPainterPath::MoveToElement;
262 elements.append(t: e);
263 require_moveTo = false;
264 }
265}
266
267inline void QPainterPathPrivate::clear()
268{
269 Q_ASSERT(ref.loadRelaxed() == 1);
270
271 elements.clear();
272
273 cStart = 0;
274 bounds = {};
275 controlBounds = {};
276
277 require_moveTo = false;
278 dirtyBounds = false;
279 dirtyControlBounds = false;
280 convex = false;
281
282 pathConverter.reset();
283}
284#define KAPPA qreal(0.5522847498)
285
286
287QT_END_NAMESPACE
288
289#endif // QPAINTERPATH_P_H
290

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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