Coverage Report

Created: 2026-04-29 07:00

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