21static const QRectF boundingRect(
const QPointF *points,
int pointCount)
23 const QPointF *e = points;
24 const QPointF *last = points + pointCount;
25 qreal minx, maxx, miny, maxy;
31 else if (e->x() > maxx)
35 else if (e->y() > maxy)
38 return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
43 auto limitCoords = [](QRect r) {
52 if (clipRect != m_clip_rect) {
53 m_clip_rect = limitCoords(clipRect);
54 const int mw = 1 << 10;
55 m_clip_trigger_rect = QRectF(limitCoords(m_clip_rect.adjusted(-mw, -mw, mw, mw)));
60#ifdef QT_DEBUG_CONVERT
61 printf(
"QOutlineMapper::curveTo() (%f, %f)\n", ep.x(), ep.y());
64 if (!m_elements.size())
66 QBezier bezier = QBezier::fromPoints(m_elements.last(), cp1, cp2, ep);
68 bool outsideClip =
false;
70 if (!QRectF(m_clip_rect).contains(m_transform.map(ep))) {
71 QRectF potentialCurveArea = m_transform.mapRect(bezier.bounds());
72 outsideClip = !potentialCurveArea.intersects(m_clip_rect);
79 bezier.addToPolygon(m_elements, m_curve_threshold);
80 m_element_types.reserve(m_elements.size());
81 for (
int i = m_elements.size() - m_element_types.size(); i; --i)
82 m_element_types << QPainterPath::LineToElement;
84 Q_ASSERT(m_elements.size() == m_element_types.size());
90 Q_ASSERT(!path.isEmpty());
91 int elmCount = path.elementCount();
92#ifdef QT_DEBUG_CONVERT
93 printf(
"QOutlineMapper::convertPath(), size=%d\n", elmCount);
95 beginOutline(path.fillRule());
97 for (
int index=0; index<elmCount; ++index) {
98 const QPainterPath::Element &elm = path.elementAt(index);
102 case QPainterPath::MoveToElement:
103 if (index == elmCount - 1)
108 case QPainterPath::LineToElement:
112 case QPainterPath::CurveToElement:
113 curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
128 int count = path.elementCount();
130#ifdef QT_DEBUG_CONVERT
131 printf(
"QOutlineMapper::convertPath(VP), size=%d\n", count);
133 beginOutline(path.hasWindingFill() ? Qt::WindingFill : Qt::OddEvenFill);
135 if (path.elements()) {
138 const QPainterPath::ElementType *elements = path.elements();
139 const QPointF *points =
reinterpret_cast<
const QPointF *>(path.points());
141 for (
int index = 0; index < count; ++index) {
142 switch (elements[index]) {
143 case QPainterPath::MoveToElement:
144 if (index == count - 1)
146 moveTo(points[index]);
149 case QPainterPath::LineToElement:
150 lineTo(points[index]);
153 case QPainterPath::CurveToElement:
154 curveTo(points[index], points[index+1], points[index+2]);
166 m_elements.resize(count);
168 memcpy(
static_cast<
void *>(m_elements.data()),
static_cast<
const void *>(path.points()), count*
sizeof(QPointF));
170 m_element_types.resize(0);
182 if (m_elements.isEmpty()) {
183 memset(&m_outline, 0,
sizeof(m_outline));
187 QPointF *elements = m_elements.data();
190 if (m_transform.isIdentity()) {
192 }
else if (m_transform.type() < QTransform::TxProject) {
193 for (
int i = 0; i < m_elements.size(); ++i)
194 elements[i] = m_transform.map(elements[i]);
196 const QVectorPath vp((qreal *)elements, m_elements.size(),
197 m_element_types.size() ? m_element_types.data() :
nullptr);
198 QPainterPath path = vp.convertToPainterPath();
199 path = m_transform.map(path);
200 if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
201 path.setFillRule(Qt::WindingFill);
202 if (path.isEmpty()) {
205 QTransform oldTransform = m_transform;
208 m_transform = oldTransform;
213 controlPointRect = boundingRect(elements, m_elements.size());
215#ifdef QT_DEBUG_CONVERT
216 printf(
" - control point rect (%.2f, %.2f) %.2f x %.2f, clip=(%d,%d, %dx%d)\n",
217 controlPointRect.x(), controlPointRect.y(),
218 controlPointRect.width(), controlPointRect.height(),
219 m_clip_rect.x(), m_clip_rect.y(), m_clip_rect.width(), m_clip_rect.height());
223 if (!m_in_clip_elements && !m_clip_trigger_rect.contains(controlPointRect)) {
224 clipElements(elements, elementTypes(), m_elements.size());
226 convertElements(elements, elementTypes(), m_elements.size());
231 const QPainterPath::ElementType *types,
237 const QPointF *e = elements;
238 for (
int i=0; i<element_count; ++i) {
240 case QPainterPath::MoveToElement:
245 m_contours << m_points.size() - 1;
246 m_points << pt_fixed;
247 m_tags << QT_FT_CURVE_TAG_ON;
251 case QPainterPath::LineToElement:
255 m_points << pt_fixed;
256 m_tags << QT_FT_CURVE_TAG_ON;
260 case QPainterPath::CurveToElement:
271 m_points << cp1_fixed << cp2_fixed << ep_fixed;
272 m_tags << QT_FT_CURVE_TAG_CUBIC
273 << QT_FT_CURVE_TAG_CUBIC
274 << QT_FT_CURVE_TAG_ON;
288 const QPointF *last = elements + element_count;
289 const QPointF *e = elements;
293 m_points << pt_fixed;
294 m_tags << QT_FT_CURVE_TAG_ON;
300 m_contours << m_points.size() - 1;
302 m_outline.n_contours = m_contours.size();
303 m_outline.n_points = m_points.size();
305 m_outline.points = m_points.data();
306 m_outline.tags = m_tags.data();
307 m_outline.contours = m_contours.data();
309#ifdef QT_DEBUG_CONVERT
310 printf(
"QOutlineMapper::endOutline\n");
312 printf(
" - contours: %d\n", m_outline.n_contours);
313 for (
int i=0; i<m_outline.n_contours; ++i) {
314 printf(
" - %d\n", m_outline.contours[i]);
317 printf(
" - points: %d\n", m_outline.n_points);
318 for (
int i=0; i<m_outline.n_points; ++i) {
319 printf(
" - %d -- %.2f, %.2f, (%d, %d)\n", i,
320 (
double) (m_outline.points[i].x / 64.0),
321 (
double) (m_outline.points[i].y / 64.0),
322 (
int) m_outline.points[i].x, (
int) m_outline.points[i].y);
328 const QPainterPath::ElementType *types,
335 QScopedValueRollback<
bool> in_clip_elements(m_in_clip_elements,
true);
339 if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
340 path.setFillRule(Qt::WindingFill);
343 for (
int i=0; i<element_count; ++i) {
345 case QPainterPath::MoveToElement:
346 path.moveTo(elements[i]);
349 case QPainterPath::LineToElement:
350 path.lineTo(elements[i]);
353 case QPainterPath::CurveToElement:
354 path.cubicTo(elements[i], elements[i+1], elements[i+2]);
362 path.moveTo(elements[0]);
363 for (
int i=1; i<element_count; ++i)
364 path.lineTo(elements[i]);
367 QPainterPath clipPath;
368 clipPath.addRect(m_clip_rect);
369 QPainterPath clippedPath = path.intersected(clipPath);
370 if (clippedPath.isEmpty()) {
373 QTransform oldTransform = m_transform;
375 convertPath(clippedPath);
376 m_transform = oldTransform;