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/qpaintengine.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
#include "qpaintengine.h"
5
#include "qpaintengine_p.h"
6
#include "qpainter_p.h"
7
#include "qpolygon.h"
8
#include "qbitmap.h"
9
#include <qdebug.h>
10
#include <qmath.h>
11
#include <qguiapplication.h>
12
#include <qvarlengtharray.h>
13
#include <qpa/qplatformintegration.h>
14
#include <qpa/qplatformpixmap.h>
15
#include <private/qfontengine_p.h>
16
#include <private/qguiapplication_p.h>
17
#include <private/qpaintengineex_p.h>
18
#include <private/qtextengine_p.h>
19
20
#include <memory>
21
22
QT_BEGIN_NAMESPACE
23
24
/*!
25
    \class QTextItem
26
    \inmodule QtGui
27
28
    \brief The QTextItem class provides all the information required to draw
29
    text in a custom paint engine.
30
31
    When you reimplement your own paint engine, you must reimplement
32
    QPaintEngine::drawTextItem(), a function that takes a QTextItem as
33
    one of its arguments.
34
*/
35
36
/*!
37
  \enum QTextItem::RenderFlag
38
39
  \value  RightToLeft Render the text from right to left.
40
  \value  Overline    Paint a line above the text.
41
  \value  Underline   Paint a line under the text.
42
  \value  StrikeOut   Paint a line through the text.
43
  \omitvalue Dummy
44
*/
45
46
47
/*!
48
    \fn qreal QTextItem::descent() const
49
50
    Corresponds to the \l{QFontMetrics::descent()}{descent} of the piece of text that is drawn.
51
*/
52
qreal QTextItem::descent() const
53
0
{
54
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
55
0
    return ti->descent.toReal();
56
0
}
57
58
/*!
59
    \fn qreal QTextItem::ascent() const
60
61
    Corresponds to the \l{QFontMetrics::ascent()}{ascent} of the piece of text that is drawn.
62
*/
63
qreal QTextItem::ascent() const
64
0
{
65
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
66
0
    return ti->ascent.toReal();
67
0
}
68
69
/*!
70
    \fn qreal QTextItem::width() const
71
72
    Specifies the total width of the text to be drawn.
73
*/
74
qreal QTextItem::width() const
75
0
{
76
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
77
0
    return ti->width.toReal();
78
0
}
79
80
/*!
81
    \fn QTextItem::RenderFlags QTextItem::renderFlags() const
82
83
    Returns the render flags used.
84
*/
85
QTextItem::RenderFlags QTextItem::renderFlags() const
86
0
{
87
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
88
0
    return ti->flags;
89
0
}
90
91
/*!
92
    \fn QString QTextItem::text() const
93
94
    Returns the text that should be drawn.
95
*/
96
QString QTextItem::text() const
97
0
{
98
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
99
0
    return QString(ti->chars, ti->num_chars);
100
0
}
101
102
/*!
103
    \fn QFont QTextItem::font() const
104
105
    Returns the font that should be used to draw the text.
106
*/
107
QFont QTextItem::font() const
108
0
{
109
0
    const QTextItemInt *ti = static_cast<const QTextItemInt *>(this);
110
0
    return ti->f ? *ti->f : QGuiApplication::font();
111
0
}
112
113
114
/*!
115
  \class QPaintEngine
116
  \ingroup painting
117
    \inmodule QtGui
118
119
  \brief The QPaintEngine class provides an abstract definition of how
120
  QPainter draws to a given device on a given platform.
121
122
  Qt provides several premade implementations of QPaintEngine for the
123
  different painter backends we support. The primary paint engine
124
  provided is the raster paint engine, which contains a software
125
  rasterizer which supports the full feature set on all supported platforms.
126
  This is the default for painting on QWidget-based classes in e.g. on Windows,
127
  X11 and \macos, it is the backend for painting on QImage and it is
128
  used as a fallback for paint engines that do not support a certain
129
  capability. In addition we provide QPaintEngine implementations for
130
  OpenGL (accessible through QOpenGLWidget) and printing (which allows using
131
  QPainter to draw on a QPrinter object).
132
133
  If one wants to use QPainter to draw to a different backend,
134
  one must subclass QPaintEngine and reimplement all its virtual
135
  functions. The QPaintEngine implementation is then made available by
136
  subclassing QPaintDevice and reimplementing the virtual function
137
  QPaintDevice::paintEngine().
138
139
  QPaintEngine is created and owned by the QPaintDevice that created it.
140
141
  \sa QPainter, QPaintDevice::paintEngine(), {Paint System}
142
*/
143
144
/*!
145
  \enum QPaintEngine::PaintEngineFeature
146
147
  This enum is used to describe the features or capabilities that the
148
  paint engine has. If a feature is not supported by the engine,
149
  QPainter will do a best effort to emulate that feature through other
150
  means and pass on an alpha blended QImage to the engine with the
151
  emulated results. Some features cannot be emulated: AlphaBlend and PorterDuff.
152
153
  \value AlphaBlend         The engine can alpha blend primitives.
154
  \value Antialiasing       The engine can use antialiasing to improve the appearance
155
                            of rendered primitives.
156
  \value BlendModes         The engine supports blending modes.
157
  \value BrushStroke        The engine supports drawing strokes that
158
                            contain brushes as fills, not just solid
159
                            colors (e.g. a dashed gradient line of
160
                            width 2).
161
  \value ConicalGradientFill The engine supports conical gradient fills.
162
  \value ConstantOpacity    The engine supports the feature provided by
163
                            QPainter::setOpacity().
164
  \value LinearGradientFill The engine supports linear gradient fills.
165
  \value MaskedBrush        The engine is capable of rendering brushes that has a
166
                            texture with an alpha channel or a mask.
167
  \value ObjectBoundingModeGradients The engine has native support for gradients
168
                            with coordinate mode QGradient::ObjectBoundingMode.
169
                            Otherwise, if QPaintEngine::PatternTransform is
170
                            supported, object bounding mode gradients are
171
                            converted to gradients with coordinate mode
172
                            QGradient::LogicalMode and a brush transform for
173
                            the coordinate mapping.
174
  \value PainterPaths       The engine has path support.
175
  \value PaintOutsidePaintEvent The engine is capable of painting outside of
176
                                paint events.
177
  \value PatternBrush       The engine is capable of rendering brushes with
178
                            the brush patterns specified in Qt::BrushStyle.
179
  \value PatternTransform   The engine has support for transforming brush
180
                            patterns.
181
  \value PerspectiveTransform The engine has support for performing perspective
182
                            transformations on primitives.
183
  \value PixmapTransform    The engine can transform pixmaps, including
184
                            rotation and shearing.
185
  \value PorterDuff         The engine supports Porter-Duff operations
186
  \value PrimitiveTransform The engine has support for transforming
187
                            drawing primitives.
188
  \value RadialGradientFill The engine supports radial gradient fills.
189
  \value RasterOpModes      The engine supports bitwise raster operations.
190
  \value AllFeatures        All of the above features. This enum value is usually
191
                            used as a bit mask.
192
*/
193
194
/*!
195
    \enum QPaintEngine::PolygonDrawMode
196
197
    \value OddEvenMode The polygon should be drawn using OddEven fill
198
    rule.
199
200
    \value WindingMode The polygon should be drawn using Winding fill rule.
201
202
    \value ConvexMode The polygon is a convex polygon and can be drawn
203
    using specialized algorithms where available.
204
205
    \value PolylineMode Only the outline of the polygon should be
206
    drawn.
207
208
*/
209
210
/*!
211
    \enum QPaintEngine::DirtyFlag
212
213
    \value DirtyPen The pen is dirty and needs to be updated.
214
215
    \value DirtyBrush The brush is dirty and needs to be updated.
216
217
    \value DirtyBrushOrigin The brush origin is dirty and needs to
218
    updated.
219
220
    \value DirtyFont The font is dirty and needs to be updated.
221
222
    \value DirtyBackground The background is dirty and needs to be
223
    updated.
224
225
    \value DirtyBackgroundMode The background mode is dirty and needs
226
    to be updated.
227
228
    \value DirtyTransform The transform is dirty and needs to be
229
    updated.
230
231
    \value DirtyClipRegion The clip region is dirty and needs to be
232
    updated.
233
234
    \value DirtyClipPath The clip path is dirty and needs to be
235
    updated.
236
237
    \value DirtyHints The render hints is dirty and needs to be
238
    updated.
239
240
    \value DirtyCompositionMode The composition mode is dirty and
241
    needs to be updated.
242
243
    \value DirtyClipEnabled Whether clipping is enabled or not is
244
    dirty and needs to be updated.
245
246
    \value DirtyOpacity The constant opacity has changed and needs to
247
                        be updated as part of the state change in
248
                        QPaintEngine::updateState().
249
250
    \value AllDirty Convenience enum used internally.
251
252
    These types are used by QPainter to trigger lazy updates of the
253
    various states in the QPaintEngine using
254
    QPaintEngine::updateState().
255
256
    A paint engine must update every dirty state.
257
*/
258
259
/*!
260
    \fn void QPaintEngine::syncState()
261
262
    \internal
263
264
    Updates all dirty states in this engine. This function should ONLY
265
    be used when drawing with native handles directly and immediate sync
266
    from QPainters state to the native state is required.
267
*/
268
void QPaintEngine::syncState()
269
0
{
270
0
    Q_ASSERT(state);
271
0
    updateState(*state);
272
273
0
    if (isExtended())
274
0
        static_cast<QPaintEngineEx *>(this)->sync();
275
0
}
276
277
static QPaintEngine *qt_polygon_recursion = nullptr;
278
struct QT_Point {
279
    int x;
280
    int y;
281
};
282
Q_DECLARE_TYPEINFO(QT_Point, Q_PRIMITIVE_TYPE);
283
284
/*!
285
    \fn void QPaintEngine::drawPolygon(const QPointF *points, int pointCount,
286
    PolygonDrawMode mode)
287
288
    Reimplement this virtual function to draw the polygon defined
289
    by the \a pointCount first points in \a points, using mode \a
290
    mode.
291
292
    \note At least one of the drawPolygon() functions must be reimplemented.
293
*/
294
void QPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
295
0
{
296
0
    Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
297
0
               "At least one drawPolygon function must be implemented");
298
0
    qt_polygon_recursion = this;
299
0
    Q_ASSERT(sizeof(QT_Point) == sizeof(QPoint));
300
0
    QVarLengthArray<QT_Point> p(pointCount);
301
0
    for (int i = 0; i < pointCount; ++i) {
302
0
        p[i].x = qRound(points[i].x());
303
0
        p[i].y = qRound(points[i].y());
304
0
    }
305
0
    drawPolygon((QPoint *)p.data(), pointCount, mode);
306
0
    qt_polygon_recursion = nullptr;
307
0
}
308
309
struct QT_PointF {
310
    qreal x;
311
    qreal y;
312
};
313
Q_DECLARE_TYPEINFO(QT_PointF, Q_PRIMITIVE_TYPE);
314
315
/*!
316
    \overload
317
318
    Reimplement this virtual function to draw the polygon defined by the
319
    \a pointCount first points in \a points, using mode \a mode.
320
321
    \note At least one of the drawPolygon() functions must be reimplemented.
322
*/
323
void QPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
324
0
{
325
0
    Q_ASSERT_X(qt_polygon_recursion != this, "QPaintEngine::drawPolygon",
326
0
               "At least one drawPolygon function must be implemented");
327
0
    qt_polygon_recursion = this;
328
0
    Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
329
0
    QVarLengthArray<QT_PointF> p(pointCount);
330
0
    for (int i=0; i<pointCount; ++i) {
331
0
        p[i].x = points[i].x();
332
0
        p[i].y = points[i].y();
333
0
    }
334
0
    drawPolygon((QPointF *)p.data(), pointCount, mode);
335
0
    qt_polygon_recursion = nullptr;
336
0
}
337
338
/*!
339
    \enum QPaintEngine::Type
340
341
    \value X11
342
    \value Windows
343
    \value MacPrinter
344
    \value CoreGraphics \macos's Quartz2D (CoreGraphics)
345
    \value QuickDraw \macos's QuickDraw
346
    \value QWindowSystem Qt for Embedded Linux
347
    \value OpenGL
348
    \value Picture QPicture format
349
    \value SVG Scalable Vector Graphics XML format
350
    \value Raster
351
    \value Direct3D Windows only, Direct3D based engine
352
    \value Pdf Portable Document Format
353
    \value OpenVG
354
    \value User First user type ID
355
    \value MaxUser Last user type ID
356
    \value OpenGL2
357
    \value PaintBuffer
358
    \value Blitter
359
    \value Direct2D Windows only, Direct2D based engine
360
*/
361
362
/*!
363
    \fn bool QPaintEngine::isActive() const
364
365
    Returns \c true if the paint engine is actively drawing; otherwise
366
    returns \c false.
367
368
    \sa setActive()
369
*/
370
371
/*!
372
    \fn void QPaintEngine::setActive(bool state)
373
374
    Sets the active state of the paint engine to \a state.
375
376
    \sa isActive()
377
*/
378
379
/*!
380
    \fn bool QPaintEngine::begin(QPaintDevice *pdev)
381
382
    Reimplement this function to initialise your paint engine when
383
    painting is to start on the paint device \a pdev. Return true if
384
    the initialization was successful; otherwise return false.
385
386
    \sa end(), isActive()
387
*/
388
389
/*!
390
    \fn bool QPaintEngine::end()
391
392
    Reimplement this function to finish painting on the current paint
393
    device. Return true if painting was finished successfully;
394
    otherwise return false.
395
396
    \sa begin(), isActive()
397
*/
398
399
400
/*!
401
    Draws the first \a pointCount points in the buffer \a points
402
*/
403
void QPaintEngine::drawPoints(const QPointF *points, int pointCount)
404
0
{
405
0
    QPainter *p = painter();
406
0
    if (!p)
407
0
        return;
408
409
0
    qreal penWidth = p->pen().widthF();
410
0
    if (penWidth == 0)
411
0
        penWidth = 1;
412
413
0
    bool ellipses = p->pen().capStyle() == Qt::RoundCap;
414
415
0
    p->save();
416
417
0
    QTransform transform;
418
0
    if (p->pen().isCosmetic()) {
419
0
        transform = p->transform();
420
0
        p->setTransform(QTransform());
421
0
    }
422
423
0
    p->setBrush(p->pen().brush());
424
0
    p->setPen(Qt::NoPen);
425
426
0
    for (int i=0; i<pointCount; ++i) {
427
0
        QPointF pos = transform.map(points[i]);
428
0
        QRectF rect(pos.x() - penWidth / 2, pos.y() - penWidth / 2, penWidth, penWidth);
429
430
0
        if (ellipses)
431
0
            p->drawEllipse(rect);
432
0
        else
433
0
            p->drawRect(rect);
434
0
    }
435
436
0
    p->restore();
437
0
}
438
439
440
/*!
441
    Draws the first \a pointCount points in the buffer \a points
442
443
    The default implementation converts the first \a pointCount QPoints in \a points
444
    to QPointFs and calls the floating point version of drawPoints.
445
446
*/
447
void QPaintEngine::drawPoints(const QPoint *points, int pointCount)
448
0
{
449
0
    Q_ASSERT(sizeof(QT_PointF) == sizeof(QPointF));
450
0
    QT_PointF fp[256];
451
0
    while (pointCount) {
452
0
        int i = 0;
453
0
        while (i < pointCount && i < 256) {
454
0
            fp[i].x = points[i].x();
455
0
            fp[i].y = points[i].y();
456
0
            ++i;
457
0
        }
458
0
        drawPoints((QPointF *)(void *)fp, i);
459
0
        points += i;
460
0
        pointCount -= i;
461
0
    }
462
0
}
463
464
/*!
465
    \fn void QPaintEngine::drawEllipse(const QRectF &rect)
466
467
    Reimplement this function to draw the largest ellipse that can be
468
    contained within rectangle \a rect.
469
470
    The default implementation calls drawPolygon().
471
*/
472
void QPaintEngine::drawEllipse(const QRectF &rect)
473
0
{
474
0
    QPainterPath path;
475
0
    path.addEllipse(rect);
476
0
    if (hasFeature(PainterPaths)) {
477
0
        drawPath(path);
478
0
    } else {
479
0
        QPolygonF polygon = path.toFillPolygon();
480
0
        drawPolygon(polygon.data(), polygon.size(), ConvexMode);
481
0
    }
482
0
}
483
484
/*!
485
    \overload
486
487
    The default implementation of this function calls the floating
488
    point version of this function
489
*/
490
void QPaintEngine::drawEllipse(const QRect &rect)
491
0
{
492
0
    drawEllipse(QRectF(rect));
493
0
}
494
495
/*!
496
    \fn void QPaintEngine::drawPixmap(const QRectF &r, const QPixmap
497
    &pm, const QRectF &sr)
498
499
    Reimplement this function to draw the part of the \a pm
500
    specified by the \a sr rectangle in the given \a r.
501
*/
502
503
504
void qt_fill_tile(QPixmap *tile, const QPixmap &pixmap)
505
0
{
506
0
    QPainter p(tile);
507
0
    p.drawPixmap(0, 0, pixmap);
508
0
    int x = pixmap.width();
509
0
    while (x < tile->width()) {
510
0
        p.drawPixmap(x, 0, *tile, 0, 0, x, pixmap.height());
511
0
        x *= 2;
512
0
    }
513
0
    int y = pixmap.height();
514
0
    while (y < tile->height()) {
515
0
        p.drawPixmap(0, y, *tile, 0, 0, tile->width(), y);
516
0
        y *= 2;
517
0
    }
518
0
}
519
520
Q_GUI_EXPORT void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
521
                               const QPixmap &pixmap, qreal xOffset, qreal yOffset)
522
0
{
523
0
    qreal yPos, xPos, drawH, drawW, yOff, xOff;
524
0
    yPos = y;
525
0
    yOff = yOffset;
526
0
    while(yPos < y + h) {
527
0
        drawH = pixmap.height() - yOff;    // Cropping first row
528
0
        if (yPos + drawH > y + h)           // Cropping last row
529
0
            drawH = y + h - yPos;
530
0
        xPos = x;
531
0
        xOff = xOffset;
532
0
        while(xPos < x + w) {
533
0
            drawW = pixmap.width() - xOff; // Cropping first column
534
0
            if (xPos + drawW > x + w)           // Cropping last column
535
0
                drawW = x + w - xPos;
536
0
            if (drawW > 0 && drawH > 0)
537
0
                gc->drawPixmap(QRectF(xPos, yPos, drawW, drawH), pixmap, QRectF(xOff, yOff, drawW, drawH));
538
0
            xPos += drawW;
539
0
            xOff = 0;
540
0
        }
541
0
        yPos += drawH;
542
0
        yOff = 0;
543
0
    }
544
0
}
545
546
547
/*!
548
    Reimplement this function to draw the \a pixmap in the given \a
549
    rect, starting at the given \a p. The pixmap will be
550
    drawn repeatedly until the \a rect is filled.
551
*/
552
void QPaintEngine::drawTiledPixmap(const QRectF &rect, const QPixmap &pixmap, const QPointF &p)
553
0
{
554
0
    int sw = pixmap.width();
555
0
    int sh = pixmap.height();
556
557
0
    if (sw*sh < 8192 && sw*sh < 16*rect.width()*rect.height()) {
558
0
        int tw = sw, th = sh;
559
0
        while (tw*th < 32678 && tw < rect.width()/2)
560
0
            tw *= 2;
561
0
        while (tw*th < 32678 && th < rect.height()/2)
562
0
            th *= 2;
563
0
        QPixmap tile;
564
0
        if (pixmap.depth() == 1) {
565
0
            tile = QBitmap(tw, th);
566
0
        } else {
567
0
            tile = QPixmap(tw, th);
568
0
            if (pixmap.hasAlphaChannel())
569
0
                tile.fill(Qt::transparent);
570
0
        }
571
0
        qt_fill_tile(&tile, pixmap);
572
0
        qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), tile, p.x(), p.y());
573
0
    } else {
574
0
        qt_draw_tile(this, rect.x(), rect.y(), rect.width(), rect.height(), pixmap, p.x(), p.y());
575
0
    }
576
0
}
577
578
/*!
579
    \fn void QPaintEngine::drawImage(const QRectF &rectangle, const QImage
580
    &image, const QRectF &sr, Qt::ImageConversionFlags flags)
581
582
    Reimplement this function to draw the part of the \a image
583
    specified by the \a sr rectangle in the given \a rectangle using
584
    the given conversion flags \a flags, to convert it to a pixmap.
585
*/
586
587
void QPaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
588
                             Qt::ImageConversionFlags flags)
589
0
{
590
0
    QRectF baseSize(0, 0, image.width(), image.height());
591
0
    QImage im = image;
592
0
    if (baseSize != sr)
593
0
        im = im.copy(qFloor(sr.x()), qFloor(sr.y()),
594
0
                     qCeil(sr.width()), qCeil(sr.height()));
595
0
    QPixmap pm = QPixmap::fromImage(im, flags);
596
0
    drawPixmap(r, pm, QRectF(QPointF(0, 0), pm.size()));
597
0
}
598
599
/*!
600
    \fn Type QPaintEngine::type() const
601
602
    Reimplement this function to return the paint engine \l{Type}.
603
*/
604
605
/*!
606
    \fn void QPaintEngine::fix_neg_rect(int *x, int *y, int *w, int *h);
607
608
    \internal
609
*/
610
611
/*!
612
    \fn bool QPaintEngine::testDirty(DirtyFlags df)
613
614
    \internal
615
*/
616
617
/*!
618
    \fn void QPaintEngine::clearDirty(DirtyFlags df)
619
620
    \internal
621
*/
622
623
/*!
624
    \fn void QPaintEngine::setDirty(DirtyFlags df)
625
626
    \internal
627
*/
628
629
/*!
630
    \fn bool QPaintEngine::hasFeature(PaintEngineFeatures feature) const
631
632
    Returns \c true if the paint engine supports the specified \a
633
    feature; otherwise returns \c false.
634
*/
635
636
/*!
637
    \fn bool QPaintEngine::isExtended() const
638
639
    \internal
640
641
    Returns \c true if the paint engine is a QPaintEngineEx derivative.
642
*/
643
644
/*!
645
    \fn void QPaintEngine::updateState(const QPaintEngineState &state)
646
647
    Reimplement this function to update the state of a paint engine.
648
649
    When implemented, this function is responsible for checking the
650
    paint engine's current \a state and update the properties that are
651
    changed. Use the QPaintEngineState::state() function to find out
652
    which properties that must be updated, then use the corresponding
653
    \l {GetFunction}{get function} to retrieve the current values for
654
    the given properties.
655
656
    \sa QPaintEngineState
657
*/
658
659
/*!
660
    Creates a paint engine with the featureset specified by \a caps.
661
*/
662
663
QPaintEngine::QPaintEngine(PaintEngineFeatures caps)
664
0
    : state(nullptr),
665
0
      gccaps(caps),
666
0
      active(0),
667
0
      selfDestruct(false),
668
0
      extended(false),
669
0
      d_ptr(new QPaintEnginePrivate)
670
0
{
671
0
    d_ptr->q_ptr = this;
672
0
}
673
674
/*!
675
  \internal
676
*/
677
678
QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps)
679
110k
    : state(nullptr),
680
110k
      gccaps(caps),
681
110k
      active(0),
682
110k
      selfDestruct(false),
683
110k
      extended(false),
684
110k
      d_ptr(&dptr)
685
110k
{
686
110k
    d_ptr->q_ptr = this;
687
110k
}
688
689
/*!
690
    Destroys the paint engine.
691
*/
692
QPaintEngine::~QPaintEngine()
693
110k
{
694
110k
}
695
696
/*!
697
    Returns the paint engine's painter.
698
*/
699
QPainter *QPaintEngine::painter() const
700
4.47k
{
701
4.47k
    return state ? state->painter() : nullptr;
702
4.47k
}
703
704
/*!
705
    The default implementation ignores the \a path and does nothing.
706
*/
707
708
void QPaintEngine::drawPath(const QPainterPath &)
709
0
{
710
0
    if (hasFeature(PainterPaths)) {
711
0
        qWarning("QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set");
712
0
    }
713
0
}
714
715
/*!
716
    This function draws the text item \a textItem at position \a p. The
717
    default implementation of this function converts the text to a
718
    QPainterPath and paints the resulting path.
719
*/
720
721
void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
722
0
{
723
0
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
724
0
    if (ti.glyphs.numGlyphs == 0)
725
0
        return;
726
727
0
    if (ti.fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
728
0
        QVarLengthArray<QFixedPoint> positions;
729
0
        QVarLengthArray<glyph_t> glyphs;
730
0
        QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - ti.fontEngine->ascent().toReal());
731
0
        ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
732
0
        painter()->save();
733
0
        painter()->setRenderHint(QPainter::SmoothPixmapTransform,
734
0
                                 bool((painter()->renderHints() & QPainter::TextAntialiasing)
735
0
                                      && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
736
0
        for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
737
0
            QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixedPoint(), QTransform());
738
0
            painter()->drawImage(positions[i].x.toReal(), positions[i].y.toReal(), glyph);
739
0
        }
740
0
        painter()->restore();
741
0
        return;
742
0
    }
743
744
0
    QPainterPath path;
745
0
    path.setFillRule(Qt::WindingFill);
746
0
    ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
747
0
    if (!path.isEmpty()) {
748
0
        painter()->save();
749
0
        painter()->setRenderHint(QPainter::Antialiasing,
750
0
                                 bool((painter()->renderHints() & QPainter::TextAntialiasing)
751
0
                                      && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
752
0
        painter()->translate(p.x(), p.y());
753
0
        painter()->fillPath(path, painter()->pen().brush());
754
0
        painter()->restore();
755
0
    }
756
0
}
757
758
/*!
759
    The default implementation splits the list of lines in \a lines
760
    into \a lineCount separate calls to drawPath() or drawPolygon()
761
    depending on the feature set of the paint engine.
762
*/
763
void QPaintEngine::drawLines(const QLineF *lines, int lineCount)
764
0
{
765
0
    for (int i=0; i<lineCount; ++i) {
766
0
        QPointF pts[2] = { lines[i].p1(), lines[i].p2() };
767
768
0
        if (pts[0] == pts[1]) {
769
0
            if (state->pen().capStyle() != Qt::FlatCap)
770
0
                drawPoints(pts, 1);
771
0
            continue;
772
0
        }
773
774
0
        drawPolygon(pts, 2, PolylineMode);
775
0
    }
776
0
}
777
778
/*!
779
    \overload
780
781
    The default implementation converts the first \a lineCount lines
782
    in \a lines to a QLineF and calls the floating point version of
783
    this function.
784
*/
785
void QPaintEngine::drawLines(const QLine *lines, int lineCount)
786
0
{
787
0
    struct PointF {
788
0
        qreal x;
789
0
        qreal y;
790
0
    };
791
0
    struct LineF {
792
0
        PointF p1;
793
0
        PointF p2;
794
0
    };
795
0
    Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
796
0
    Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
797
0
    LineF fl[256];
798
0
    while (lineCount) {
799
0
        int i = 0;
800
0
        while (i < lineCount && i < 256) {
801
0
            fl[i].p1.x = lines[i].x1();
802
0
            fl[i].p1.y = lines[i].y1();
803
0
            fl[i].p2.x = lines[i].x2();
804
0
            fl[i].p2.y = lines[i].y2();
805
0
            ++i;
806
0
        }
807
0
        drawLines((QLineF *)(void *)fl, i);
808
0
        lines += i;
809
0
        lineCount -= i;
810
0
    }
811
0
}
812
813
814
/*!
815
    \overload
816
817
    The default implementation converts the first \a rectCount
818
    rectangles in the buffer \a rects to a QRectF and calls the
819
    floating point version of this function.
820
*/
821
void QPaintEngine::drawRects(const QRect *rects, int rectCount)
822
0
{
823
0
    struct RectF {
824
0
        qreal x;
825
0
        qreal y;
826
0
        qreal w;
827
0
        qreal h;
828
0
    };
829
0
    Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
830
0
    RectF fr[256];
831
0
    while (rectCount) {
832
0
        int i = 0;
833
0
        while (i < rectCount && i < 256) {
834
0
            fr[i].x = rects[i].x();
835
0
            fr[i].y = rects[i].y();
836
0
            fr[i].w = rects[i].width();
837
0
            fr[i].h = rects[i].height();
838
0
            ++i;
839
0
        }
840
0
        drawRects((QRectF *)(void *)fr, i);
841
0
        rects += i;
842
0
        rectCount -= i;
843
0
    }
844
0
}
845
846
/*!
847
    Draws the first \a rectCount rectangles in the buffer \a
848
    rects. The default implementation of this function calls drawPath()
849
    or drawPolygon() depending on the feature set of the paint engine.
850
*/
851
void QPaintEngine::drawRects(const QRectF *rects, int rectCount)
852
0
{
853
0
    if (hasFeature(PainterPaths) &&
854
0
        !state->penNeedsResolving() &&
855
0
        !state->brushNeedsResolving()) {
856
0
        for (int i=0; i<rectCount; ++i) {
857
0
            QPainterPath path;
858
0
            path.addRect(rects[i]);
859
0
            if (path.isEmpty())
860
0
                continue;
861
0
            drawPath(path);
862
0
        }
863
0
    } else {
864
0
        for (int i=0; i<rectCount; ++i) {
865
0
            QRectF rf = rects[i];
866
0
            QPointF pts[4] = { QPointF(rf.x(), rf.y()),
867
0
                               QPointF(rf.x() + rf.width(), rf.y()),
868
0
                               QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
869
0
                               QPointF(rf.x(), rf.y() + rf.height()) };
870
0
            drawPolygon(pts, 4, ConvexMode);
871
0
        }
872
0
    }
873
0
}
874
875
/*!
876
    \internal
877
    Sets the paintdevice that this engine operates on to \a device
878
*/
879
void QPaintEngine::setPaintDevice(QPaintDevice *device)
880
220k
{
881
220k
    d_func()->pdev = device;
882
220k
}
883
884
/*!
885
    Returns the device that this engine is painting on, if painting is
886
    active; otherwise returns \nullptr.
887
*/
888
QPaintDevice *QPaintEngine::paintDevice() const
889
0
{
890
0
    return d_func()->pdev;
891
0
}
892
893
894
/*!
895
    \internal
896
897
    Returns the offset from the painters origo to the engines
898
    origo. This value is used by QPainter for engines who have
899
    internal double buffering.
900
901
    This function only makes sense when the engine is active.
902
*/
903
QPoint QPaintEngine::coordinateOffset() const
904
0
{
905
0
    return QPoint();
906
0
}
907
908
/*!
909
    \internal
910
911
    Sets the system clip for this engine. The system clip defines the
912
    basis area that the engine has to draw in. All clips that are
913
    set will be an intersection with the system clip.
914
915
    Reset the systemclip to no clip by setting an empty region.
916
*/
917
void QPaintEngine::setSystemClip(const QRegion &region)
918
0
{
919
0
    Q_D(QPaintEngine);
920
0
    d->baseSystemClip = region;
921
    // Be backward compatible and only call d->systemStateChanged()
922
    // if we currently have a system transform/viewport set.
923
0
    d->updateSystemClip();
924
0
    if (d->hasSystemTransform || d->hasSystemViewport) {
925
0
        d->systemStateChanged();
926
0
    }
927
0
}
928
929
/*!
930
    \internal
931
932
    Returns the system clip. The system clip is read only while the
933
    painter is active. An empty region indicates that system clip
934
    is not in use.
935
*/
936
937
QRegion QPaintEngine::systemClip() const
938
17.9k
{
939
17.9k
    return d_func()->systemClip;
940
17.9k
}
941
942
/*!
943
    \internal
944
945
    Sets the target rect for drawing within the backing store. This
946
    function should ONLY be used by the backing store.
947
*/
948
void QPaintEngine::setSystemRect(const QRect &rect)
949
0
{
950
0
    if (isActive()) {
951
0
        qWarning("QPaintEngine::setSystemRect: Should not be changed while engine is active");
952
0
        return;
953
0
    }
954
0
    d_func()->systemRect = rect;
955
0
}
956
957
/*!
958
    \internal
959
960
    Retrieves the rect for drawing within the backing store. This
961
    function should ONLY be used by the backing store.
962
 */
963
QRect QPaintEngine::systemRect() const
964
110k
{
965
110k
    return d_func()->systemRect;
966
110k
}
967
968
/*!
969
    \internal
970
971
    Creates a QPixmap optimized for this paint engine and device.
972
*/
973
QPixmap QPaintEngine::createPixmap(QSize size)
974
0
{
975
0
    if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
976
0
        qWarning("QPaintEngine::createPixmap: QPixmap cannot be created without a QGuiApplication");
977
0
        return QPixmap();
978
0
    }
979
980
0
    std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
981
0
    data->resize(size.width(), size.height());
982
0
    return QPixmap(data.release());
983
0
}
984
985
/*!
986
    \internal
987
988
    Creates a QPixmap optimized for this paint engine and device.
989
*/
990
QPixmap QPaintEngine::createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags)
991
0
{
992
0
    if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
993
0
        qWarning("QPaintEngine::createPixmapFromImage: QPixmap cannot be created without a QGuiApplication");
994
0
        return QPixmap();
995
0
    }
996
997
0
    std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
998
0
    if (image.isDetached())
999
0
        data->fromImageInPlace(image, flags);
1000
0
    else
1001
0
        data->fromImage(image, flags);
1002
0
    return QPixmap(data.release());
1003
0
}
1004
1005
QPaintEnginePrivate::~QPaintEnginePrivate()
1006
110k
{
1007
110k
}
1008
1009
void QPaintEnginePrivate::drawBoxTextItem(const QPointF &p, const QTextItemInt &ti)
1010
0
{
1011
0
    if (!ti.glyphs.numGlyphs)
1012
0
        return;
1013
1014
    // any fixes here should probably also be done in QFontEngineBox::draw
1015
0
    const int size = qRound(ti.fontEngine->ascent());
1016
0
    QVarLengthArray<QFixedPoint> positions;
1017
0
    QVarLengthArray<glyph_t> glyphs;
1018
0
    QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - size);
1019
0
    ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1020
0
    if (glyphs.size() == 0)
1021
0
        return;
1022
1023
0
    QSize s(size - 3, size - 3);
1024
1025
0
    QPainter *painter = q_func()->state->painter();
1026
0
    painter->save();
1027
0
    painter->setBrush(Qt::NoBrush);
1028
0
    QPen pen = painter->pen();
1029
0
    pen.setWidthF(ti.fontEngine->lineThickness().toReal());
1030
0
    painter->setPen(pen);
1031
0
    for (int k = 0; k < positions.size(); k++)
1032
0
        painter->drawRect(QRectF(positions[k].toPointF(), s));
1033
0
    painter->restore();
1034
0
}
1035
1036
QT_END_NAMESPACE