Coverage Report

Created: 2026-02-10 07:39

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