Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qoutlinemapper.cpp
Go to the documentation of this file.
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#include "qoutlinemapper_p.h"
5
6#include "qbezier_p.h"
7#include "qmath.h"
8#include "qpainterpath_p.h"
10
11#include <stdlib.h>
12
14
15#define qreal_to_fixed_26_6(f) (qRound(f * 64))
16
17
18
19
20static const QRectF boundingRect(const QPointF *points, int pointCount)
21{
22 const QPointF *e = points;
23 const QPointF *last = points + pointCount;
24 qreal minx, maxx, miny, maxy;
25 minx = maxx = e->x();
26 miny = maxy = e->y();
27 while (++e < last) {
28 if (e->x() < minx)
29 minx = e->x();
30 else if (e->x() > maxx)
31 maxx = e->x();
32 if (e->y() < miny)
33 miny = e->y();
34 else if (e->y() > maxy)
35 maxy = e->y();
36 }
37 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
38}
39
41{
42 auto limitCoords = [](QRect r) {
45 r &= limitRect;
46 r.setWidth(qMin(r.width(), QT_RASTER_COORD_LIMIT));
47 r.setHeight(qMin(r.height(), QT_RASTER_COORD_LIMIT));
48 return r;
49 };
50
51 if (clipRect != m_clip_rect) {
52 m_clip_rect = limitCoords(clipRect);
53 const int mw = 1 << 10; // margin width. No need to trigger clipping for slight overshooting
54 m_clip_trigger_rect = QRectF(limitCoords(m_clip_rect.adjusted(-mw, -mw, mw, mw)));
55 }
56}
57
58void QOutlineMapper::curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep) {
59#ifdef QT_DEBUG_CONVERT
60 printf("QOutlineMapper::curveTo() (%f, %f)\n", ep.x(), ep.y());
61#endif
62
63 if (!m_elements.size())
64 return;
65 QBezier bezier = QBezier::fromPoints(m_elements.last(), cp1, cp2, ep);
66
67 bool outsideClip = false;
68 // Test one point first before doing a full intersection test.
70 QRectF potentialCurveArea = m_transform.mapRect(bezier.bounds());
71 outsideClip = !potentialCurveArea.intersects(m_clip_rect);
72 }
73 if (outsideClip) {
74 // The curve is entirely outside the clip rect, so just
75 // approximate it with a line that closes the path.
76 lineTo(ep);
77 } else {
80 for (int i = m_elements.size() - m_element_types.size(); i; --i)
82 }
84}
85
86
88{
89 Q_ASSERT(!path.isEmpty());
90 int elmCount = path.elementCount();
91#ifdef QT_DEBUG_CONVERT
92 printf("QOutlineMapper::convertPath(), size=%d\n", elmCount);
93#endif
94 beginOutline(path.fillRule());
95
96 for (int index=0; index<elmCount; ++index) {
97 const QPainterPath::Element &elm = path.elementAt(index);
98
99 switch (elm.type) {
100
102 if (index == elmCount - 1)
103 continue;
104 moveTo(elm);
105 break;
106
108 lineTo(elm);
109 break;
110
112 curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
113 index += 2;
114 break;
115
116 default:
117 break; // This will never hit..
118 }
119 }
120
121 endOutline();
122 return outline();
123}
124
126{
127 int count = path.elementCount();
128
129#ifdef QT_DEBUG_CONVERT
130 printf("QOutlineMapper::convertPath(VP), size=%d\n", count);
131#endif
132 beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);
133
134 if (path.elements()) {
135 // TODO: if we do closing of subpaths in convertElements instead we
136 // could avoid this loop
137 const QPainterPath::ElementType *elements = path.elements();
138 const QPointF *points = reinterpret_cast<const QPointF *>(path.points());
139
140 for (int index = 0; index < count; ++index) {
141 switch (elements[index]) {
143 if (index == count - 1)
144 continue;
146 break;
147
150 break;
151
154 index += 2;
155 break;
156
157 default:
158 break; // This will never hit..
159 }
160 }
161
162 } else {
163 // ### We can kill this copying and just use the buffer straight...
164
166 if (count)
167 memcpy(static_cast<void *>(m_elements.data()), static_cast<const void *>(path.points()), count* sizeof(QPointF));
168
170 }
171
172 endOutline();
173 return outline();
174}
175
176
178{
179 closeSubpath();
180
181 if (m_elements.isEmpty()) {
182 memset(&m_outline, 0, sizeof(m_outline));
183 return;
184 }
185
187
188 // Transform the outline
189 if (m_transform.isIdentity()) {
190 // Nothing to do
191 } else if (m_transform.type() < QTransform::TxProject) {
192 for (int i = 0; i < m_elements.size(); ++i)
194 } else {
196 m_element_types.size() ? m_element_types.data() : nullptr);
197 QPainterPath path = vp.convertToPainterPath();
200 path.setFillRule(Qt::WindingFill);
201 if (path.isEmpty()) {
202 m_valid = false;
203 } else {
204 QTransform oldTransform = m_transform;
207 m_transform = oldTransform;
208 }
209 return;
210 }
211
213
214#ifdef QT_DEBUG_CONVERT
215 printf(" - control point rect (%.2f, %.2f) %.2f x %.2f, clip=(%d,%d, %dx%d)\n",
219#endif
220
221 // Avoid rasterizing outside cliprect: faster, and ensures coords < QT_RASTER_COORD_LIMIT
224 } else {
226 }
227}
228
231 int element_count)
232{
233
234 if (types) {
235 // Translate into FT coords
236 const QPointF *e = elements;
237 for (int i=0; i<element_count; ++i) {
238 switch (*types) {
240 {
241 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
242 qreal_to_fixed_26_6(e->y()) };
243 if (i != 0)
244 m_contours << m_points.size() - 1;
245 m_points << pt_fixed;
247 }
248 break;
249
251 {
252 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
253 qreal_to_fixed_26_6(e->y()) };
254 m_points << pt_fixed;
256 }
257 break;
258
260 {
261 QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(e->x()),
262 qreal_to_fixed_26_6(e->y()) };
263 ++e;
264 QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6((e)->x()),
265 qreal_to_fixed_26_6((e)->y()) };
266 ++e;
267 QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6((e)->x()),
268 qreal_to_fixed_26_6((e)->y()) };
269
270 m_points << cp1_fixed << cp2_fixed << ep_fixed;
274
275 types += 2;
276 i += 2;
277 }
278 break;
279 default:
280 break;
281 }
282 ++types;
283 ++e;
284 }
285 } else {
286 // Plain polygon...
287 const QPointF *last = elements + element_count;
288 const QPointF *e = elements;
289 while (e < last) {
290 QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(e->x()),
291 qreal_to_fixed_26_6(e->y()) };
292 m_points << pt_fixed;
294 ++e;
295 }
296 }
297
298 // close the very last subpath
299 m_contours << m_points.size() - 1;
300
302 m_outline.n_points = m_points.size();
303
304 m_outline.points = m_points.data();
307
308#ifdef QT_DEBUG_CONVERT
309 printf("QOutlineMapper::endOutline\n");
310
311 printf(" - contours: %d\n", m_outline.n_contours);
312 for (int i=0; i<m_outline.n_contours; ++i) {
313 printf(" - %d\n", m_outline.contours[i]);
314 }
315
316 printf(" - points: %d\n", m_outline.n_points);
317 for (int i=0; i<m_outline.n_points; ++i) {
318 printf(" - %d -- %.2f, %.2f, (%d, %d)\n", i,
319 (double) (m_outline.points[i].x / 64.0),
320 (double) (m_outline.points[i].y / 64.0),
321 (int) m_outline.points[i].x, (int) m_outline.points[i].y);
322 }
323#endif
324}
325
328 int element_count)
329{
330 // We could save a bit of time by actually implementing them fully
331 // instead of going through convenience functionality, but since
332 // this part of code hardly every used, it shouldn't matter.
333
334 QScopedValueRollback<bool> in_clip_elements(m_in_clip_elements, true);
335
337
339 path.setFillRule(Qt::WindingFill);
340
341 if (types) {
342 for (int i=0; i<element_count; ++i) {
343 switch (types[i]) {
345 path.moveTo(elements[i]);
346 break;
347
349 path.lineTo(elements[i]);
350 break;
351
353 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
354 i += 2;
355 break;
356 default:
357 break;
358 }
359 }
360 } else {
361 path.moveTo(elements[0]);
362 for (int i=1; i<element_count; ++i)
363 path.lineTo(elements[i]);
364 }
365
366 QPainterPath clipPath;
367 clipPath.addRect(m_clip_rect);
368 QPainterPath clippedPath = path.intersected(clipPath);
369 if (clippedPath.isEmpty()) {
370 m_valid = false;
371 } else {
372 QTransform oldTransform = m_transform;
374 convertPath(clippedPath);
375 m_transform = oldTransform;
376 }
377}
378
QRectF bounds() const
Definition qbezier.cpp:137
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:33
void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold=0.5) const
Definition qbezier.cpp:65
void resize(qsizetype size)
qsizetype size() const
Type & last()
bool isEmpty() const
void reserve(qsizetype size)
Type * data() const
QTransform m_transform
QT_FT_Outline * outline()
void clipElements(const QPointF *points, const QPainterPath::ElementType *types, int count)
QDataBuffer< QT_FT_Vector > m_points
void convertElements(const QPointF *points, const QPainterPath::ElementType *types, int count)
void moveTo(const QPointF &pt)
void curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep)
void setClipRect(QRect clipRect)
QDataBuffer< QPointF > m_elements
QPainterPath::ElementType * elementTypes() const
QDataBuffer< char > m_tags
QDataBuffer< int > m_contours
QDataBuffer< QPainterPath::ElementType > m_element_types
QT_FT_Outline m_outline
QT_FT_Outline * convertPath(const QPainterPath &path)
void beginOutline(Qt::FillRule fillRule)
void lineTo(const QPointF &pt)
\inmodule QtGui
\inmodule QtGui
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
QPainterPath intersected(const QPainterPath &r) const
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
bool contains(const QRectF &r) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:1993
\inmodule QtCore\reentrant
Definition qrect.h:30
bool intersects(const QRect &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e., there is at least one pixel...
Definition qrect.cpp:1069
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QPoint map(const QPoint &p) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void reset()
Resets the matrix to an identity matrix, i.e.
TransformationType type() const
Returns the transformation type of this matrix.
QRect mapRect(const QRect &) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool isIdentity() const
Returns true if the matrix is the identity matrix, otherwise returns false.
Definition qtransform.h:169
Combined button and popup list for selecting options.
@ WindingFill
@ OddEvenFill
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLint GLint GLint GLint GLint x
[0]
GLuint index
[2]
GLboolean r
[2]
GLsizei GLenum GLenum * types
GLenum GLenum GLsizei count
GLint y
GLfixed GLfixed GLint GLint GLfixed points
GLsizei const GLchar *const * path
#define qreal_to_fixed_26_6(f)
static const QRectF boundingRect(const QPointF *points, int pointCount)
QT_BEGIN_NAMESPACE constexpr int QT_RASTER_COORD_LIMIT
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QT_FT_OUTLINE_EVEN_ODD_FILL
#define QT_FT_CURVE_TAG_ON
#define QT_FT_CURVE_TAG_CUBIC
static const QTextHtmlElement elements[Html_NumElements]
double qreal
Definition qtypes.h:187
QT_FT_Vector * points