Coverage Report

Created: 2025-07-23 06:48

/src/qt/qtbase/src/gui/painting/qpaintengineex.cpp
Line
Count
Source (jump to first uncovered line)
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 "qpaintengineex_p.h"
5
#include "qpainter_p.h"
6
#include "qstroker_p.h"
7
#include "qbezier_p.h"
8
#include <private/qpainterpath_p.h>
9
#include <private/qfontengine_p.h>
10
#include <private/qstatictext_p.h>
11
12
#include <qvarlengtharray.h>
13
#include <qdebug.h>
14
15
16
QT_BEGIN_NAMESPACE
17
18
#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
19
0
#  define QT_MAX_CACHED_GLYPH_SIZE 64
20
#endif
21
22
/*******************************************************************************
23
 *
24
 * class QVectorPath
25
 *
26
 */
27
QVectorPath::~QVectorPath()
28
195k
{
29
195k
    if (m_hints & ShouldUseCacheHint) {
30
0
        CacheEntry *e = m_cache;
31
0
        while (e) {
32
0
            if (e->data)
33
0
                e->cleanup(e->engine, e->data);
34
0
            CacheEntry *n = e->next;
35
0
            delete e;
36
0
            e = n;
37
0
        }
38
0
    }
39
195k
}
40
41
42
QRectF QVectorPath::controlPointRect() const
43
182k
{
44
182k
    if (m_hints & ControlPointRect)
45
51.6k
        return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
46
47
131k
    if (m_count == 0) {
48
0
        m_cp_rect.x1 = m_cp_rect.x2 = m_cp_rect.y1 = m_cp_rect.y2 = 0;
49
0
        m_hints |= ControlPointRect;
50
0
        return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
51
0
    }
52
131k
    Q_ASSERT(m_points && m_count > 0);
53
54
131k
    const qreal *pts = m_points;
55
131k
    m_cp_rect.x1 = m_cp_rect.x2 = *pts;
56
131k
    ++pts;
57
131k
    m_cp_rect.y1 = m_cp_rect.y2 = *pts;
58
131k
    ++pts;
59
60
131k
    const qreal *epts = m_points + (m_count << 1);
61
39.8M
    while (pts < epts) {
62
39.7M
        qreal x = *pts;
63
39.7M
        if (x < m_cp_rect.x1) m_cp_rect.x1 = x;
64
38.5M
        else if (x > m_cp_rect.x2) m_cp_rect.x2 = x;
65
39.7M
        ++pts;
66
67
39.7M
        qreal y = *pts;
68
39.7M
        if (y < m_cp_rect.y1) m_cp_rect.y1 = y;
69
39.1M
        else if (y > m_cp_rect.y2) m_cp_rect.y2 = y;
70
39.7M
        ++pts;
71
39.7M
    }
72
73
131k
    m_hints |= ControlPointRect;
74
131k
    return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2));
75
131k
}
76
77
78
QVectorPath::CacheEntry *QVectorPath::addCacheData(QPaintEngineEx *engine, void *data,
79
0
                                                   qvectorpath_cache_cleanup cleanup) const{
80
0
    Q_ASSERT(!lookupCacheData(engine));
81
0
    if ((m_hints & IsCachedHint) == 0) {
82
0
        m_cache = nullptr;
83
0
        m_hints |= IsCachedHint;
84
0
    }
85
0
    CacheEntry *e = new CacheEntry;
86
0
    e->engine = engine;
87
0
    e->data = data;
88
0
    e->cleanup = cleanup;
89
0
    e->next = m_cache;
90
0
    m_cache = e;
91
0
    return m_cache;
92
0
}
93
94
95
const QVectorPath &qtVectorPathForPath(const QPainterPath &path)
96
195k
{
97
195k
    Q_ASSERT(path.d_func());
98
195k
    return path.d_func()->vectorPath();
99
195k
}
100
101
#ifndef QT_NO_DEBUG_STREAM
102
QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path)
103
0
{
104
0
    QDebugStateSaver saver(s);
105
0
    QRectF rf = path.controlPointRect();
106
0
    s << "QVectorPath(size:" << path.elementCount()
107
0
      << " hints:" << Qt::hex << path.hints()
108
0
      << rf << ')';
109
0
    return s;
110
0
}
111
#endif
112
113
/*******************************************************************************
114
 *
115
 * class QPaintEngineExPrivate:
116
 *
117
 */
118
119
120
struct StrokeHandler {
121
102
    StrokeHandler(int reserve) : pts(reserve), types(reserve) {}
122
    QDataBuffer<qreal> pts;
123
    QDataBuffer<QPainterPath::ElementType> types;
124
};
125
126
127
QPaintEngineExPrivate::QPaintEngineExPrivate()
128
46.1k
    : dasher(&stroker),
129
46.1k
      strokeHandler(nullptr),
130
46.1k
      activeStroker(nullptr),
131
46.1k
      strokerPen(Qt::NoPen)
132
46.1k
{
133
46.1k
}
134
135
136
QPaintEngineExPrivate::~QPaintEngineExPrivate()
137
46.1k
{
138
46.1k
    delete strokeHandler;
139
46.1k
}
140
141
142
void QPaintEngineExPrivate::replayClipOperations()
143
45.9k
{
144
45.9k
    Q_Q(QPaintEngineEx);
145
146
45.9k
    QPainter *p = q->painter();
147
45.9k
    if (!p || !p->d_ptr)
148
0
        return;
149
150
45.9k
    const QList<QPainterClipInfo> &clipInfo = p->d_ptr->state->clipInfo;
151
152
45.9k
    QTransform transform = q->state()->matrix;
153
154
45.9k
    for (const QPainterClipInfo &info : clipInfo) {
155
156
0
        if (info.matrix != q->state()->matrix) {
157
0
            q->state()->matrix = info.matrix;
158
0
            q->transformChanged();
159
0
        }
160
161
0
        switch (info.clipType) {
162
0
        case QPainterClipInfo::RegionClip:
163
0
            q->clip(info.region, info.operation);
164
0
            break;
165
0
        case QPainterClipInfo::PathClip:
166
0
            q->clip(info.path, info.operation);
167
0
            break;
168
0
        case QPainterClipInfo::RectClip:
169
0
            q->clip(info.rect, info.operation);
170
0
            break;
171
0
        case QPainterClipInfo::RectFClip: {
172
0
            qreal right = info.rectf.x() + info.rectf.width();
173
0
            qreal bottom = info.rectf.y() + info.rectf.height();
174
0
            qreal pts[] = { info.rectf.x(), info.rectf.y(),
175
0
                            right, info.rectf.y(),
176
0
                            right, bottom,
177
0
                            info.rectf.x(), bottom };
178
0
            QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
179
0
            q->clip(vp, info.operation);
180
0
            break;
181
0
            }
182
0
        }
183
0
    }
184
185
45.9k
    if (transform != q->state()->matrix) {
186
0
        q->state()->matrix = transform;
187
0
        q->transformChanged();
188
0
    }
189
45.9k
}
190
191
192
bool QPaintEngineExPrivate::hasClipOperations() const
193
0
{
194
0
    Q_Q(const QPaintEngineEx);
195
196
0
    QPainter *p = q->painter();
197
0
    if (!p || !p->d_ptr)
198
0
        return false;
199
200
0
    return !p->d_ptr->state->clipInfo.isEmpty();
201
0
}
202
203
/*******************************************************************************
204
 *
205
 * class QPaintEngineEx:
206
 *
207
 */
208
209
static const QPainterPath::ElementType qpaintengineex_ellipse_types[] = {
210
    QPainterPath::MoveToElement,
211
    QPainterPath::CurveToElement,
212
    QPainterPath::CurveToDataElement,
213
    QPainterPath::CurveToDataElement,
214
215
    QPainterPath::CurveToElement,
216
    QPainterPath::CurveToDataElement,
217
    QPainterPath::CurveToDataElement,
218
219
    QPainterPath::CurveToElement,
220
    QPainterPath::CurveToDataElement,
221
    QPainterPath::CurveToDataElement,
222
223
    QPainterPath::CurveToElement,
224
    QPainterPath::CurveToDataElement,
225
    QPainterPath::CurveToDataElement
226
};
227
228
static const QPainterPath::ElementType qpaintengineex_line_types_16[] = {
229
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
230
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
231
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
232
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
233
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
234
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
235
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
236
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
237
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
238
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
239
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
240
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
241
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
242
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
243
    QPainterPath::MoveToElement, QPainterPath::LineToElement,
244
    QPainterPath::MoveToElement, QPainterPath::LineToElement
245
};
246
247
static const QPainterPath::ElementType qpaintengineex_rect4_types_32[] = {
248
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 1
249
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 2
250
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 3
251
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 4
252
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 5
253
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 6
254
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 7
255
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 8
256
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 9
257
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 10
258
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 11
259
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 12
260
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 13
261
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 14
262
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 15
263
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 16
264
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 17
265
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 18
266
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 19
267
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 20
268
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 21
269
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 22
270
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 23
271
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 24
272
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 25
273
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 26
274
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 27
275
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 28
276
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 29
277
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 30
278
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 31
279
    QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 32
280
};
281
282
283
static const QPainterPath::ElementType qpaintengineex_roundedrect_types[] = {
284
    QPainterPath::MoveToElement,
285
    QPainterPath::LineToElement,
286
    QPainterPath::CurveToElement,
287
    QPainterPath::CurveToDataElement,
288
    QPainterPath::CurveToDataElement,
289
    QPainterPath::LineToElement,
290
    QPainterPath::CurveToElement,
291
    QPainterPath::CurveToDataElement,
292
    QPainterPath::CurveToDataElement,
293
    QPainterPath::LineToElement,
294
    QPainterPath::CurveToElement,
295
    QPainterPath::CurveToDataElement,
296
    QPainterPath::CurveToDataElement,
297
    QPainterPath::LineToElement,
298
    QPainterPath::CurveToElement,
299
    QPainterPath::CurveToDataElement,
300
    QPainterPath::CurveToDataElement
301
};
302
303
304
305
3.45M
static void qpaintengineex_moveTo(qreal x, qreal y, void *data) {
306
3.45M
    ((StrokeHandler *) data)->pts.add(x);
307
3.45M
    ((StrokeHandler *) data)->pts.add(y);
308
3.45M
    ((StrokeHandler *) data)->types.add(QPainterPath::MoveToElement);
309
3.45M
}
310
311
24.1M
static void qpaintengineex_lineTo(qreal x, qreal y, void *data) {
312
24.1M
    ((StrokeHandler *) data)->pts.add(x);
313
24.1M
    ((StrokeHandler *) data)->pts.add(y);
314
24.1M
    ((StrokeHandler *) data)->types.add(QPainterPath::LineToElement);
315
24.1M
}
316
317
823k
static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data) {
318
823k
    ((StrokeHandler *) data)->pts.add(c1x);
319
823k
    ((StrokeHandler *) data)->pts.add(c1y);
320
823k
    ((StrokeHandler *) data)->types.add(QPainterPath::CurveToElement);
321
322
823k
    ((StrokeHandler *) data)->pts.add(c2x);
323
823k
    ((StrokeHandler *) data)->pts.add(c2y);
324
823k
    ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement);
325
326
823k
    ((StrokeHandler *) data)->pts.add(ex);
327
823k
    ((StrokeHandler *) data)->pts.add(ey);
328
823k
    ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement);
329
823k
}
330
331
QPaintEngineEx::QPaintEngineEx()
332
981
    : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures)
333
981
{
334
981
    extended = true;
335
981
}
336
337
QPaintEngineEx::QPaintEngineEx(QPaintEngineExPrivate &data)
338
45.2k
    : QPaintEngine(data, AllFeatures)
339
45.2k
{
340
45.2k
    extended = true;
341
45.2k
}
342
343
QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
344
0
{
345
0
    if (!orig)
346
0
        return new QPainterState;
347
0
    return new QPainterState(orig);
348
0
}
349
350
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
351
352
void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
353
56.5k
{
354
#ifdef QT_DEBUG_DRAW
355
    qDebug() << "QPaintEngineEx::stroke()" << inPen;
356
#endif
357
358
56.5k
    Q_D(QPaintEngineEx);
359
360
56.5k
    if (path.isEmpty())
361
0
        return;
362
363
56.5k
    if (!d->strokeHandler) {
364
102
        d->strokeHandler = new StrokeHandler(path.elementCount()+4);
365
102
        d->stroker.setMoveToHook(qpaintengineex_moveTo);
366
102
        d->stroker.setLineToHook(qpaintengineex_lineTo);
367
102
        d->stroker.setCubicToHook(qpaintengineex_cubicTo);
368
102
    }
369
370
56.5k
    QRectF clipRect;
371
56.5k
    QPen pen = inPen;
372
56.5k
    if (pen.style() > Qt::SolidLine) {
373
15.8k
        QRectF cpRect = path.controlPointRect();
374
15.8k
        const QTransform &xf = state()->matrix;
375
15.8k
        if (pen.isCosmetic()) {
376
0
            clipRect = d->exDeviceRect;
377
0
            cpRect.translate(xf.dx(), xf.dy());
378
15.8k
        } else {
379
15.8k
            clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
380
15.8k
        }
381
        // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
382
15.8k
        qreal pw = pen.widthF() ? pen.widthF() : 1;
383
15.8k
        QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
384
15.8k
        qreal extent = qMax(extentRect.width(), extentRect.height());
385
15.8k
        qreal patternLength = 0;
386
15.8k
        const QList<qreal> pattern = pen.dashPattern();
387
15.8k
        const int patternSize = qMin(pattern.size(), 32);
388
112k
        for (int i = 0; i < patternSize; i++)
389
97.0k
            patternLength += qMax(pattern.at(i), qreal(0));
390
15.8k
        patternLength *= pw;
391
15.8k
        if (qFuzzyIsNull(patternLength)) {
392
811
            pen.setStyle(Qt::NoPen);
393
15.0k
        } else if (extent / patternLength > QDashStroker::repetitionLimit()) {
394
            // approximate stream of tiny dashes with semi-transparent solid line
395
165
            pen.setStyle(Qt::SolidLine);
396
165
            QColor color(pen.color());
397
165
            color.setAlpha(color.alpha() / 2);
398
165
            pen.setColor(color);
399
165
        }
400
15.8k
    }
401
402
56.5k
    if (!qpen_fast_equals(pen, d->strokerPen)) {
403
31.9k
        d->strokerPen = pen;
404
31.9k
        d->stroker.setJoinStyle(pen.joinStyle());
405
31.9k
        d->stroker.setCapStyle(pen.capStyle());
406
31.9k
        d->stroker.setMiterLimit(pen.miterLimit());
407
31.9k
        qreal penWidth = pen.widthF();
408
31.9k
        if (penWidth == 0)
409
0
            d->stroker.setStrokeWidth(1);
410
31.9k
        else
411
31.9k
            d->stroker.setStrokeWidth(penWidth);
412
413
31.9k
        Qt::PenStyle style = pen.style();
414
31.9k
        if (style == Qt::SolidLine) {
415
21.3k
            d->activeStroker = &d->stroker;
416
21.3k
        } else if (style == Qt::NoPen) {
417
811
            d->activeStroker = nullptr;
418
9.78k
        } else {
419
9.78k
            d->dasher.setDashPattern(pen.dashPattern());
420
9.78k
            d->dasher.setDashOffset(pen.dashOffset());
421
9.78k
            d->activeStroker = &d->dasher;
422
9.78k
        }
423
31.9k
    }
424
425
56.5k
    if (!d->activeStroker) {
426
811
        return;
427
811
    }
428
429
55.7k
    if (!clipRect.isNull())
430
15.0k
        d->activeStroker->setClipRect(clipRect);
431
432
55.7k
    if (d->activeStroker == &d->stroker)
433
40.8k
        d->stroker.setForceOpen(path.hasExplicitOpen());
434
435
55.7k
    const QPainterPath::ElementType *types = path.elements();
436
55.7k
    const qreal *points = path.points();
437
55.7k
    int pointCount = path.elementCount();
438
439
55.7k
    const qreal *lastPoint = points + (pointCount<<1);
440
441
55.7k
    d->strokeHandler->types.reset();
442
55.7k
    d->strokeHandler->pts.reset();
443
444
    // Some engines might decide to optimize for the non-shape hint later on...
445
55.7k
    uint flags = QVectorPath::WindingFill;
446
447
55.7k
    if (path.elementCount() > 2)
448
44.4k
        flags |= QVectorPath::NonConvexShapeMask;
449
450
55.7k
    if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin)
451
11.4k
        flags |= QVectorPath::CurvedShapeMask;
452
453
    // ### Perspective Xforms are currently not supported...
454
55.7k
    if (!pen.isCosmetic()) {
455
        // We include cosmetic pens in this case to avoid having to
456
        // change the current transform. Normal transformed,
457
        // non-cosmetic pens will be transformed as part of fill
458
        // later, so they are also covered here..
459
55.7k
        d->activeStroker->setCurveThresholdFromTransform(state()->matrix);
460
55.7k
        d->activeStroker->begin(d->strokeHandler);
461
55.7k
        if (types) {
462
2.79M
            while (points < lastPoint) {
463
2.73M
                switch (*types) {
464
524k
                case QPainterPath::MoveToElement:
465
524k
                    d->activeStroker->moveTo(points[0], points[1]);
466
524k
                    points += 2;
467
524k
                    ++types;
468
524k
                    break;
469
2.04M
                case QPainterPath::LineToElement:
470
2.04M
                    d->activeStroker->lineTo(points[0], points[1]);
471
2.04M
                    points += 2;
472
2.04M
                    ++types;
473
2.04M
                    break;
474
174k
                case QPainterPath::CurveToElement:
475
174k
                    d->activeStroker->cubicTo(points[0], points[1],
476
174k
                                              points[2], points[3],
477
174k
                                              points[4], points[5]);
478
174k
                    points += 6;
479
174k
                    types += 3;
480
174k
                    flags |= QVectorPath::CurvedShapeMask;
481
174k
                    break;
482
0
                default:
483
0
                    break;
484
2.73M
                }
485
2.73M
            }
486
54.2k
            if (path.hasImplicitClose())
487
0
                d->activeStroker->lineTo(path.points()[0], path.points()[1]);
488
489
54.2k
        } else {
490
1.51k
            d->activeStroker->moveTo(points[0], points[1]);
491
1.51k
            points += 2;
492
3.59M
            while (points < lastPoint) {
493
3.58M
                d->activeStroker->lineTo(points[0], points[1]);
494
3.58M
                points += 2;
495
3.58M
            }
496
1.51k
            if (path.hasImplicitClose())
497
470
                d->activeStroker->lineTo(path.points()[0], path.points()[1]);
498
1.51k
        }
499
55.7k
        d->activeStroker->end();
500
501
55.7k
        if (!d->strokeHandler->types.size()) // an empty path...
502
11.6k
            return;
503
504
44.0k
        QVectorPath strokePath(d->strokeHandler->pts.data(),
505
44.0k
                               d->strokeHandler->types.size(),
506
44.0k
                               d->strokeHandler->types.data(),
507
44.0k
                               flags);
508
44.0k
        fill(strokePath, pen.brush());
509
44.0k
    } else {
510
        // For cosmetic pens we need a bit of trickery... We to process xform the input points
511
0
        if (state()->matrix.type() >= QTransform::TxProject) {
512
0
            QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath());
513
0
            d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform());
514
0
        } else {
515
0
            d->activeStroker->setCurveThresholdFromTransform(QTransform());
516
0
            d->activeStroker->begin(d->strokeHandler);
517
0
            if (types) {
518
0
                while (points < lastPoint) {
519
0
                    switch (*types) {
520
0
                    case QPainterPath::MoveToElement: {
521
0
                        QPointF pt = (*(const QPointF *) points) * state()->matrix;
522
0
                        d->activeStroker->moveTo(pt.x(), pt.y());
523
0
                        points += 2;
524
0
                        ++types;
525
0
                        break;
526
0
                    }
527
0
                    case QPainterPath::LineToElement: {
528
0
                        QPointF pt = (*(const QPointF *) points) * state()->matrix;
529
0
                        d->activeStroker->lineTo(pt.x(), pt.y());
530
0
                        points += 2;
531
0
                        ++types;
532
0
                        break;
533
0
                    }
534
0
                    case QPainterPath::CurveToElement: {
535
0
                        QPointF c1 = ((const QPointF *) points)[0] * state()->matrix;
536
0
                        QPointF c2 = ((const QPointF *) points)[1] * state()->matrix;
537
0
                        QPointF e =  ((const QPointF *) points)[2] * state()->matrix;
538
0
                        d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
539
0
                        points += 6;
540
0
                        types += 3;
541
0
                        flags |= QVectorPath::CurvedShapeMask;
542
0
                        break;
543
0
                    }
544
0
                    default:
545
0
                        break;
546
0
                    }
547
0
                }
548
0
                if (path.hasImplicitClose()) {
549
0
                    QPointF pt = * ((const QPointF *) path.points()) * state()->matrix;
550
0
                    d->activeStroker->lineTo(pt.x(), pt.y());
551
0
                }
552
553
0
            } else {
554
0
                QPointF p = ((const QPointF *)points)[0] * state()->matrix;
555
0
                d->activeStroker->moveTo(p.x(), p.y());
556
0
                points += 2;
557
0
                while (points < lastPoint) {
558
0
                    QPointF p = ((const QPointF *)points)[0] * state()->matrix;
559
0
                    d->activeStroker->lineTo(p.x(), p.y());
560
0
                    points += 2;
561
0
                }
562
0
                if (path.hasImplicitClose())
563
0
                    d->activeStroker->lineTo(p.x(), p.y());
564
0
            }
565
0
            d->activeStroker->end();
566
0
        }
567
568
0
        QVectorPath strokePath(d->strokeHandler->pts.data(),
569
0
                               d->strokeHandler->types.size(),
570
0
                               d->strokeHandler->types.data(),
571
0
                               flags);
572
573
0
        QTransform xform = state()->matrix;
574
0
        state()->matrix = QTransform();
575
0
        transformChanged();
576
577
0
        QBrush brush = pen.brush();
578
0
        if (qbrush_style(brush) != Qt::SolidPattern)
579
0
            brush.setTransform(brush.transform() * xform);
580
581
0
        fill(strokePath, brush);
582
583
0
        state()->matrix = xform;
584
0
        transformChanged();
585
0
    }
586
55.7k
}
587
588
void QPaintEngineEx::draw(const QVectorPath &path)
589
201k
{
590
201k
    const QBrush &brush = state()->brush;
591
201k
    if (qbrush_style(brush) != Qt::NoBrush)
592
129k
        fill(path, brush);
593
594
201k
    const QPen &pen = state()->pen;
595
201k
    if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush)
596
108k
        stroke(path, pen);
597
201k
}
598
599
600
void QPaintEngineEx::clip(const QRect &r, Qt::ClipOperation op)
601
0
{
602
0
    qreal right = r.x() + r.width();
603
0
    qreal bottom = r.y() + r.height();
604
0
    qreal pts[] = { qreal(r.x()), qreal(r.y()),
605
0
                    right, qreal(r.y()),
606
0
                    right, bottom,
607
0
                    qreal(r.x()), bottom,
608
0
                    qreal(r.x()), qreal(r.y()) };
609
0
    QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
610
0
    clip(vp, op);
611
0
}
612
613
void QPaintEngineEx::clip(const QRegion &region, Qt::ClipOperation op)
614
0
{
615
0
    const auto rectsInRegion = region.rectCount();
616
0
    if (rectsInRegion == 1) {
617
0
        clip(*region.begin(), op);
618
0
    } else if (rectsInRegion <= 32) {
619
0
        qreal pts[2*32*4];
620
0
        int pos = 0;
621
0
        for (QRect r : region) {
622
0
            qreal x1 = r.x();
623
0
            qreal y1 = r.y();
624
0
            qreal x2 = r.x() + r.width();
625
0
            qreal y2 = r.y() + r.height();
626
627
0
            pts[pos++] = x1;
628
0
            pts[pos++] = y1;
629
630
0
            pts[pos++] = x2;
631
0
            pts[pos++] = y1;
632
633
0
            pts[pos++] = x2;
634
0
            pts[pos++] = y2;
635
636
0
            pts[pos++] = x1;
637
0
            pts[pos++] = y2;
638
0
        }
639
0
        QVectorPath vp(pts, rectsInRegion * 4, qpaintengineex_rect4_types_32);
640
0
        clip(vp, op);
641
0
    } else {
642
0
        QVarLengthArray<qreal> pts(rectsInRegion * 2 * 4);
643
0
        QVarLengthArray<QPainterPath::ElementType> types(rectsInRegion * 4);
644
0
        int ppos = 0;
645
0
        int tpos = 0;
646
647
0
        for (QRect r : region) {
648
0
            qreal x1 = r.x();
649
0
            qreal y1 = r.y();
650
0
            qreal x2 = r.x() + r.width();
651
0
            qreal y2 = r.y() + r.height();
652
653
0
            pts[ppos++] = x1;
654
0
            pts[ppos++] = y1;
655
656
0
            pts[ppos++] = x2;
657
0
            pts[ppos++] = y1;
658
659
0
            pts[ppos++] = x2;
660
0
            pts[ppos++] = y2;
661
662
0
            pts[ppos++] = x1;
663
0
            pts[ppos++] = y2;
664
665
0
            types[tpos++] = QPainterPath::MoveToElement;
666
0
            types[tpos++] = QPainterPath::LineToElement;
667
0
            types[tpos++] = QPainterPath::LineToElement;
668
0
            types[tpos++] = QPainterPath::LineToElement;
669
0
        }
670
671
0
        QVectorPath vp(pts.data(), rectsInRegion * 4, types.data());
672
0
        clip(vp, op);
673
0
    }
674
675
0
}
676
677
void QPaintEngineEx::clip(const QPainterPath &path, Qt::ClipOperation op)
678
0
{
679
0
    if (path.isEmpty()) {
680
0
        QVectorPath vp(nullptr, 0);
681
0
        clip(vp, op);
682
0
    } else {
683
0
        clip(qtVectorPathForPath(path), op);
684
0
    }
685
0
}
686
687
void QPaintEngineEx::fillRect(const QRectF &r, const QBrush &brush)
688
0
{
689
0
    qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(),
690
0
                    r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() };
691
0
    QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
692
0
    fill(vp, brush);
693
0
}
694
695
void QPaintEngineEx::fillRect(const QRectF &r, const QColor &color)
696
0
{
697
0
    fillRect(r, QBrush(color));
698
0
}
699
700
void QPaintEngineEx::drawRects(const QRect *rects, int rectCount)
701
0
{
702
0
    for (int i=0; i<rectCount; ++i) {
703
0
        const QRect &r = rects[i];
704
        // ### Is there a one off here?
705
0
        qreal right = r.x() + r.width();
706
0
        qreal bottom = r.y() + r.height();
707
0
        qreal pts[] = { qreal(r.x()), qreal(r.y()),
708
0
                        right, qreal(r.y()),
709
0
                        right, bottom,
710
0
                        qreal(r.x()), bottom,
711
0
                        qreal(r.x()), qreal(r.y()) };
712
0
        QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
713
0
        draw(vp);
714
0
    }
715
0
}
716
717
void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount)
718
902
{
719
1.80k
    for (int i=0; i<rectCount; ++i) {
720
902
        const QRectF &r = rects[i];
721
902
        qreal right = r.x() + r.width();
722
902
        qreal bottom = r.y() + r.height();
723
902
        qreal pts[] = { r.x(), r.y(),
724
902
                        right, r.y(),
725
902
                        right, bottom,
726
902
                        r.x(), bottom,
727
902
                        r.x(), r.y() };
728
902
        QVectorPath vp(pts, 5, nullptr, QVectorPath::RectangleHint);
729
902
        draw(vp);
730
902
    }
731
902
}
732
733
734
void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
735
                                     Qt::SizeMode mode)
736
1.35k
{
737
1.35k
    qreal x1 = rect.left();
738
1.35k
    qreal x2 = rect.right();
739
1.35k
    qreal y1 = rect.top();
740
1.35k
    qreal y2 = rect.bottom();
741
742
1.35k
    if (mode == Qt::RelativeSize) {
743
1.35k
        xRadius = xRadius * rect.width() / 200.;
744
1.35k
        yRadius = yRadius * rect.height() / 200.;
745
1.35k
    }
746
747
1.35k
    xRadius = qMin(xRadius, rect.width() / 2);
748
1.35k
    yRadius = qMin(yRadius, rect.height() / 2);
749
750
1.35k
    qreal pts[] = {
751
1.35k
        x1 + xRadius, y1,                   // MoveTo
752
1.35k
        x2 - xRadius, y1,                   // LineTo
753
1.35k
        x2 - (1 - KAPPA) * xRadius, y1,     // CurveTo
754
1.35k
        x2, y1 + (1 - KAPPA) * yRadius,
755
1.35k
        x2, y1 + yRadius,
756
1.35k
        x2, y2 - yRadius,                   // LineTo
757
1.35k
        x2, y2 - (1 - KAPPA) * yRadius,     // CurveTo
758
1.35k
        x2 - (1 - KAPPA) * xRadius, y2,
759
1.35k
        x2 - xRadius, y2,
760
1.35k
        x1 + xRadius, y2,                   // LineTo
761
1.35k
        x1 + (1 - KAPPA) * xRadius, y2,           // CurveTo
762
1.35k
        x1, y2 - (1 - KAPPA) * yRadius,
763
1.35k
        x1, y2 - yRadius,
764
1.35k
        x1, y1 + yRadius,                   // LineTo
765
1.35k
        x1, y1 + (1 - KAPPA) * yRadius,           // CurveTo
766
1.35k
        x1 + (1 - KAPPA) * xRadius, y1,
767
1.35k
        x1 + xRadius, y1
768
1.35k
    };
769
770
1.35k
    QVectorPath path(pts, 17, qpaintengineex_roundedrect_types, QVectorPath::RoundedRectHint);
771
1.35k
    draw(path);
772
1.35k
}
773
774
775
776
void QPaintEngineEx::drawLines(const QLine *lines, int lineCount)
777
0
{
778
0
    int elementCount = lineCount << 1;
779
0
    while (elementCount > 0) {
780
0
        int count = qMin(elementCount, 32);
781
782
0
        qreal pts[64];
783
0
        int count2 = count<<1;
784
0
        for (int i=0; i<count2; ++i)
785
0
            pts[i] = ((const int *) lines)[i];
786
787
0
        QVectorPath path(pts, count, qpaintengineex_line_types_16, QVectorPath::LinesHint);
788
0
        stroke(path, state()->pen);
789
790
0
        elementCount -= 32;
791
0
        lines += 16;
792
0
    }
793
0
}
794
795
void QPaintEngineEx::drawLines(const QLineF *lines, int lineCount)
796
9.39k
{
797
9.39k
    int elementCount = lineCount << 1;
798
18.7k
    while (elementCount > 0) {
799
9.39k
        int count = qMin(elementCount, 32);
800
801
9.39k
        QVectorPath path((const qreal *) lines, count, qpaintengineex_line_types_16,
802
9.39k
                         QVectorPath::LinesHint);
803
9.39k
        stroke(path, state()->pen);
804
805
9.39k
        elementCount -= 32;
806
9.39k
        lines += 16;
807
9.39k
    }
808
9.39k
}
809
810
void QPaintEngineEx::drawEllipse(const QRectF &r)
811
1.99k
{
812
1.99k
    qreal pts[26]; // QPointF[13] without constructors...
813
1.99k
    union {
814
1.99k
        qreal *ptr;
815
1.99k
        QPointF *points;
816
1.99k
    } x;
817
1.99k
    x.ptr = pts;
818
819
1.99k
    int point_count = 0;
820
1.99k
    x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
821
1.99k
    if (point_count == 0)
822
250
        return;
823
1.74k
    QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
824
1.74k
    draw(vp);
825
1.74k
}
826
827
void QPaintEngineEx::drawEllipse(const QRect &r)
828
0
{
829
0
    drawEllipse(QRectF(r));
830
0
}
831
832
void QPaintEngineEx::drawPath(const QPainterPath &path)
833
200k
{
834
200k
    if (!path.isEmpty())
835
195k
        draw(qtVectorPathForPath(path));
836
200k
}
837
838
839
void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
840
6.51k
{
841
6.51k
    QPen pen = state()->pen;
842
6.51k
    if (pen.capStyle() == Qt::FlatCap)
843
0
        pen.setCapStyle(Qt::SquareCap);
844
845
6.51k
    if (pen.brush().isOpaque()) {
846
12.8k
        while (pointCount > 0) {
847
6.43k
            int count = qMin(pointCount, 16);
848
6.43k
            qreal pts[64];
849
6.43k
            int oset = -1;
850
12.8k
            for (int i=0; i<count; ++i) {
851
6.43k
                pts[++oset] = points[i].x();
852
6.43k
                pts[++oset] = points[i].y();
853
6.43k
                pts[++oset] = points[i].x() + 1/63.;
854
6.43k
                pts[++oset] = points[i].y();
855
6.43k
            }
856
6.43k
            QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
857
6.43k
            stroke(path, pen);
858
6.43k
            pointCount -= 16;
859
6.43k
            points += 16;
860
6.43k
        }
861
6.43k
    } else {
862
166
        for (int i=0; i<pointCount; ++i) {
863
83
            qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + qreal(1/63.), points[i].y() };
864
83
            QVectorPath path(pts, 2, nullptr);
865
83
            stroke(path, pen);
866
83
        }
867
83
    }
868
6.51k
}
869
870
void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
871
0
{
872
0
    QPen pen = state()->pen;
873
0
    if (pen.capStyle() == Qt::FlatCap)
874
0
        pen.setCapStyle(Qt::SquareCap);
875
876
0
    if (pen.brush().isOpaque()) {
877
0
        while (pointCount > 0) {
878
0
            int count = qMin(pointCount, 16);
879
0
            qreal pts[64];
880
0
            int oset = -1;
881
0
            for (int i=0; i<count; ++i) {
882
0
                pts[++oset] = points[i].x();
883
0
                pts[++oset] = points[i].y();
884
0
                pts[++oset] = points[i].x() + 1/63.;
885
0
                pts[++oset] = points[i].y();
886
0
            }
887
0
            QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
888
0
            stroke(path, pen);
889
0
            pointCount -= 16;
890
0
            points += 16;
891
0
        }
892
0
    } else {
893
0
        for (int i=0; i<pointCount; ++i) {
894
0
            qreal pts[] = { qreal(points[i].x()), qreal(points[i].y()),
895
0
                            qreal(points[i].x() +1/63.), qreal(points[i].y()) };
896
0
            QVectorPath path(pts, 2, nullptr);
897
0
            stroke(path, pen);
898
0
        }
899
0
    }
900
0
}
901
902
903
void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
904
3.51k
{
905
3.51k
    Q_ASSERT(pointCount >= 2);
906
3.51k
    QVectorPath path((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
907
908
3.51k
    if (mode == PolylineMode)
909
1.09k
        stroke(path, state()->pen);
910
2.41k
    else
911
2.41k
        draw(path);
912
3.51k
}
913
914
void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
915
0
{
916
0
    Q_ASSERT(pointCount >= 2);
917
0
    int count = pointCount<<1;
918
0
    QVarLengthArray<qreal> pts(count);
919
920
0
    for (int i=0; i<count; ++i)
921
0
        pts[i] = ((const int *) points)[i];
922
923
0
    QVectorPath path(pts.data(), pointCount, nullptr, QVectorPath::polygonFlags(mode));
924
925
0
    if (mode == PolylineMode)
926
0
        stroke(path, state()->pen);
927
0
    else
928
0
        draw(path);
929
930
0
}
931
932
void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm)
933
0
{
934
0
    drawPixmap(QRectF(pos, pm.deviceIndependentSize()), pm, pm.rect());
935
0
}
936
937
void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image)
938
0
{
939
0
    drawImage(QRectF(pos, image.deviceIndependentSize()), image, image.rect());
940
0
}
941
942
void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
943
0
{
944
0
    QBrush brush(state()->pen.color(), pixmap);
945
0
    QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y());
946
0
    if (!qFuzzyCompare(pixmap.devicePixelRatio(), qreal(1.0)))
947
0
        xform.scale(1.0/pixmap.devicePixelRatio(), 1.0/pixmap.devicePixelRatio());
948
0
    brush.setTransform(xform);
949
950
0
    qreal pts[] = { r.x(), r.y(),
951
0
                    r.x() + r.width(), r.y(),
952
0
                    r.x() + r.width(), r.y() + r.height(),
953
0
                    r.x(), r.y() + r.height() };
954
955
0
    QVectorPath path(pts, 4, nullptr, QVectorPath::RectangleHint);
956
0
    fill(path, brush);
957
0
}
958
959
void QPaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount,
960
                                         const QPixmap &pixmap, QPainter::PixmapFragmentHints /*hints*/)
961
0
{
962
0
    if (pixmap.isNull())
963
0
        return;
964
965
0
    qreal oldOpacity = state()->opacity;
966
0
    QTransform oldTransform = state()->matrix;
967
968
0
    for (int i = 0; i < fragmentCount; ++i) {
969
0
        QTransform transform = oldTransform;
970
0
        transform.translate(fragments[i].x, fragments[i].y);
971
0
        transform.rotate(fragments[i].rotation);
972
0
        state()->opacity = oldOpacity * fragments[i].opacity;
973
0
        state()->matrix = transform;
974
0
        opacityChanged();
975
0
        transformChanged();
976
977
0
        qreal w = fragments[i].scaleX * fragments[i].width;
978
0
        qreal h = fragments[i].scaleY * fragments[i].height;
979
0
        QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
980
0
                          fragments[i].width, fragments[i].height);
981
0
        drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, sourceRect);
982
0
    }
983
984
0
    state()->opacity = oldOpacity;
985
0
    state()->matrix = oldTransform;
986
0
    opacityChanged();
987
0
    transformChanged();
988
0
}
989
990
void QPaintEngineEx::setState(QPainterState *s)
991
197k
{
992
197k
    QPaintEngine::state = s;
993
197k
}
994
995
996
void QPaintEngineEx::updateState(const QPaintEngineState &)
997
0
{
998
    // do nothing...
999
0
}
1000
1001
Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
1002
0
{
1003
0
    const qreal *points = path.points();
1004
0
    const QPainterPath::ElementType *types = path.elements();
1005
1006
0
    QPainterPath p;
1007
0
    if (types) {
1008
0
        int id = 0;
1009
0
        for (int i=0; i<path.elementCount(); ++i) {
1010
0
            switch(types[i]) {
1011
0
            case QPainterPath::MoveToElement:
1012
0
                p.moveTo(QPointF(points[id], points[id+1]));
1013
0
                id+=2;
1014
0
                break;
1015
0
            case QPainterPath::LineToElement:
1016
0
                p.lineTo(QPointF(points[id], points[id+1]));
1017
0
                id+=2;
1018
0
                break;
1019
0
            case QPainterPath::CurveToElement: {
1020
0
                QPointF p1(points[id], points[id+1]);
1021
0
                QPointF p2(points[id+2], points[id+3]);
1022
0
                QPointF p3(points[id+4], points[id+5]);
1023
0
                p.cubicTo(p1, p2, p3);
1024
0
                id+=6;
1025
0
                break;
1026
0
            }
1027
0
            case QPainterPath::CurveToDataElement:
1028
0
                ;
1029
0
                break;
1030
0
            }
1031
0
        }
1032
0
    } else {
1033
0
        p.moveTo(QPointF(points[0], points[1]));
1034
0
        int id = 2;
1035
0
        for (int i=1; i<path.elementCount(); ++i) {
1036
0
            p.lineTo(QPointF(points[id], points[id+1]));
1037
0
            id+=2;
1038
0
        }
1039
0
    }
1040
0
    if (path.hints() & QVectorPath::WindingFill)
1041
0
        p.setFillRule(Qt::WindingFill);
1042
1043
0
    return p;
1044
0
}
1045
1046
void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem)
1047
0
{
1048
0
    QPainterPath path;
1049
0
    path.setFillRule(Qt::WindingFill);
1050
1051
0
    if (staticTextItem->numGlyphs == 0)
1052
0
        return;
1053
1054
0
    QFontEngine *fontEngine = staticTextItem->fontEngine();
1055
0
    fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
1056
0
                                staticTextItem->numGlyphs, &path, { });
1057
0
    if (!path.isEmpty()) {
1058
0
        QPainterState *s = state();
1059
0
        QPainter::RenderHints oldHints = s->renderHints;
1060
0
        bool changedHints = false;
1061
0
        if (bool(oldHints & QPainter::TextAntialiasing)
1062
0
            && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
1063
0
            && !bool(oldHints & QPainter::Antialiasing)) {
1064
0
            s->renderHints |= QPainter::Antialiasing;
1065
0
            renderHintsChanged();
1066
0
            changedHints = true;
1067
0
        }
1068
1069
0
        fill(qtVectorPathForPath(path), s->pen.brush());
1070
1071
0
        if (changedHints) {
1072
0
            s->renderHints = oldHints;
1073
0
            renderHintsChanged();
1074
0
        }
1075
0
    }
1076
0
}
1077
1078
bool QPaintEngineEx::requiresPretransformedGlyphPositions(QFontEngine *, const QTransform &) const
1079
0
{
1080
0
    return false;
1081
0
}
1082
1083
bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const
1084
0
{
1085
0
    if (fontEngine->glyphFormat == QFontEngine::Format_ARGB)
1086
0
        return true;
1087
1088
0
    static const int maxCachedGlyphSizeSquared = std::pow([]{
1089
0
        if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE"))
1090
0
            return env;
1091
0
        return QT_MAX_CACHED_GLYPH_SIZE;
1092
0
    }(), 2);
1093
1094
0
    qreal pixelSize = fontEngine->fontDef.pixelSize;
1095
0
    return (pixelSize * pixelSize * qAbs(m.determinant())) <= maxCachedGlyphSizeSquared;
1096
0
}
1097
1098
QT_END_NAMESPACE