Coverage Report

Created: 2026-10-27 06:57

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
4.18k
    : state(nullptr),
680
4.18k
      gccaps(caps),
681
4.18k
      active(0),
682
4.18k
      selfDestruct(false),
683
4.18k
      extended(false),
684
4.18k
      d_ptr(&dptr)
685
4.18k
{
686
4.18k
    d_ptr->q_ptr = this;
687
4.18k
}
688
689
/*!
690
    Destroys the paint engine.
691
*/
692
QPaintEngine::~QPaintEngine()
693
4.18k
{
694
4.18k
}
695
696
/*!
697
    Returns the paint engine's painter.
698
*/
699
QPainter *QPaintEngine::painter() const
700
0
{
701
0
    return state ? state->painter() : nullptr;
702
0
}
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());
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
        const QColor color = painter()->pen().color();
737
0
        for (qsizetype i = 0; i < glyphs.size(); ++i) {
738
0
            QImage glyph
739
0
                = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixedPoint(), QTransform(), color);
740
0
            if (glyph.isNull())
741
0
                continue;
742
            // The glyph positions are on the baseline; place the image using
743
            // the glyph's own bearings.
744
0
            const glyph_metrics_t metrics = ti.fontEngine->alphaMapBoundingBox(
745
0
                glyphs[i], QFixedPoint(), QTransform(), QFontEngine::Format_ARGB);
746
0
            painter()->drawImage(QPointF(positions[i].x.toReal() + metrics.x.toReal(),
747
0
                                         positions[i].y.toReal() + metrics.y.toReal()),
748
0
                                 glyph);
749
0
        }
750
0
        painter()->restore();
751
0
        return;
752
0
    }
753
754
0
    QPainterPath path;
755
0
    path.setFillRule(Qt::WindingFill);
756
0
    ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
757
0
    if (!path.isEmpty()) {
758
0
        painter()->save();
759
0
        painter()->setRenderHint(QPainter::Antialiasing,
760
0
                                 bool((painter()->renderHints() & QPainter::TextAntialiasing)
761
0
                                      && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
762
0
        painter()->translate(p.x(), p.y());
763
0
        painter()->fillPath(path, painter()->pen().brush());
764
0
        painter()->restore();
765
0
    }
766
0
}
767
768
/*!
769
    The default implementation splits the list of lines in \a lines
770
    into \a lineCount separate calls to drawPath() or drawPolygon()
771
    depending on the feature set of the paint engine.
772
*/
773
void QPaintEngine::drawLines(const QLineF *lines, int lineCount)
774
0
{
775
0
    for (int i=0; i<lineCount; ++i) {
776
0
        QPointF pts[2] = { lines[i].p1(), lines[i].p2() };
777
778
0
        if (pts[0] == pts[1]) {
779
0
            if (state->pen().capStyle() != Qt::FlatCap)
780
0
                drawPoints(pts, 1);
781
0
            continue;
782
0
        }
783
784
0
        drawPolygon(pts, 2, PolylineMode);
785
0
    }
786
0
}
787
788
/*!
789
    \overload
790
791
    The default implementation converts the first \a lineCount lines
792
    in \a lines to a QLineF and calls the floating point version of
793
    this function.
794
*/
795
void QPaintEngine::drawLines(const QLine *lines, int lineCount)
796
0
{
797
0
    struct PointF {
798
0
        qreal x;
799
0
        qreal y;
800
0
    };
801
0
    struct LineF {
802
0
        PointF p1;
803
0
        PointF p2;
804
0
    };
805
0
    Q_ASSERT(sizeof(PointF) == sizeof(QPointF));
806
0
    Q_ASSERT(sizeof(LineF) == sizeof(QLineF));
807
0
    LineF fl[256];
808
0
    while (lineCount) {
809
0
        int i = 0;
810
0
        while (i < lineCount && i < 256) {
811
0
            fl[i].p1.x = lines[i].x1();
812
0
            fl[i].p1.y = lines[i].y1();
813
0
            fl[i].p2.x = lines[i].x2();
814
0
            fl[i].p2.y = lines[i].y2();
815
0
            ++i;
816
0
        }
817
0
        drawLines((QLineF *)(void *)fl, i);
818
0
        lines += i;
819
0
        lineCount -= i;
820
0
    }
821
0
}
822
823
824
/*!
825
    \overload
826
827
    The default implementation converts the first \a rectCount
828
    rectangles in the buffer \a rects to a QRectF and calls the
829
    floating point version of this function.
830
*/
831
void QPaintEngine::drawRects(const QRect *rects, int rectCount)
832
0
{
833
0
    struct RectF {
834
0
        qreal x;
835
0
        qreal y;
836
0
        qreal w;
837
0
        qreal h;
838
0
    };
839
0
    Q_ASSERT(sizeof(RectF) == sizeof(QRectF));
840
0
    RectF fr[256];
841
0
    while (rectCount) {
842
0
        int i = 0;
843
0
        while (i < rectCount && i < 256) {
844
0
            fr[i].x = rects[i].x();
845
0
            fr[i].y = rects[i].y();
846
0
            fr[i].w = rects[i].width();
847
0
            fr[i].h = rects[i].height();
848
0
            ++i;
849
0
        }
850
0
        drawRects((QRectF *)(void *)fr, i);
851
0
        rects += i;
852
0
        rectCount -= i;
853
0
    }
854
0
}
855
856
/*!
857
    Draws the first \a rectCount rectangles in the buffer \a
858
    rects. The default implementation of this function calls drawPath()
859
    or drawPolygon() depending on the feature set of the paint engine.
860
*/
861
void QPaintEngine::drawRects(const QRectF *rects, int rectCount)
862
0
{
863
0
    if (hasFeature(PainterPaths) &&
864
0
        !state->penNeedsResolving() &&
865
0
        !state->brushNeedsResolving()) {
866
0
        for (int i=0; i<rectCount; ++i) {
867
0
            QPainterPath path;
868
0
            path.addRect(rects[i]);
869
0
            if (path.isEmpty())
870
0
                continue;
871
0
            drawPath(path);
872
0
        }
873
0
    } else {
874
0
        for (int i=0; i<rectCount; ++i) {
875
0
            QRectF rf = rects[i];
876
0
            QPointF pts[4] = { QPointF(rf.x(), rf.y()),
877
0
                               QPointF(rf.x() + rf.width(), rf.y()),
878
0
                               QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
879
0
                               QPointF(rf.x(), rf.y() + rf.height()) };
880
0
            drawPolygon(pts, 4, ConvexMode);
881
0
        }
882
0
    }
883
0
}
884
885
/*!
886
    \internal
887
    Sets the paintdevice that this engine operates on to \a device
888
*/
889
void QPaintEngine::setPaintDevice(QPaintDevice *device)
890
3.71M
{
891
3.71M
    d_func()->pdev = device;
892
3.71M
}
893
894
/*!
895
    Returns the device that this engine is painting on, if painting is
896
    active; otherwise returns \nullptr.
897
*/
898
QPaintDevice *QPaintEngine::paintDevice() const
899
0
{
900
0
    return d_func()->pdev;
901
0
}
902
903
904
/*!
905
    \internal
906
907
    Returns the offset from the painters origo to the engines
908
    origo. This value is used by QPainter for engines who have
909
    internal double buffering.
910
911
    This function only makes sense when the engine is active.
912
*/
913
QPoint QPaintEngine::coordinateOffset() const
914
0
{
915
0
    return QPoint();
916
0
}
917
918
/*!
919
    \internal
920
921
    Sets the system clip for this engine. The system clip defines the
922
    basis area that the engine has to draw in. All clips that are
923
    set will be an intersection with the system clip.
924
925
    Reset the systemclip to no clip by setting an empty region.
926
*/
927
void QPaintEngine::setSystemClip(const QRegion &region)
928
0
{
929
0
    Q_D(QPaintEngine);
930
0
    d->baseSystemClip = region;
931
    // Be backward compatible and only call d->systemStateChanged()
932
    // if we currently have a system transform/viewport set.
933
0
    d->updateSystemClip();
934
0
    if (d->hasSystemTransform || d->hasSystemViewport) {
935
0
        d->systemStateChanged();
936
0
    }
937
0
}
938
939
/*!
940
    \internal
941
942
    Returns the system clip. The system clip is read only while the
943
    painter is active. An empty region indicates that system clip
944
    is not in use.
945
*/
946
947
QRegion QPaintEngine::systemClip() const
948
0
{
949
0
    return d_func()->systemClip;
950
0
}
951
952
/*!
953
    \internal
954
955
    Sets the target rect for drawing within the backing store. This
956
    function should ONLY be used by the backing store.
957
*/
958
void QPaintEngine::setSystemRect(const QRect &rect)
959
0
{
960
0
    if (isActive()) {
961
0
        qWarning("QPaintEngine::setSystemRect: Should not be changed while engine is active");
962
0
        return;
963
0
    }
964
0
    d_func()->systemRect = rect;
965
0
}
966
967
/*!
968
    \internal
969
970
    Retrieves the rect for drawing within the backing store. This
971
    function should ONLY be used by the backing store.
972
 */
973
QRect QPaintEngine::systemRect() const
974
1.85M
{
975
1.85M
    return d_func()->systemRect;
976
1.85M
}
977
978
/*!
979
    \internal
980
981
    Creates a QPixmap optimized for this paint engine and device.
982
*/
983
QPixmap QPaintEngine::createPixmap(QSize size)
984
0
{
985
0
    if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
986
0
        qWarning("QPaintEngine::createPixmap: QPixmap cannot be created without a QGuiApplication");
987
0
        return QPixmap();
988
0
    }
989
990
0
    std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
991
0
    data->resize(size.width(), size.height());
992
0
    return QPixmap(data.release());
993
0
}
994
995
/*!
996
    \internal
997
998
    Creates a QPixmap optimized for this paint engine and device.
999
*/
1000
QPixmap QPaintEngine::createPixmapFromImage(QImage image, Qt::ImageConversionFlags flags)
1001
0
{
1002
0
    if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(QCoreApplication::instance()))) {
1003
0
        qWarning("QPaintEngine::createPixmapFromImage: QPixmap cannot be created without a QGuiApplication");
1004
0
        return QPixmap();
1005
0
    }
1006
1007
0
    std::unique_ptr<QPlatformPixmap> data(QGuiApplicationPrivate::platformIntegration()->createPlatformPixmap(QPlatformPixmap::PixmapType));
1008
0
    if (image.isDetached())
1009
0
        data->fromImageInPlace(image, flags);
1010
0
    else
1011
0
        data->fromImage(image, flags);
1012
0
    return QPixmap(data.release());
1013
0
}
1014
1015
QPaintEnginePrivate::~QPaintEnginePrivate()
1016
4.18k
{
1017
4.18k
}
1018
1019
void QPaintEnginePrivate::drawBoxTextItem(const QPointF &p, const QTextItemInt &ti)
1020
0
{
1021
0
    if (!ti.glyphs.numGlyphs)
1022
0
        return;
1023
1024
    // any fixes here should probably also be done in QFontEngineBox::draw
1025
0
    const int size = qRound(ti.fontEngine->ascent());
1026
0
    QVarLengthArray<QFixedPoint> positions;
1027
0
    QVarLengthArray<glyph_t> glyphs;
1028
0
    QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - size);
1029
0
    ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1030
0
    if (glyphs.size() == 0)
1031
0
        return;
1032
1033
0
    QSize s(size - 3, size - 3);
1034
1035
0
    QPainter *painter = q_func()->state->painter();
1036
0
    painter->save();
1037
0
    painter->setBrush(Qt::NoBrush);
1038
0
    QPen pen = painter->pen();
1039
0
    pen.setWidthF(ti.fontEngine->lineThickness().toReal());
1040
0
    painter->setPen(pen);
1041
0
    for (int k = 0; k < positions.size(); k++)
1042
0
        painter->drawRect(QRectF(positions[k].toPointF(), s));
1043
0
    painter->restore();
1044
0
}
1045
1046
QT_END_NAMESPACE