Coverage Report

Created: 2026-09-14 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qpainter.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
4
// QtCore
5
// Qt-Security score:significant reason:default
6
#include <memory>
7
#include <qdebug.h>
8
#include <qmath.h>
9
#include <qmutex.h>
10
11
// QtGui
12
#include "qbitmap.h"
13
#include "qimage.h"
14
#include "qpaintdevice.h"
15
#include "qpaintengine.h"
16
#include "qpainter.h"
17
#include "qpainter_p.h"
18
#include "qpainterpath.h"
19
#include "qpicture.h"
20
#include "qpixmapcache.h"
21
#include "qpolygon.h"
22
#include "qtextlayout.h"
23
#include "qthread.h"
24
#include "qvarlengtharray.h"
25
#include "qstatictext.h"
26
#include "qglyphrun.h"
27
28
#include <qpa/qplatformtheme.h>
29
#include <qpa/qplatformintegration.h>
30
31
#include <private/qfontengine_p.h>
32
#include <private/qpaintengine_p.h>
33
#include <private/qemulationpaintengine_p.h>
34
#include <private/qpainterpath_p.h>
35
#include <private/qtextengine_p.h>
36
#include <private/qpaintengine_raster_p.h>
37
#include <private/qmath_p.h>
38
#include <private/qstatictext_p.h>
39
#include <private/qglyphrun_p.h>
40
#include <private/qhexstring_p.h>
41
#include <private/qguiapplication_p.h>
42
#include <private/qrawfont_p.h>
43
#include <private/qfont_p.h>
44
45
#include <QtCore/private/qtclasshelper_p.h>
46
47
QT_BEGIN_NAMESPACE
48
49
using namespace Qt::StringLiterals;
50
51
// We changed the type from QScopedPointer to unique_ptr, make sure it's binary compatible:
52
static_assert(sizeof(QScopedPointer<QPainterPrivate>) == sizeof(std::unique_ptr<QPainterPrivate>));
53
54
0
#define QGradient_StretchToDevice 0x10000000
55
0
#define QPaintEngine_OpaqueBackground 0x40000000
56
57
// #define QT_DEBUG_DRAW
58
#ifdef QT_DEBUG_DRAW
59
constexpr bool qt_show_painter_debug_output = true;
60
#endif
61
62
extern QPixmap qt_pixmapForBrush(int style, bool invert);
63
64
void qt_format_text(const QFont &font,
65
                    const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
66
                    int tabstops, int* tabarray, int tabarraylen,
67
                    QPainter *painter);
68
static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine,
69
                                   QTextCharFormat::UnderlineStyle underlineStyle,
70
                                   QTextItem::RenderFlags flags, qreal width,
71
                                   const QTextCharFormat &charFormat);
72
// Helper function to calculate left most position, width and flags for decoration drawing
73
static void qt_draw_decoration_for_glyphs(QPainter *painter,
74
                                          const QPointF &decorationPosition,
75
                                          const glyph_t *glyphArray,
76
                                          const QFixedPoint *positions,
77
                                          int glyphCount,
78
                                          QFontEngine *fontEngine,
79
                                          bool underline,
80
                                          bool overline,
81
                                          bool strikeOut);
82
83
static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
84
0
{
85
0
    switch (brush.style()) {
86
0
    case Qt::LinearGradientPattern:
87
0
    case Qt::RadialGradientPattern:
88
0
    case Qt::ConicalGradientPattern:
89
0
        return brush.gradient()->coordinateMode();
90
0
    default:
91
0
        ;
92
0
    }
93
0
    return QGradient::LogicalMode;
94
0
}
95
96
extern bool qHasPixmapTexture(const QBrush &);
97
98
0
static inline bool is_brush_transparent(const QBrush &brush) {
99
0
    Qt::BrushStyle s = brush.style();
100
0
    if (s != Qt::TexturePattern)
101
0
        return s >= Qt::Dense1Pattern && s <= Qt::DiagCrossPattern;
102
0
    if (qHasPixmapTexture(brush))
103
0
        return brush.texture().isQBitmap() || brush.texture().hasAlphaChannel();
104
0
    else {
105
0
        const QImage texture = brush.textureImage();
106
0
        return texture.hasAlphaChannel() || (texture.depth() == 1 && texture.colorCount() == 0);
107
0
    }
108
0
}
109
110
0
static inline bool is_pen_transparent(const QPen &pen) {
111
0
    return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());
112
0
}
113
114
/* Discards the emulation flags that are not relevant for line drawing
115
   and returns the result
116
*/
117
static inline uint line_emulation(uint emulation)
118
0
{
119
0
    return emulation & (QPaintEngine::PrimitiveTransform
120
0
                        | QPaintEngine::AlphaBlend
121
0
                        | QPaintEngine::Antialiasing
122
0
                        | QPaintEngine::BrushStroke
123
0
                        | QPaintEngine::ConstantOpacity
124
0
                        | QGradient_StretchToDevice
125
0
                        | QPaintEngine::ObjectBoundingModeGradients
126
0
                        | QPaintEngine_OpaqueBackground);
127
0
}
128
129
#ifndef QT_NO_DEBUG
130
static bool qt_painter_thread_test(int devType, int engineType, const char *what)
131
0
{
132
0
    const QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
133
0
    switch (devType) {
134
0
    case QInternal::Image:
135
0
    case QInternal::Printer:
136
0
    case QInternal::Picture:
137
        // can be drawn onto these devices safely from any thread
138
0
        break;
139
0
    default:
140
0
        if (!QThread::isMainThread()
141
                // pixmaps cannot be targets unless threaded pixmaps are supported
142
0
                && (devType != QInternal::Pixmap || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedPixmaps))
143
                // framebuffer objects and such cannot be targets unless threaded GL is supported
144
0
                && (devType != QInternal::OpenGL || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL))
145
                // widgets cannot be targets except for QGLWidget
146
0
                && (devType != QInternal::Widget || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL)
147
0
                    || (engineType != QPaintEngine::OpenGL && engineType != QPaintEngine::OpenGL2))) {
148
0
            qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
149
0
            return false;
150
0
        }
151
0
        break;
152
0
    }
153
0
    return true;
154
0
}
155
#endif
156
157
static bool needsEmulation(const QBrush &brush)
158
0
{
159
0
    bool res = false;
160
161
0
    const QGradient *bg = brush.gradient();
162
0
    if (bg) {
163
0
        res = (bg->coordinateMode() > QGradient::LogicalMode);
164
0
    } else if (brush.style() == Qt::TexturePattern) {
165
0
        if (qHasPixmapTexture(brush))
166
0
            res = !qFuzzyCompare(brush.texture().devicePixelRatio(), qreal(1.0));
167
0
        else
168
0
            res = !qFuzzyCompare(brush.textureImage().devicePixelRatio(), qreal(1.0));
169
0
    }
170
171
0
    return res;
172
0
}
173
174
void QPainterPrivate::checkEmulation()
175
0
{
176
0
    Q_ASSERT(extended);
177
0
    bool doEmulation = false;
178
0
    if (state->bgMode == Qt::OpaqueMode)
179
0
        doEmulation = true;
180
181
0
    if (needsEmulation(state->brush))
182
0
        doEmulation = true;
183
184
0
    if (needsEmulation(qpen_brush(state->pen)))
185
0
        doEmulation = true;
186
187
0
    if (doEmulation && extended->flags() & QPaintEngineEx::DoNotEmulate)
188
0
        return;
189
190
0
    if (doEmulation) {
191
0
        if (extended != emulationEngine.get()) {
192
0
            if (!emulationEngine)
193
0
                emulationEngine = std::make_unique<QEmulationPaintEngine>(extended);
194
0
            extended = emulationEngine.get();
195
0
            extended->setState(state.get());
196
0
        }
197
0
    } else if (emulationEngine.get() == extended) {
198
0
        extended = emulationEngine->real_engine;
199
0
    }
200
0
}
201
202
QPainterPrivate::QPainterPrivate(QPainter *painter)
203
1.39M
    : q_ptr(painter), txinv(0), inDestructor(false)
204
1.39M
{
205
1.39M
}
206
207
1.39M
QPainterPrivate::~QPainterPrivate()
208
    = default;
209
210
QTransform QPainterPrivate::viewTransform() const
211
0
{
212
0
    if (state->VxF) {
213
0
        qreal scaleW = qreal(state->vw)/qreal(state->ww);
214
0
        qreal scaleH = qreal(state->vh)/qreal(state->wh);
215
0
        return QTransform(scaleW, 0, 0, scaleH,
216
0
                          state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
217
0
    }
218
0
    return QTransform();
219
0
}
220
221
qreal QPainterPrivate::effectiveDevicePixelRatio() const
222
1.39M
{
223
    // Special cases for devices that does not support PdmDevicePixelRatio go here:
224
1.39M
    if (device->devType() == QInternal::Printer)
225
0
        return qreal(1);
226
227
1.39M
    return device->devicePixelRatio();
228
1.39M
}
229
230
QTransform QPainterPrivate::hidpiScaleTransform() const
231
0
{
232
0
    const qreal devicePixelRatio = effectiveDevicePixelRatio();
233
0
    return QTransform::fromScale(devicePixelRatio, devicePixelRatio);
234
0
}
235
236
/*
237
   \internal
238
   Returns \c true if using a shared painter; otherwise false.
239
*/
240
bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
241
2.79M
{
242
2.79M
    Q_ASSERT(q);
243
2.79M
    Q_ASSERT(pdev);
244
245
2.79M
    QPainter *sp = pdev->sharedPainter();
246
2.79M
    if (!sp)
247
2.79M
        return false;
248
249
    // Save the current state of the shared painter and assign
250
    // the current d_ptr to the shared painter's d_ptr.
251
0
    sp->save();
252
0
    ++sp->d_ptr->refcount;
253
0
    sp->d_ptr->d_ptrs.push_back(std::move(q->d_ptr));
254
0
    q->d_ptr.reset(sp->d_ptr.get());
255
256
0
    Q_ASSERT(q->d_ptr->state);
257
258
    // Now initialize the painter with correct widget properties.
259
0
    q->d_ptr->initFrom(pdev);
260
0
    QPoint offset;
261
0
    pdev->redirected(&offset);
262
0
    offset += q->d_ptr->engine->coordinateOffset();
263
264
    // Update system rect.
265
0
    q->d_ptr->state->ww = q->d_ptr->state->vw = pdev->width();
266
0
    q->d_ptr->state->wh = q->d_ptr->state->vh = pdev->height();
267
268
    // Update matrix.
269
0
    if (q->d_ptr->state->WxF) {
270
0
        q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
271
0
        q->d_ptr->state->redirectionMatrix *= q->d_ptr->hidpiScaleTransform().inverted();
272
0
        q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
273
0
        q->d_ptr->state->worldMatrix = QTransform();
274
0
        q->d_ptr->state->WxF = false;
275
0
    } else {
276
0
        q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
277
0
    }
278
0
    q->d_ptr->updateMatrix();
279
280
0
    QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
281
0
    if (enginePrivate->currentClipDevice == pdev) {
282
0
        enginePrivate->systemStateChanged();
283
0
        return true;
284
0
    }
285
286
    // Update system transform and clip.
287
0
    enginePrivate->currentClipDevice = pdev;
288
0
    enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
289
0
    return true;
290
0
}
291
292
void QPainterPrivate::detachPainterPrivate(QPainter *q)
293
0
{
294
0
    Q_ASSERT(refcount > 1);
295
0
    Q_ASSERT(q);
296
297
0
    --refcount;
298
0
    auto original = std::move(d_ptrs.back());
299
0
    d_ptrs.pop_back();
300
0
    if (inDestructor) {
301
0
        inDestructor = false;
302
0
        if (original)
303
0
            original->inDestructor = true;
304
0
    } else if (!original) {
305
0
        original = std::make_unique<QPainterPrivate>(q);
306
0
    }
307
308
0
    q->restore();
309
0
    Q_UNUSED(q->d_ptr.release());
310
0
    q->d_ptr = std::move(original);
311
312
0
    if (emulationEngine) {
313
0
        extended = emulationEngine->real_engine;
314
0
        emulationEngine = nullptr;
315
0
    }
316
0
}
317
318
319
void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op)
320
0
{
321
#ifdef QT_DEBUG_DRAW
322
    if constexpr (qt_show_painter_debug_output) {
323
        printf("QPainter::drawHelper\n");
324
    }
325
#endif
326
327
0
    if (originalPath.isEmpty())
328
0
        return;
329
330
0
    QPaintEngine::PaintEngineFeatures gradientStretch =
331
0
        QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
332
0
                                          | QPaintEngine::ObjectBoundingModeGradients);
333
334
0
    const bool mustEmulateObjectBoundingModeGradients = extended
335
0
                                                        || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
336
0
                                                            && !engine->hasFeature(QPaintEngine::PatternTransform));
337
338
0
    if (!(state->emulationSpecifier & ~gradientStretch)
339
0
        && !mustEmulateObjectBoundingModeGradients) {
340
0
        drawStretchedGradient(originalPath, op);
341
0
        return;
342
0
    } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
343
0
        drawOpaqueBackground(originalPath, op);
344
0
        return;
345
0
    }
346
347
0
    Q_Q(QPainter);
348
349
0
    qreal strokeOffsetX = 0, strokeOffsetY = 0;
350
351
0
    QPainterPath path = originalPath * state->matrix;
352
0
    QRectF pathBounds = path.boundingRect();
353
0
    QRectF strokeBounds;
354
0
    bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
355
0
    if (doStroke) {
356
0
        qreal penWidth = state->pen.widthF();
357
0
        if (penWidth == 0) {
358
0
            strokeOffsetX = 1;
359
0
            strokeOffsetY = 1;
360
0
        } else {
361
            // In case of complex xform
362
0
            if (state->matrix.type() > QTransform::TxScale) {
363
0
                QPainterPathStroker stroker;
364
0
                stroker.setWidth(penWidth);
365
0
                stroker.setJoinStyle(state->pen.joinStyle());
366
0
                stroker.setCapStyle(state->pen.capStyle());
367
0
                QPainterPath stroke = stroker.createStroke(originalPath);
368
0
                strokeBounds = (stroke * state->matrix).boundingRect();
369
0
            } else {
370
0
                strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
371
0
                strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
372
0
            }
373
0
        }
374
0
    }
375
376
0
    QRect absPathRect;
377
0
    if (!strokeBounds.isEmpty()) {
378
0
        absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
379
0
    } else {
380
0
        absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
381
0
            .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
382
0
    }
383
384
0
    if (q->hasClipping()) {
385
0
        bool hasPerspectiveTransform = false;
386
0
        for (const QPainterClipInfo &info : std::as_const(state->clipInfo)) {
387
0
            if (info.matrix.type() == QTransform::TxProject) {
388
0
                hasPerspectiveTransform = true;
389
0
                break;
390
0
            }
391
0
        }
392
        // avoid mapping QRegions with perspective transforms
393
0
        if (!hasPerspectiveTransform) {
394
            // The trick with txinv and invMatrix is done in order to
395
            // avoid transforming the clip to logical coordinates, and
396
            // then back to device coordinates. This is a problem with
397
            // QRegion/QRect based clips, since they use integer
398
            // coordinates and converting to/from logical coordinates will
399
            // lose precision.
400
0
            bool old_txinv = txinv;
401
0
            QTransform old_invMatrix = invMatrix;
402
0
            txinv = true;
403
0
            invMatrix = QTransform();
404
0
            QPainterPath clipPath = q->clipPath();
405
0
            QRectF r = clipPath.boundingRect().intersected(absPathRect);
406
0
            absPathRect = r.toAlignedRect();
407
0
            txinv = old_txinv;
408
0
            invMatrix = old_invMatrix;
409
0
        }
410
0
    }
411
412
//     qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
413
//            devMinX, devMinY, device->width(), device->height());
414
//     qDebug() << " - matrix" << state->matrix;
415
//     qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
416
//     qDebug() << " - path.bounds" << path.boundingRect();
417
418
0
    if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
419
0
        return;
420
421
0
    QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
422
0
    image.fill(0);
423
424
0
    QPainter p(&image);
425
426
0
    p.d_ptr->helper_device = helper_device;
427
428
0
    p.setOpacity(state->opacity);
429
0
    p.translate(-absPathRect.x(), -absPathRect.y());
430
0
    p.setTransform(state->matrix, true);
431
0
    p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
432
0
    p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
433
0
    p.setBackground(state->bgBrush);
434
0
    p.setBackgroundMode(state->bgMode);
435
0
    p.setBrushOrigin(state->brushOrigin);
436
437
0
    p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
438
0
    p.setRenderHint(QPainter::SmoothPixmapTransform,
439
0
                    state->renderHints & QPainter::SmoothPixmapTransform);
440
441
0
    p.drawPath(originalPath);
442
443
0
#ifndef QT_NO_DEBUG
444
0
    static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty("QT_PAINT_FALLBACK_OVERLAY");
445
0
    if (do_fallback_overlay) {
446
0
        QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
447
0
        QPainter pt(&block);
448
0
        pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
449
0
        pt.drawLine(0, 0, 8, 8);
450
0
        pt.end();
451
0
        p.resetTransform();
452
0
        p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
453
0
        p.setOpacity(0.5);
454
0
        p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
455
0
    }
456
0
#endif
457
458
0
    p.end();
459
460
0
    q->save();
461
0
    state->matrix = QTransform();
462
0
    if (extended) {
463
0
        extended->transformChanged();
464
0
    } else {
465
0
        state->dirtyFlags |= QPaintEngine::DirtyTransform;
466
0
        updateState(state);
467
0
    }
468
0
    engine->drawImage(absPathRect,
469
0
                 image,
470
0
                 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
471
0
                 Qt::OrderedDither | Qt::OrderedAlphaDither);
472
0
    q->restore();
473
0
}
474
475
void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op)
476
0
{
477
0
    Q_Q(QPainter);
478
479
0
    q->setBackgroundMode(Qt::TransparentMode);
480
481
0
    if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
482
0
        q->fillPath(path, state->bgBrush.color());
483
0
        q->fillPath(path, state->brush);
484
0
    }
485
486
0
    if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
487
0
        q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
488
0
        q->strokePath(path, state->pen);
489
0
    }
490
491
0
    q->setBackgroundMode(Qt::OpaqueMode);
492
0
}
493
494
static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
495
0
{
496
0
    Q_ASSERT(brush.style() >= Qt::LinearGradientPattern
497
0
             && brush.style() <= Qt::ConicalGradientPattern);
498
499
0
    QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
500
0
                              boundingRect.x(), boundingRect.y());
501
502
0
    QGradient g = *brush.gradient();
503
0
    g.setCoordinateMode(QGradient::LogicalMode);
504
505
0
    QBrush b(g);
506
0
    if (brush.gradient()->coordinateMode() == QGradient::ObjectMode)
507
0
        b.setTransform(b.transform() * gradientToUser);
508
0
    else
509
0
        b.setTransform(gradientToUser * b.transform());
510
0
    return b;
511
0
}
512
513
void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperation op)
514
0
{
515
0
    Q_Q(QPainter);
516
517
0
    const qreal sw = helper_device->width();
518
0
    const qreal sh = helper_device->height();
519
520
0
    bool changedPen = false;
521
0
    bool changedBrush = false;
522
0
    bool needsFill = false;
523
524
0
    const QPen pen = state->pen;
525
0
    const QBrush brush = state->brush;
526
527
0
    const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
528
0
    const QGradient::CoordinateMode brushMode = coordinateMode(brush);
529
530
0
    QRectF boundingRect;
531
532
    // Draw the xformed fill if the brush is a stretch gradient.
533
0
    if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
534
0
        if (brushMode == QGradient::StretchToDeviceMode) {
535
0
            q->setPen(Qt::NoPen);
536
0
            changedPen = pen.style() != Qt::NoPen;
537
0
            q->scale(sw, sh);
538
0
            updateState(state);
539
540
0
            const qreal isw = 1.0 / sw;
541
0
            const qreal ish = 1.0 / sh;
542
0
            QTransform inv(isw, 0, 0, ish, 0, 0);
543
0
            engine->drawPath(path * inv);
544
0
            q->scale(isw, ish);
545
0
        } else {
546
0
            needsFill = true;
547
548
0
            if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
549
0
                Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
550
0
                boundingRect = path.boundingRect();
551
0
                q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
552
0
                changedBrush = true;
553
0
            }
554
0
        }
555
0
    }
556
557
0
    if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
558
        // Draw the xformed outline if the pen is a stretch gradient.
559
0
        if (penMode == QGradient::StretchToDeviceMode) {
560
0
            q->setPen(Qt::NoPen);
561
0
            changedPen = true;
562
563
0
            if (needsFill) {
564
0
                updateState(state);
565
0
                engine->drawPath(path);
566
0
            }
567
568
0
            q->scale(sw, sh);
569
0
            q->setBrush(pen.brush());
570
0
            changedBrush = true;
571
0
            updateState(state);
572
573
0
            QPainterPathStroker stroker;
574
0
            stroker.setDashPattern(pen.style());
575
0
            stroker.setWidth(pen.widthF());
576
0
            stroker.setJoinStyle(pen.joinStyle());
577
0
            stroker.setCapStyle(pen.capStyle());
578
0
            stroker.setMiterLimit(pen.miterLimit());
579
0
            QPainterPath stroke = stroker.createStroke(path);
580
581
0
            const qreal isw = 1.0 / sw;
582
0
            const qreal ish = 1.0 / sh;
583
0
            QTransform inv(isw, 0, 0, ish, 0, 0);
584
0
            engine->drawPath(stroke * inv);
585
0
            q->scale(isw, ish);
586
0
        } else {
587
0
            if (!needsFill && brush.style() != Qt::NoBrush) {
588
0
                q->setBrush(Qt::NoBrush);
589
0
                changedBrush = true;
590
0
            }
591
592
0
            if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
593
0
                Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
594
595
                // avoid computing the bounding rect twice
596
0
                if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
597
0
                    boundingRect = path.boundingRect();
598
599
0
                QPen p = pen;
600
0
                p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
601
0
                q->setPen(p);
602
0
                changedPen = true;
603
0
            } else if (changedPen) {
604
0
                q->setPen(pen);
605
0
                changedPen = false;
606
0
            }
607
608
0
            updateState(state);
609
0
            engine->drawPath(path);
610
0
        }
611
0
    } else if (needsFill) {
612
0
        if (pen.style() != Qt::NoPen) {
613
0
            q->setPen(Qt::NoPen);
614
0
            changedPen = true;
615
0
        }
616
617
0
        updateState(state);
618
0
        engine->drawPath(path);
619
0
    }
620
621
0
    if (changedPen)
622
0
        q->setPen(pen);
623
0
    if (changedBrush)
624
0
        q->setBrush(brush);
625
0
}
626
627
628
void QPainterPrivate::updateMatrix()
629
0
{
630
0
    state->matrix = state->WxF ? state->worldMatrix : QTransform();
631
0
    if (state->VxF)
632
0
        state->matrix *= viewTransform();
633
634
0
    txinv = false;                                // no inverted matrix
635
0
    state->matrix *= state->redirectionMatrix;
636
0
    if (extended)
637
0
        extended->transformChanged();
638
0
    else
639
0
        state->dirtyFlags |= QPaintEngine::DirtyTransform;
640
641
0
    state->matrix *= hidpiScaleTransform();
642
643
//     printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
644
//     qDebug() << " --- using matrix" << state->matrix << redirection_offset;
645
0
}
646
647
/*! \internal */
648
void QPainterPrivate::updateInvMatrix()
649
0
{
650
0
    Q_ASSERT(txinv == false);
651
0
    txinv = true;                                // creating inverted matrix
652
0
    invMatrix = state->matrix.inverted();
653
0
}
654
655
extern bool qt_isExtendedRadialGradient(const QBrush &brush);
656
657
void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
658
0
{
659
0
    bool alpha = false;
660
0
    bool linearGradient = false;
661
0
    bool radialGradient = false;
662
0
    bool extendedRadialGradient = false;
663
0
    bool conicalGradient = false;
664
0
    bool patternBrush = false;
665
0
    bool xform = false;
666
0
    bool complexXform = false;
667
668
0
    bool skip = true;
669
670
    // Pen and brush properties (we have to check both if one changes because the
671
    // one that's unchanged can still be in a state which requires emulation)
672
0
    if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
673
        // Check Brush stroke emulation
674
0
        if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
675
0
            s->emulationSpecifier |= QPaintEngine::BrushStroke;
676
0
        else
677
0
            s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
678
679
0
        skip = false;
680
681
0
        QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
682
0
        Qt::BrushStyle brushStyle = qbrush_style(s->brush);
683
0
        Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
684
0
        alpha = (penBrushStyle != Qt::NoBrush
685
0
                 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
686
0
                 && !penBrush.isOpaque())
687
0
                || (brushStyle != Qt::NoBrush
688
0
                    && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
689
0
                    && !s->brush.isOpaque());
690
0
        linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
691
0
                           (brushStyle == Qt::LinearGradientPattern));
692
0
        radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
693
0
                           (brushStyle == Qt::RadialGradientPattern));
694
0
        extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
695
0
        conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
696
0
                            (brushStyle == Qt::ConicalGradientPattern));
697
0
        patternBrush = (((penBrushStyle > Qt::SolidPattern
698
0
                           && penBrushStyle < Qt::LinearGradientPattern)
699
0
                          || penBrushStyle == Qt::TexturePattern) ||
700
0
                         ((brushStyle > Qt::SolidPattern
701
0
                           && brushStyle < Qt::LinearGradientPattern)
702
0
                          || brushStyle == Qt::TexturePattern));
703
704
0
        bool penTextureAlpha = false;
705
0
        if (penBrush.style() == Qt::TexturePattern)
706
0
            penTextureAlpha = qHasPixmapTexture(penBrush)
707
0
                              ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
708
0
                              : penBrush.textureImage().hasAlphaChannel();
709
0
        bool brushTextureAlpha = false;
710
0
        if (s->brush.style() == Qt::TexturePattern) {
711
0
            brushTextureAlpha = qHasPixmapTexture(s->brush)
712
0
                                ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
713
0
                                : s->brush.textureImage().hasAlphaChannel();
714
0
        }
715
0
        if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
716
0
             || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
717
0
            && !engine->hasFeature(QPaintEngine::MaskedBrush))
718
0
            s->emulationSpecifier |= QPaintEngine::MaskedBrush;
719
0
        else
720
0
            s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
721
0
    }
722
723
0
    if (s->state() & (QPaintEngine::DirtyHints
724
0
                      | QPaintEngine::DirtyOpacity
725
0
                      | QPaintEngine::DirtyBackgroundMode)) {
726
0
        skip = false;
727
0
    }
728
729
0
    if (skip)
730
0
        return;
731
732
#if 0
733
    qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
734
           " - alpha: %d\n"
735
           " - linearGradient: %d\n"
736
           " - radialGradient: %d\n"
737
           " - conicalGradient: %d\n"
738
           " - patternBrush: %d\n"
739
           " - hints: %x\n"
740
           " - xform: %d\n",
741
           s,
742
           alpha,
743
           linearGradient,
744
           radialGradient,
745
           conicalGradient,
746
           patternBrush,
747
           uint(s->renderHints),
748
           xform);
749
#endif
750
751
    // XForm properties
752
0
    if (s->state() & QPaintEngine::DirtyTransform) {
753
0
        xform = !s->matrix.isIdentity();
754
0
        complexXform = !s->matrix.isAffine();
755
0
    } else if (s->matrix.type() >= QTransform::TxTranslate) {
756
0
        xform = true;
757
0
        complexXform = !s->matrix.isAffine();
758
0
    }
759
760
0
    const bool brushXform = (s->brush.transform().type() != QTransform::TxNone);
761
0
    const bool penXform = (s->pen.brush().transform().type() != QTransform::TxNone);
762
763
0
    const bool patternXform = patternBrush && (xform || brushXform || penXform);
764
765
    // Check alphablending
766
0
    if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
767
0
        s->emulationSpecifier |= QPaintEngine::AlphaBlend;
768
0
    else
769
0
        s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
770
771
    // Linear gradient emulation
772
0
    if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
773
0
        s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
774
0
    else
775
0
        s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
776
777
    // Radial gradient emulation
778
0
    if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
779
0
        s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
780
0
    else
781
0
        s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
782
783
    // Conical gradient emulation
784
0
    if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
785
0
        s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
786
0
    else
787
0
        s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
788
789
    // Pattern brushes
790
0
    if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
791
0
        s->emulationSpecifier |= QPaintEngine::PatternBrush;
792
0
    else
793
0
        s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
794
795
    // Pattern XForms
796
0
    if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
797
0
        s->emulationSpecifier |= QPaintEngine::PatternTransform;
798
0
    else
799
0
        s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
800
801
    // Primitive XForms
802
0
    if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
803
0
        s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
804
0
    else
805
0
        s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
806
807
    // Perspective XForms
808
0
    if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
809
0
        s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
810
0
    else
811
0
        s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
812
813
    // Constant opacity
814
0
    if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
815
0
        s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
816
0
    else
817
0
        s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
818
819
0
    bool gradientStretch = false;
820
0
    bool objectBoundingMode = false;
821
0
    if (linearGradient || conicalGradient || radialGradient) {
822
0
        QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
823
0
        QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
824
825
0
        gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
826
0
        gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
827
828
0
        objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
829
0
        objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
830
0
    }
831
0
    if (gradientStretch)
832
0
        s->emulationSpecifier |= QGradient_StretchToDevice;
833
0
    else
834
0
        s->emulationSpecifier &= ~QGradient_StretchToDevice;
835
836
0
    if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
837
0
        s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
838
0
    else
839
0
        s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
840
841
    // Opaque backgrounds...
842
0
    if (s->bgMode == Qt::OpaqueMode &&
843
0
        (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
844
0
        s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
845
0
    else
846
0
        s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
847
848
#if 0
849
    //won't be correct either way because the device can already have
850
    // something rendered to it in which case subsequent emulation
851
    // on a fully transparent qimage and then blitting the results
852
    // won't produce correct results
853
    // Blend modes
854
    if (state->composition_mode > QPainter::CompositionMode_Xor &&
855
        !engine->hasFeature(QPaintEngine::BlendModes))
856
        s->emulationSpecifier |= QPaintEngine::BlendModes;
857
    else
858
        s->emulationSpecifier &= ~QPaintEngine::BlendModes;
859
#endif
860
0
}
861
862
void QPainterPrivate::updateStateImpl(QPainterState *newState)
863
0
{
864
    // ### we might have to call QPainter::begin() here...
865
0
    if (!engine->state) {
866
0
        engine->state = newState;
867
0
        engine->setDirty(QPaintEngine::AllDirty);
868
0
    }
869
870
0
    if (engine->state->painter() != newState->painter)
871
        // ### this could break with clip regions vs paths.
872
0
        engine->setDirty(QPaintEngine::AllDirty);
873
874
    // Upon restore, revert all changes since last save
875
0
    else if (engine->state != newState)
876
0
        newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
877
878
    // We need to store all changes made so that restore can deal with them
879
0
    else
880
0
        newState->changeFlags |= newState->dirtyFlags;
881
882
0
    updateEmulationSpecifier(newState);
883
884
    // Unset potential dirty background mode
885
0
    newState->dirtyFlags &= ~(QPaintEngine::DirtyBackgroundMode
886
0
            | QPaintEngine::DirtyBackground);
887
888
0
    engine->state = newState;
889
0
    engine->updateState(*newState);
890
0
    engine->clearDirty(QPaintEngine::AllDirty);
891
892
0
}
893
894
void QPainterPrivate::updateState(QPainterState *newState)
895
1.39M
{
896
897
1.39M
    if (!newState) {
898
1.39M
        engine->state = newState;
899
1.39M
    } else if (newState->state() || engine->state!=newState) {
900
0
        updateStateImpl(newState);
901
0
    }
902
1.39M
}
903
904
/*!
905
    \class QPainter
906
    \brief The QPainter class performs low-level painting on widgets and
907
    other paint devices.
908
909
    \inmodule QtGui
910
    \ingroup painting
911
912
    \reentrant
913
914
    QPainter provides highly optimized functions to do most of the
915
    drawing GUI programs require. It can draw everything from simple
916
    lines to complex shapes like pies and chords. It can also draw
917
    aligned text and pixmaps. Normally, it draws in a "natural"
918
    coordinate system, but it can also do view and world
919
    transformation. QPainter can operate on any object that inherits
920
    the QPaintDevice class.
921
922
    The common use of QPainter is inside a widget's paint event:
923
    Construct and customize (e.g. set the pen or the brush) the
924
    painter. Then draw. Remember to destroy the QPainter object after
925
    drawing. For example:
926
927
    \snippet code/src_gui_painting_qpainter.cpp 0
928
929
    The core functionality of QPainter is drawing, but the class also
930
    provide several functions that allows you to customize QPainter's
931
    settings and its rendering quality, and others that enable
932
    clipping. In addition you can control how different shapes are
933
    merged together by specifying the painter's composition mode.
934
935
    The isActive() function indicates whether the painter is active. A
936
    painter is activated by the begin() function and the constructor
937
    that takes a QPaintDevice argument. The end() function, and the
938
    destructor, deactivates it.
939
940
    Together with the QPaintDevice and QPaintEngine classes, QPainter
941
    form the basis for Qt's paint system. QPainter is the class used
942
    to perform drawing operations. QPaintDevice represents a device
943
    that can be painted on using a QPainter. QPaintEngine provides the
944
    interface that the painter uses to draw onto different types of
945
    devices. If the painter is active, device() returns the paint
946
    device on which the painter paints, and paintEngine() returns the
947
    paint engine that the painter is currently operating on. For more
948
    information, see the \l {Paint System}.
949
950
    Sometimes it is desirable to make someone else paint on an unusual
951
    QPaintDevice. QPainter supports a static function to do this,
952
    setRedirected().
953
954
    \warning When the paintdevice is a widget, QPainter can only be
955
    used inside a paintEvent() function or in a function called by
956
    paintEvent().
957
958
    \section1 Settings
959
960
    There are several settings that you can customize to make QPainter
961
    draw according to your preferences:
962
963
    \list
964
965
    \li font() is the font used for drawing text. If the painter
966
        isActive(), you can retrieve information about the currently set
967
        font, and its metrics, using the fontInfo() and fontMetrics()
968
        functions respectively.
969
970
    \li brush() defines the color or pattern that is used for filling
971
       shapes.
972
973
    \li pen() defines the color or stipple that is used for drawing
974
       lines or boundaries.
975
976
    \li backgroundMode() defines whether there is a background() or
977
       not, i.e it is either Qt::OpaqueMode or Qt::TransparentMode.
978
979
    \li background() only applies when backgroundMode() is \l
980
       Qt::OpaqueMode and pen() is a stipple. In that case, it
981
       describes the color of the background pixels in the stipple.
982
983
    \li brushOrigin() defines the origin of the tiled brushes, normally
984
       the origin of widget's background.
985
986
    \li viewport(), window(), worldTransform() make up the painter's coordinate
987
        transformation system. For more information, see the \l
988
        {Coordinate Transformations} section and the \l {Coordinate
989
        System} documentation.
990
991
    \li hasClipping() tells whether the painter clips at all. (The paint
992
       device clips, too.) If the painter clips, it clips to clipRegion().
993
994
    \li layoutDirection() defines the layout direction used by the
995
       painter when drawing text.
996
997
    \li worldMatrixEnabled() tells whether world transformation is enabled.
998
999
    \li viewTransformEnabled() tells whether view transformation is
1000
        enabled.
1001
1002
    \endlist
1003
1004
    Note that some of these settings mirror settings in some paint
1005
    devices, e.g.  QWidget::font(). The QPainter::begin() function (or
1006
    equivalently the QPainter constructor) copies these attributes
1007
    from the paint device.
1008
1009
    You can at any time save the QPainter's state by calling the
1010
    save() function which saves all the available settings on an
1011
    internal stack. The restore() function pops them back.
1012
1013
    \section1 Drawing
1014
1015
    QPainter provides functions to draw most primitives: drawPoint(),
1016
    drawPoints(), drawLine(), drawRect(), drawRoundedRect(),
1017
    drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(),
1018
    drawPolygon(), drawConvexPolygon() and drawCubicBezier().  The two
1019
    convenience functions, drawRects() and drawLines(), draw the given
1020
    number of rectangles or lines in the given array of \l
1021
    {QRect}{QRects} or \l {QLine}{QLines} using the current pen and
1022
    brush.
1023
1024
    The QPainter class also provides the fillRect() function which
1025
    fills the given QRect, with the given QBrush, and the eraseRect()
1026
    function that erases the area inside the given rectangle.
1027
1028
    All of these functions have both integer and floating point
1029
    versions.
1030
1031
    \table 100%
1032
    \row
1033
    \li \inlineimage qpainter-basicdrawing.png
1034
                     {Basic Drawing application with shape and pen options}
1035
    \li
1036
    \b {Basic Drawing Example}
1037
1038
    The \l {painting/basicdrawing}{Basic Drawing} example shows how to
1039
    display basic graphics primitives in a variety of styles using the
1040
    QPainter class.
1041
1042
    \endtable
1043
1044
    If you need to draw a complex shape, especially if you need to do
1045
    so repeatedly, consider creating a QPainterPath and drawing it
1046
    using drawPath().
1047
1048
    \table 100%
1049
    \row
1050
    \li
1051
    \b {Painter Paths example}
1052
1053
    The QPainterPath class provides a container for painting
1054
    operations, enabling graphical shapes to be constructed and
1055
    reused.
1056
1057
    The \l {painting/painterpaths}{Painter Paths} example shows how
1058
    painter paths can be used to build complex shapes for rendering.
1059
1060
    \li \inlineimage qpainter-painterpaths.png
1061
                     {Painter Paths application with various shapes}
1062
    \endtable
1063
1064
    QPainter also provides the fillPath() function which fills the
1065
    given QPainterPath with the given QBrush, and the strokePath()
1066
    function that draws the outline of the given path (i.e. strokes
1067
    the path).
1068
1069
    See also the \l {painting/deform}{Vector Deformation} example which
1070
    shows how to use advanced vector techniques to draw text using a
1071
    QPainterPath, the \l {painting/gradients}{Gradients} example which shows
1072
    the different types of gradients that are available in Qt, and the \l
1073
    {painting/pathstroke}{Path Stroking} example which shows Qt's built-in
1074
    dash patterns and shows how custom patterns can be used to extend
1075
    the range of available patterns.
1076
1077
    \table
1078
    \header
1079
    \li \l {painting/deform}{Vector Deformation}
1080
    \li \l {painting/gradients}{Gradients}
1081
    \li \l {painting/pathstroke}{Path Stroking}
1082
    \row
1083
    \li \inlineimage qpainter-vectordeformation.png
1084
                     {Vector Deformation application with lens effect}
1085
    \li \inlineimage qpainter-gradients.png {Gradients application}
1086
    \li \inlineimage qpainter-pathstroking.png {Path Stroking application}
1087
    \endtable
1088
1089
    Text drawing is done using drawText(). When you need
1090
    fine-grained positioning, boundingRect() tells you where a given
1091
    drawText() command will draw.
1092
1093
    \section1 Drawing Pixmaps and Images
1094
1095
    There are functions to draw pixmaps/images, namely drawPixmap(),
1096
    drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
1097
    produce the same result, except that drawPixmap() is faster
1098
    on-screen while drawImage() may be faster on a QPrinter or other
1099
    devices.
1100
1101
    There is a drawPicture() function that draws the contents of an
1102
    entire QPicture. The drawPicture() function is the only function
1103
    that disregards all the painter's settings as QPicture has its own
1104
    settings.
1105
1106
    \section2 Drawing High Resolution Versions of Pixmaps and Images
1107
1108
    High resolution versions of pixmaps have a \e{device pixel ratio} value larger
1109
    than 1 (see QImageReader, QPixmap::devicePixelRatio()). Should it match the value
1110
    of the underlying QPaintDevice, it is drawn directly onto the device with no
1111
    additional transformation applied.
1112
1113
    This is for example the case when drawing a QPixmap of 64x64 pixels size with
1114
    a device pixel ratio of 2 onto a high DPI screen which also has
1115
    a device pixel ratio of 2. Note that the pixmap is then effectively 32x32
1116
    pixels in \e{user space}. Code paths in Qt that calculate layout geometry
1117
    based on the pixmap size will use this size. The net effect of this is that
1118
    the pixmap is displayed as high DPI pixmap rather than a large pixmap.
1119
1120
    \section1 Rendering Quality
1121
1122
    To get the optimal rendering result using QPainter, you should use
1123
    the platform independent QImage as paint device; i.e. using QImage
1124
    will ensure that the result has an identical pixel representation
1125
    on any platform.
1126
1127
    The QPainter class also provides a means of controlling the
1128
    rendering quality through its RenderHint enum and the support for
1129
    floating point precision: All the functions for drawing primitives
1130
    have floating point versions.
1131
1132
    \snippet code/src_gui_painting_qpainter.cpp floatBased
1133
1134
    These are often used in combination
1135
    with the \l {RenderHint}{QPainter::Antialiasing} render hint.
1136
1137
    \snippet code/src_gui_painting_qpainter.cpp renderHint
1138
1139
    \table 100%
1140
    \row
1141
    \li Comparing concentric circles with int and float, and with or without
1142
        anti-aliased rendering. Using the floating point precision versions
1143
        produces evenly spaced rings. Anti-aliased rendering results in
1144
        smooth circles.
1145
    \li \inlineimage qpainter-concentriccircles.png
1146
                     {Concentric circles comparing aliased and antialiased}
1147
    \endtable
1148
1149
    The RenderHint enum specifies flags to QPainter that may or may
1150
    not be respected by any given engine.  \l
1151
    {RenderHint}{QPainter::Antialiasing} indicates that the engine
1152
    should antialias edges of primitives if possible, \l
1153
    {RenderHint}{QPainter::TextAntialiasing} indicates that the engine
1154
    should antialias text if possible, and the \l
1155
    {RenderHint}{QPainter::SmoothPixmapTransform} indicates that the
1156
    engine should use a smooth pixmap transformation algorithm.
1157
1158
    The renderHints() function returns a flag that specifies the
1159
    rendering hints that are set for this painter.  Use the
1160
    setRenderHint() function to set or clear the currently set
1161
    RenderHints.
1162
1163
    \section1 Coordinate Transformations
1164
1165
    Normally, the QPainter operates on the device's own coordinate
1166
    system (usually pixels), but QPainter has good support for
1167
    coordinate transformations.
1168
1169
    \table
1170
    \header
1171
    \li  nop \li rotate() \li scale() \li translate()
1172
    \row
1173
    \li \inlineimage qpainter-clock.png {Clock without transformation}
1174
    \li \inlineimage qpainter-rotation.png {Clock with rotation applied}
1175
    \li \inlineimage qpainter-scale.png {Clock with scale applied}
1176
    \li \inlineimage qpainter-translation.png {Clock with translation applied}
1177
    \endtable
1178
1179
    The most commonly used transformations are scaling, rotation,
1180
    translation and shearing. Use the scale() function to scale the
1181
    coordinate system by a given offset, the rotate() function to
1182
    rotate it clockwise and translate() to translate it (i.e. adding a
1183
    given offset to the points). You can also twist the coordinate
1184
    system around the origin using the shear() function. See the \l
1185
    {painting/affine}{Affine Transformations} example for a visualization of
1186
    a sheared coordinate system.
1187
1188
    See also the \l {painting/transformations}{Transformations}
1189
    example which shows how transformations influence the way that
1190
    QPainter renders graphics primitives. In particular it shows how
1191
    the order of transformations affects the result.
1192
1193
    \table 100%
1194
    \row
1195
    \li
1196
    \b {Affine Transformations Example}
1197
1198
    The \l {painting/affine}{Affine Transformations} example shows Qt's
1199
    ability to perform affine transformations on painting
1200
    operations. The demo also allows the user to experiment with the
1201
    transformation operations and see the results immediately.
1202
1203
    \li \inlineimage qpainter-affinetransformations.png
1204
        {Affine Transformations example with penguin graphic}
1205
    \endtable
1206
1207
    All the transformation operations operate on the transformation
1208
    worldTransform(). A matrix transforms a point in the plane to another
1209
    point. For more information about the transformation matrix, see
1210
    the \l {Coordinate System} and QTransform documentation.
1211
1212
    The setWorldTransform() function can replace or add to the currently
1213
    set worldTransform(). The resetTransform() function resets any
1214
    transformations that were made using translate(), scale(),
1215
    shear(), rotate(), setWorldTransform(), setViewport() and setWindow()
1216
    functions. The deviceTransform() returns the matrix that transforms
1217
    from logical coordinates to device coordinates of the platform
1218
    dependent paint device. The latter function is only needed when
1219
    using platform painting commands on the platform dependent handle,
1220
    and the platform does not do transformations nativly.
1221
1222
    When drawing with QPainter, we specify points using logical
1223
    coordinates which then are converted into the physical coordinates
1224
    of the paint device. The mapping of the logical coordinates to the
1225
    physical coordinates are handled by QPainter's combinedTransform(), a
1226
    combination of viewport() and window() and worldTransform(). The
1227
    viewport() represents the physical coordinates specifying an
1228
    arbitrary rectangle, the window() describes the same rectangle in
1229
    logical coordinates, and the worldTransform() is identical with the
1230
    transformation matrix.
1231
1232
    See also \l {Coordinate System}
1233
1234
    \section1 Clipping
1235
1236
    QPainter can clip any drawing operation to a rectangle, a region,
1237
    or a vector path. The current clip is available using the
1238
    functions clipRegion() and clipPath(). Whether paths or regions are
1239
    preferred (faster) depends on the underlying paintEngine(). For
1240
    example, the QImage paint engine prefers paths while the X11 paint
1241
    engine prefers regions. Setting a clip is done in the painters
1242
    logical coordinates.
1243
1244
    After QPainter's clipping, the paint device may also clip. For
1245
    example, most widgets clip away the pixels used by child widgets,
1246
    and most printers clip away an area near the edges of the paper.
1247
    This additional clipping is not reflected by the return value of
1248
    clipRegion() or hasClipping().
1249
1250
    \section1 Composition Modes
1251
    \target Composition Modes
1252
1253
    QPainter provides the CompositionMode enum which defines the
1254
    Porter-Duff rules for digital image compositing; it describes a
1255
    model for combining the pixels in one image, the source, with the
1256
    pixels in another image, the destination.
1257
1258
    The two most common forms of composition are \l
1259
    {QPainter::CompositionMode}{Source} and \l
1260
    {QPainter::CompositionMode}{SourceOver}.  \l
1261
    {QPainter::CompositionMode}{Source} is used to draw opaque objects
1262
    onto a paint device. In this mode, each pixel in the source
1263
    replaces the corresponding pixel in the destination. In \l
1264
    {QPainter::CompositionMode}{SourceOver} composition mode, the
1265
    source object is transparent and is drawn on top of the
1266
    destination.
1267
1268
    Note that composition transformation operates pixelwise. For that
1269
    reason, there is a difference between using the graphic primitive
1270
    itself and its bounding rectangle: The bounding rect contains
1271
    pixels with alpha == 0 (i.e the pixels surrounding the
1272
    primitive). These pixels will overwrite the other image's pixels,
1273
    effectively clearing those, while the primitive only overwrites
1274
    its own area.
1275
1276
    \table 100%
1277
    \row
1278
    \li \inlineimage qpainter-compositiondemo.png
1279
        {Composition Modes example with blended images}
1280
1281
    \li
1282
    \b {Composition Modes Example}
1283
1284
    The \l {painting/composition}{Composition Modes} example, available in
1285
    Qt's examples directory, allows you to experiment with the various
1286
    composition modes and see the results immediately.
1287
1288
    \endtable
1289
1290
    \section1 Limitations
1291
    \target Limitations
1292
1293
    If you are using coordinates with Qt's raster-based paint engine, it is
1294
    important to note that, while coordinates greater than +/- 2\sup 15 can
1295
    be used, any painting performed with coordinates outside this range is not
1296
    guaranteed to be shown; the drawing may be clipped. This is due to the
1297
    use of \c{short int} in the implementation.
1298
1299
    The outlines generated by Qt's stroker are only an approximation when dealing
1300
    with curved shapes. It is in most cases impossible to represent the outline of
1301
    a bezier curve segment using another bezier curve segment, and so Qt approximates
1302
    the curve outlines by using several smaller curves. For performance reasons there
1303
    is a limit to how many curves Qt uses for these outlines, and thus when using
1304
    large pen widths or scales the outline error increases. To generate outlines with
1305
    smaller errors it is possible to use the QPainterPathStroker class, which has the
1306
    setCurveThreshold member function which let's the user specify the error tolerance.
1307
    Another workaround is to convert the paths to polygons first and then draw the
1308
    polygons instead.
1309
1310
    Qt likewise approximates arcs and ellipses with cubic Bezier curves instead
1311
    of evaluating them trigonometrically, so points on an arc are slightly off
1312
    their true positions. Related to this, the angles that \l{drawArc()},
1313
    \l{drawPie()}, and \l{drawChord()} take are eccentric angles: they measure
1314
    the direction from the center of the bounding rectangle only when that
1315
    rectangle is square. See \l{QPainterPath#Arcs and Ellipses}{Arcs and
1316
    Ellipses} for details on both.
1317
1318
    \section1 Performance
1319
1320
    QPainter is a rich framework that allows developers to do a great
1321
    variety of graphical operations, such as gradients, composition
1322
    modes and vector graphics. And QPainter can do this across a
1323
    variety of different hardware and software stacks. Naturally the
1324
    underlying combination of hardware and software has some
1325
    implications for performance, and ensuring that every single
1326
    operation is fast in combination with all the various combinations
1327
    of composition modes, brushes, clipping, transformation, etc, is
1328
    close to an impossible task because of the number of
1329
    permutations. As a compromise we have selected a subset of the
1330
    QPainter API and backends, where performance is guaranteed to be as
1331
    good as we can sensibly get it for the given combination of
1332
    hardware and software.
1333
1334
    The backends we focus on as high-performance engines are:
1335
1336
    \list
1337
1338
    \li Raster - This backend implements all rendering in pure software
1339
    and is always used to render into QImages. For optimal performance
1340
    only use the format types QImage::Format_ARGB32_Premultiplied,
1341
    QImage::Format_RGB32 or QImage::Format_RGB16. Any other format,
1342
    including QImage::Format_ARGB32, has significantly worse
1343
    performance. This engine is used by default for QWidget and QPixmap.
1344
1345
    \li OpenGL 2.0 (ES) - This backend is the primary backend for
1346
    hardware accelerated graphics. It can be run on desktop machines
1347
    and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0
1348
    specification. This includes most graphics chips produced in the
1349
    last couple of years. The engine can be enabled by using QPainter
1350
    onto a QOpenGLWidget.
1351
1352
    \endlist
1353
1354
    These operations are:
1355
1356
    \list
1357
1358
    \li Simple transformations, meaning translation and scaling, pluss
1359
    0, 90, 180, 270 degree rotations.
1360
1361
    \li \c drawPixmap() in combination with simple transformations and
1362
    opacity with non-smooth transformation mode
1363
    (\c QPainter::SmoothPixmapTransform not enabled as a render hint).
1364
1365
    \li Rectangle fills with solid color, two-color linear gradients
1366
    and simple transforms.
1367
1368
    \li Rectangular clipping with simple transformations and intersect
1369
    clip.
1370
1371
    \li Composition Modes \c QPainter::CompositionMode_Source and
1372
    QPainter::CompositionMode_SourceOver.
1373
1374
    \li Rounded rectangle filling using solid color and two-color
1375
    linear gradients fills.
1376
1377
    \li 3x3 patched pixmaps, via qDrawBorderPixmap.
1378
1379
    \endlist
1380
1381
    This list gives an indication of which features to safely use in
1382
    an application where performance is critical. For certain setups,
1383
    other operations may be fast too, but before making extensive use
1384
    of them, it is recommended to benchmark and verify them on the
1385
    system where the software will run in the end. There are also
1386
    cases where expensive operations are ok to use, for instance when
1387
    the result is cached in a QPixmap.
1388
1389
    \sa QPaintDevice, QPaintEngine, {Qt SVG}, {Basic Drawing Example}, {<qdrawutil.h>}{Drawing Utility Functions}
1390
*/
1391
1392
/*!
1393
    \enum QPainter::RenderHint
1394
1395
    Renderhints are used to specify flags to QPainter that may or
1396
    may not be respected by any given engine.
1397
1398
    \value Antialiasing Indicates that the engine should antialias
1399
    edges of primitives if possible.
1400
1401
    \value TextAntialiasing Indicates that the engine should antialias
1402
    text if possible. To forcibly disable antialiasing for text, do not
1403
    use this hint. Instead, set QFont::NoAntialias on your font's style
1404
    strategy.
1405
1406
    \value SmoothPixmapTransform Indicates that the engine should use
1407
    a smooth pixmap transformation algorithm (such as bilinear) rather
1408
    than nearest neighbor.
1409
1410
    \value VerticalSubpixelPositioning Allow text to be positioned at fractions
1411
    of pixels vertically as well as horizontally, if this is supported by the
1412
    font engine. This is currently supported by Freetype on all platforms when
1413
    the hinting preference is QFont::PreferNoHinting, and also on macOS. For
1414
    most use cases this will not improve visual quality, but may increase memory
1415
    consumption and some reduction in text rendering performance. Therefore, enabling
1416
    this is not recommended unless the use case requires it. One such use case could
1417
    be aligning glyphs with other visual primitives.
1418
    This value was added in Qt 6.1.
1419
1420
    \value LosslessImageRendering Use a lossless image rendering, whenever possible.
1421
    Currently, this hint is only used when QPainter is employed to output a PDF
1422
    file through QPrinter or QPdfWriter, where drawImage()/drawPixmap() calls
1423
    will encode images using a lossless compression algorithm instead of lossy
1424
    JPEG compression.
1425
    This value was added in Qt 5.13.
1426
1427
    \value NonCosmeticBrushPatterns When painting with a brush with one of the predefined pattern
1428
    styles, transform the pattern too, along with the object being painted. The default is to treat
1429
    the pattern as cosmetic, so that the pattern pixels will map directly to device pixels,
1430
    independently of any active transformations.
1431
    This value was added in Qt 6.4.
1432
1433
    \sa renderHints(), setRenderHint(), {QPainter#Rendering
1434
    Quality}{Rendering Quality}
1435
1436
*/
1437
1438
/*!
1439
    Constructs a painter.
1440
1441
    \sa begin(), end()
1442
*/
1443
1444
QPainter::QPainter()
1445
0
    : d_ptr(new QPainterPrivate(this))
1446
0
{
1447
0
}
1448
1449
/*!
1450
    \fn QPainter::QPainter(QPaintDevice *device)
1451
1452
    Constructs a painter that begins painting the paint \a device
1453
    immediately.
1454
1455
    This constructor is convenient for short-lived painters, e.g. in a
1456
    QWidget::paintEvent() and should be used only once. The
1457
    constructor calls begin() for you and the QPainter destructor
1458
    automatically calls end().
1459
1460
    Here's an example using begin() and end():
1461
    \snippet code/src_gui_painting_qpainter.cpp 1
1462
1463
    The same example using this constructor:
1464
    \snippet code/src_gui_painting_qpainter.cpp 2
1465
1466
    Since the constructor cannot provide feedback when the initialization
1467
    of the painter failed you should rather use begin() and end() to paint
1468
    on external devices, e.g. printers.
1469
1470
    \sa begin(), end()
1471
*/
1472
1473
QPainter::QPainter(QPaintDevice *pd)
1474
1.39M
    : d_ptr(nullptr)
1475
1.39M
{
1476
1.39M
    Q_ASSERT(pd != nullptr);
1477
1.39M
    if (!QPainterPrivate::attachPainterPrivate(this, pd)) {
1478
1.39M
        d_ptr.reset(new QPainterPrivate(this));
1479
1.39M
        begin(pd);
1480
1.39M
    }
1481
1.39M
    Q_ASSERT(d_ptr);
1482
1.39M
}
1483
1484
/*!
1485
    Destroys the painter.
1486
*/
1487
QPainter::~QPainter()
1488
1.39M
{
1489
1.39M
    d_ptr->inDestructor = true;
1490
1.39M
    QT_TRY {
1491
1.39M
        if (isActive())
1492
1.39M
            end();
1493
983
        else if (d_ptr->refcount > 1)
1494
0
            d_ptr->detachPainterPrivate(this);
1495
1.39M
    } QT_CATCH(...) {
1496
        // don't throw anything in the destructor.
1497
0
    }
1498
1.39M
    if (d_ptr) {
1499
        // Make sure we haven't messed things up.
1500
1.39M
        Q_ASSERT(d_ptr->inDestructor);
1501
1.39M
        d_ptr->inDestructor = false;
1502
1.39M
        Q_ASSERT(d_ptr->refcount == 1);
1503
1.39M
        Q_ASSERT(d_ptr->d_ptrs.empty());
1504
1.39M
    }
1505
1.39M
}
1506
1507
/*!
1508
    Returns the paint device on which this painter is currently
1509
    painting, or \nullptr if the painter is not active.
1510
1511
    \sa isActive()
1512
*/
1513
1514
QPaintDevice *QPainter::device() const
1515
1.39M
{
1516
1.39M
    Q_D(const QPainter);
1517
1.39M
    if (isActive() && d->engine->d_func()->currentClipDevice)
1518
0
        return d->engine->d_func()->currentClipDevice;
1519
1.39M
    return d->original_device;
1520
1.39M
}
1521
1522
/*!
1523
    Returns \c true if begin() has been called and end() has not yet been
1524
    called; otherwise returns \c false.
1525
1526
    \sa begin(), QPaintDevice::paintingActive()
1527
*/
1528
1529
bool QPainter::isActive() const
1530
2.79M
{
1531
2.79M
    Q_D(const QPainter);
1532
2.79M
    return d->engine != nullptr;
1533
2.79M
}
1534
1535
void QPainterPrivate::initFrom(const QPaintDevice *device)
1536
1.39M
{
1537
1.39M
    if (!engine) {
1538
0
        qWarning("QPainter::initFrom: Painter not active, aborted");
1539
0
        return;
1540
0
    }
1541
1542
1.39M
    Q_Q(QPainter);
1543
1.39M
    device->initPainter(q);
1544
1.39M
}
1545
1546
void QPainterPrivate::setEngineDirtyFlags(QSpan<const QPaintEngine::DirtyFlags> flags)
1547
0
{
1548
0
    if (!engine)
1549
0
        return;
1550
0
    for (const QPaintEngine::DirtyFlags f : flags)
1551
0
        engine->setDirty(f);
1552
0
}
1553
1554
/*!
1555
    Saves the current painter state (pushes the state onto a stack). A
1556
    save() must be followed by a corresponding restore(); the end()
1557
    function unwinds the stack.
1558
1559
    \sa restore()
1560
*/
1561
1562
void QPainter::save()
1563
0
{
1564
#ifdef QT_DEBUG_DRAW
1565
    if constexpr (qt_show_painter_debug_output)
1566
        printf("QPainter::save()\n");
1567
#endif
1568
0
    Q_D(QPainter);
1569
0
    if (!d->engine) {
1570
0
        qWarning("QPainter::save: Painter not active");
1571
0
        return;
1572
0
    }
1573
1574
0
    std::unique_ptr<QPainterState> prev;
1575
0
    if (d->extended) {
1576
        // separate the creation of a new state from the update of d->state, since some
1577
        // engines access d->state directly (not via createState()'s argument)
1578
0
        std::unique_ptr<QPainterState> next(d->extended->createState(d->state.get()));
1579
0
        prev = std::exchange(d->state, std::move(next));
1580
0
        d->extended->setState(d->state.get());
1581
0
    } else {
1582
0
        d->updateState(d->state);
1583
0
        prev = std::exchange(d->state, std::make_unique<QPainterState>(d->state.get()));
1584
0
        d->engine->state = d->state.get();
1585
0
    }
1586
0
    d->savedStates.push(std::move(prev));
1587
0
}
1588
1589
/*!
1590
    Restores the current painter state (pops a saved state off the
1591
    stack).
1592
1593
    \sa save()
1594
*/
1595
1596
void QPainter::restore()
1597
0
{
1598
#ifdef QT_DEBUG_DRAW
1599
    if constexpr (qt_show_painter_debug_output)
1600
        printf("QPainter::restore()\n");
1601
#endif
1602
0
    Q_D(QPainter);
1603
0
    if (d->savedStates.empty()) {
1604
0
        qWarning("QPainter::restore: Unbalanced save/restore");
1605
0
        return;
1606
0
    } else if (!d->engine) {
1607
0
        qWarning("QPainter::restore: Painter not active");
1608
0
        return;
1609
0
    }
1610
1611
0
    const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
1612
0
    d->savedStates.pop();
1613
0
    d->txinv = false;
1614
1615
0
    if (d->extended) {
1616
0
        d->checkEmulation();
1617
0
        d->extended->setState(d->state.get());
1618
0
        return;
1619
0
    }
1620
1621
    // trigger clip update if the clip path/region has changed since
1622
    // last save
1623
0
    if (!d->state->clipInfo.isEmpty()
1624
0
        && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1625
        // reuse the tmp state to avoid any extra allocs...
1626
0
        tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1627
0
        tmp->clipOperation = Qt::NoClip;
1628
0
        tmp->clipPath = QPainterPath();
1629
0
        d->engine->updateState(*tmp);
1630
        // replay the list of clip states,
1631
0
        for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
1632
0
            tmp->matrix = info.matrix;
1633
0
            tmp->clipOperation = info.operation;
1634
0
            if (info.clipType == QPainterClipInfo::RectClip) {
1635
0
                tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1636
0
                tmp->clipRegion = info.rect;
1637
0
            } else if (info.clipType == QPainterClipInfo::RegionClip) {
1638
0
                tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1639
0
                tmp->clipRegion = info.region;
1640
0
            } else { // clipType == QPainterClipInfo::PathClip
1641
0
                tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
1642
0
                tmp->clipPath = info.path;
1643
0
            }
1644
0
            d->engine->updateState(*tmp);
1645
0
        }
1646
1647
1648
        //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
1649
0
        d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1650
0
        tmp->changeFlags &= ~uint(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1651
0
        tmp->changeFlags |= QPaintEngine::DirtyTransform;
1652
0
    }
1653
1654
0
    d->updateState(d->state.get());
1655
0
}
1656
1657
1658
/*!
1659
1660
    \fn bool QPainter::begin(QPaintDevice *device)
1661
1662
    Begins painting the paint \a device and returns \c true if
1663
    successful; otherwise returns \c false.
1664
1665
    Notice that all painter settings (setPen(), setBrush() etc.) are reset
1666
    to default values when begin() is called.
1667
1668
    The errors that can occur are serious problems, such as these:
1669
1670
    \snippet code/src_gui_painting_qpainter.cpp 3
1671
1672
    Note that most of the time, you can use one of the constructors
1673
    instead of begin(), and that end() is automatically done at
1674
    destruction.
1675
1676
    \warning A paint device can only be painted by one painter at a
1677
    time.
1678
1679
    \warning Painting on a QImage with the format
1680
    QImage::Format_Indexed8 is not supported.
1681
1682
    \sa end(), QPainter()
1683
*/
1684
1685
static inline void qt_cleanup_painter_state(QPainterPrivate *d)
1686
1.39M
{
1687
1.39M
    d->savedStates.clear();
1688
1.39M
    d->state = nullptr;
1689
1.39M
    d->engine = nullptr;
1690
1.39M
    d->device = nullptr;
1691
1.39M
}
1692
1693
bool QPainter::begin(QPaintDevice *pd)
1694
1.39M
{
1695
1.39M
    Q_ASSERT(pd);
1696
1697
1.39M
    if (pd->painters > 0) {
1698
0
        qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
1699
0
        return false;
1700
0
    }
1701
1702
1.39M
    if (d_ptr->engine) {
1703
0
        qWarning("QPainter::begin: Painter already active");
1704
0
        return false;
1705
0
    }
1706
1707
1.39M
    if (QPainterPrivate::attachPainterPrivate(this, pd))
1708
0
        return true;
1709
1710
1.39M
    Q_D(QPainter);
1711
1712
1.39M
    d->helper_device = pd;
1713
1.39M
    d->original_device = pd;
1714
1715
1.39M
    QPoint redirectionOffset;
1716
1.39M
    QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1717
1.39M
    if (rpd)
1718
0
        pd = rpd;
1719
1720
#ifdef QT_DEBUG_DRAW
1721
    if constexpr (qt_show_painter_debug_output)
1722
        printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1723
#endif
1724
1725
1.39M
    if (pd->devType() == QInternal::Pixmap)
1726
0
        static_cast<QPixmap *>(pd)->detach();
1727
1.39M
    else if (pd->devType() == QInternal::Image)
1728
1.39M
        static_cast<QImage *>(pd)->detach();
1729
1730
1.39M
    d->engine.reset(pd->paintEngine());
1731
1732
1.39M
    if (!d->engine) {
1733
963
        qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1734
963
        return false;
1735
963
    }
1736
1737
1.39M
    d->device = pd;
1738
1739
1.39M
    d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine.get()) : nullptr;
1740
1.39M
    if (d->emulationEngine)
1741
0
        d->emulationEngine->real_engine = d->extended;
1742
1743
    // Setup new state...
1744
1.39M
    Q_ASSERT(!d->state);
1745
1.39M
    d->state.reset(d->extended ? d->extended->createState(nullptr) : new QPainterState);
1746
1.39M
    d->state->painter = this;
1747
1748
1.39M
    d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1749
1.39M
    d->state->brushOrigin = QPointF();
1750
1751
    // Slip a painter state into the engine before we do any other operations
1752
1.39M
    if (d->extended)
1753
1.39M
        d->extended->setState(d->state.get());
1754
0
    else
1755
0
        d->engine->state = d->state.get();
1756
1757
1.39M
    switch (pd->devType()) {
1758
0
        case QInternal::Pixmap:
1759
0
        {
1760
0
            QPixmap *pm = static_cast<QPixmap *>(pd);
1761
0
            Q_ASSERT(pm);
1762
0
            if (pm->isNull()) {
1763
0
                qWarning("QPainter::begin: Cannot paint on a null pixmap");
1764
0
                qt_cleanup_painter_state(d);
1765
0
                return false;
1766
0
            }
1767
1768
0
            if (pm->depth() == 1) {
1769
0
                d->state->pen = QPen(Qt::color1);
1770
0
                d->state->brush = QBrush(Qt::color0);
1771
0
            }
1772
0
            break;
1773
0
        }
1774
1.39M
        case QInternal::Image:
1775
1.39M
        {
1776
1.39M
            QImage *img = static_cast<QImage *>(pd);
1777
1.39M
            Q_ASSERT(img);
1778
1.39M
            if (img->isNull()) {
1779
0
                qWarning("QPainter::begin: Cannot paint on a null image");
1780
0
                qt_cleanup_painter_state(d);
1781
0
                return false;
1782
1.39M
            } else if (img->format() == QImage::Format_Indexed8 ||
1783
1.39M
                       img->format() == QImage::Format_CMYK8888) {
1784
                // Painting on these formats is not supported.
1785
20
                qWarning() << "QPainter::begin: Cannot paint on an image with the"
1786
20
                           << img->format()
1787
20
                           << "format";
1788
20
                qt_cleanup_painter_state(d);
1789
20
                return false;
1790
20
            }
1791
1.39M
            if (img->depth() == 1) {
1792
0
                d->state->pen = QPen(Qt::color1);
1793
0
                d->state->brush = QBrush(Qt::color0);
1794
0
            }
1795
1.39M
            break;
1796
1.39M
        }
1797
0
        default:
1798
0
            break;
1799
1.39M
    }
1800
1.39M
    if (d->state->ww == 0) // For compat with 3.x painter defaults
1801
1.39M
        d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1802
1803
1.39M
    d->engine->setPaintDevice(pd);
1804
1805
1.39M
    bool begun = d->engine->begin(pd);
1806
1.39M
    if (!begun) {
1807
0
        qWarning("QPainter::begin(): Returned false");
1808
0
        if (d->engine->isActive()) {
1809
0
            end();
1810
0
        } else {
1811
0
            qt_cleanup_painter_state(d);
1812
0
        }
1813
0
        return false;
1814
1.39M
    } else {
1815
1.39M
        d->engine->setActive(begun);
1816
1.39M
    }
1817
1818
1.39M
    switch (d->original_device->devType()) {
1819
0
    case QInternal::Widget:
1820
0
        d->initFrom(d->original_device);
1821
0
        break;
1822
1823
1.39M
    default:
1824
1.39M
        d->state->layoutDirection = Qt::LayoutDirectionAuto;
1825
        // make sure we have a font compatible with the paintdevice
1826
1.39M
        d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1827
1.39M
        break;
1828
1.39M
    }
1829
1830
1.39M
    QRect systemRect = d->engine->systemRect();
1831
1.39M
    if (!systemRect.isEmpty()) {
1832
0
        d->state->ww = d->state->vw = systemRect.width();
1833
0
        d->state->wh = d->state->vh = systemRect.height();
1834
1.39M
    } else {
1835
1.39M
        d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1836
1.39M
        d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1837
1.39M
    }
1838
1839
1.39M
    const QPoint coordinateOffset = d->engine->coordinateOffset();
1840
1.39M
    d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1841
1842
1.39M
    Q_ASSERT(d->engine->isActive());
1843
1844
1.39M
    if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
1845
0
        d->updateMatrix();
1846
1847
1.39M
    Q_ASSERT(d->engine->isActive());
1848
1.39M
    d->state->renderHints = QPainter::TextAntialiasing;
1849
1.39M
    ++d->device->painters;
1850
1851
1.39M
    d->state->emulationSpecifier = 0;
1852
1853
1.39M
    switch (d->original_device->devType()) {
1854
0
    case QInternal::Widget:
1855
        // for widgets we've aleady initialized the painter above
1856
0
        break;
1857
1.39M
    default:
1858
1.39M
        d->initFrom(d->original_device);
1859
1.39M
        break;
1860
1.39M
    }
1861
1862
1.39M
    return true;
1863
1.39M
}
1864
1865
/*!
1866
    Ends painting. Any resources used while painting are released. You
1867
    don't normally need to call this since it is called by the
1868
    destructor.
1869
1870
    Returns \c true if the painter is no longer active; otherwise returns \c false.
1871
1872
    \sa begin(), isActive()
1873
*/
1874
1875
bool QPainter::end()
1876
1.39M
{
1877
#ifdef QT_DEBUG_DRAW
1878
    if constexpr (qt_show_painter_debug_output)
1879
        printf("QPainter::end()\n");
1880
#endif
1881
1.39M
    Q_D(QPainter);
1882
1883
1.39M
    if (!d->engine) {
1884
0
        qWarning("QPainter::end: Painter not active, aborted");
1885
0
        qt_cleanup_painter_state(d);
1886
0
        return false;
1887
0
    }
1888
1889
1.39M
    if (d->refcount > 1) {
1890
0
        d->detachPainterPrivate(this);
1891
0
        return true;
1892
0
    }
1893
1894
1.39M
    bool ended = true;
1895
1896
1.39M
    if (d->engine->isActive()) {
1897
1.39M
        ended = d->engine->end();
1898
1.39M
        d->updateState(nullptr);
1899
1900
1.39M
        --d->device->painters;
1901
1.39M
        if (d->device->painters == 0) {
1902
1.39M
            d->engine->setPaintDevice(nullptr);
1903
1.39M
            d->engine->setActive(false);
1904
1.39M
        }
1905
1.39M
    }
1906
1907
1.39M
    if (d->savedStates.size() > 0) {
1908
0
        qWarning("QPainter::end: Painter ended with %d saved states", int(d->savedStates.size()));
1909
0
    }
1910
1911
1.39M
    d->engine.reset();
1912
1.39M
    d->emulationEngine = nullptr;
1913
1.39M
    d->extended = nullptr;
1914
1915
1.39M
    qt_cleanup_painter_state(d);
1916
1917
1.39M
    return ended;
1918
1.39M
}
1919
1920
1921
/*!
1922
    Returns the paint engine that the painter is currently operating
1923
    on if the painter is active; otherwise 0.
1924
1925
    \sa isActive()
1926
*/
1927
QPaintEngine *QPainter::paintEngine() const
1928
0
{
1929
0
    Q_D(const QPainter);
1930
0
    return d->engine.get();
1931
0
}
1932
1933
/*!
1934
    \since 4.6
1935
1936
    Flushes the painting pipeline and prepares for the user issuing commands
1937
    directly to the underlying graphics context. Must be followed by a call to
1938
    endNativePainting().
1939
1940
    Note that only the states the underlying paint engine changes will be reset
1941
    to their respective default states. The states we reset may change from
1942
    release to release. The following states are currently reset in the OpenGL
1943
    2 engine:
1944
1945
    \list
1946
    \li blending is disabled
1947
    \li the depth, stencil and scissor tests are disabled
1948
    \li the active texture unit is reset to 0
1949
    \li the depth mask, depth function and the clear depth are reset to their
1950
    default values
1951
    \li the stencil mask, stencil operation and stencil function are reset to
1952
    their default values
1953
     \li the current color is reset to solid white
1954
    \endlist
1955
1956
    If, for example, the OpenGL polygon mode is changed by the user inside a
1957
    beginNativePaint()/endNativePainting() block, it will not be reset to the
1958
    default state by endNativePainting(). Here is an example that shows
1959
    intermixing of painter commands and raw OpenGL commands:
1960
1961
    \snippet code/src_gui_painting_qpainter.cpp 21
1962
1963
    \sa endNativePainting()
1964
*/
1965
void QPainter::beginNativePainting()
1966
0
{
1967
0
    Q_D(QPainter);
1968
0
    if (!d->engine) {
1969
0
        qWarning("QPainter::beginNativePainting: Painter not active");
1970
0
        return;
1971
0
    }
1972
1973
0
    if (d->extended)
1974
0
        d->extended->beginNativePainting();
1975
0
}
1976
1977
/*!
1978
    \since 4.6
1979
1980
    Restores the painter after manually issuing native painting commands. Lets
1981
    the painter restore any native state that it relies on before calling any
1982
    other painter commands.
1983
1984
    \sa beginNativePainting()
1985
*/
1986
void QPainter::endNativePainting()
1987
0
{
1988
0
    Q_D(const QPainter);
1989
0
    if (!d->engine) {
1990
0
        qWarning("QPainter::beginNativePainting: Painter not active");
1991
0
        return;
1992
0
    }
1993
1994
0
    if (d->extended)
1995
0
        d->extended->endNativePainting();
1996
0
    else
1997
0
        d->engine->syncState();
1998
0
}
1999
2000
/*!
2001
    Returns the font metrics for the painter if the painter is
2002
    active. Otherwise, the return value is undefined.
2003
2004
    \sa font(), isActive(), {QPainter#Settings}{Settings}
2005
*/
2006
2007
QFontMetrics QPainter::fontMetrics() const
2008
0
{
2009
0
    Q_D(const QPainter);
2010
0
    if (!d->engine) {
2011
0
        qWarning("QPainter::fontMetrics: Painter not active");
2012
0
        return QFontMetrics(QFont());
2013
0
    }
2014
0
    return QFontMetrics(d->state->font);
2015
0
}
2016
2017
2018
/*!
2019
    Returns the font info for the painter if the painter is
2020
    active. Otherwise, the return value is undefined.
2021
2022
    \sa font(), isActive(), {QPainter#Settings}{Settings}
2023
*/
2024
2025
QFontInfo QPainter::fontInfo() const
2026
0
{
2027
0
    Q_D(const QPainter);
2028
0
    if (!d->engine) {
2029
0
        qWarning("QPainter::fontInfo: Painter not active");
2030
0
        return QFontInfo(QFont());
2031
0
    }
2032
0
    return QFontInfo(d->state->font);
2033
0
}
2034
2035
/*!
2036
    \since 4.2
2037
2038
    Returns the opacity of the painter. The default value is
2039
    1.
2040
*/
2041
2042
qreal QPainter::opacity() const
2043
0
{
2044
0
    Q_D(const QPainter);
2045
0
    if (!d->engine) {
2046
0
        qWarning("QPainter::opacity: Painter not active");
2047
0
        return 1.0;
2048
0
    }
2049
0
    return d->state->opacity;
2050
0
}
2051
2052
/*!
2053
    \since 4.2
2054
2055
    Sets the opacity of the painter to \a opacity. The value should
2056
    be in the range 0.0 to 1.0, where 0.0 is fully transparent and
2057
    1.0 is fully opaque.
2058
2059
    The opacity set on the painter applies to each drawing operation
2060
    separately. Filling a shape and drawing its outline are treated
2061
    as separate drawing operations.
2062
*/
2063
2064
void QPainter::setOpacity(qreal opacity)
2065
1.39M
{
2066
1.39M
    Q_D(QPainter);
2067
2068
1.39M
    if (!d->engine) {
2069
983
        qWarning("QPainter::setOpacity: Painter not active");
2070
983
        return;
2071
983
    }
2072
2073
1.39M
    opacity = qMin(qreal(1), qMax(qreal(0), opacity));
2074
2075
1.39M
    if (opacity == d->state->opacity)
2076
1.10M
        return;
2077
2078
295k
    d->state->opacity = opacity;
2079
2080
295k
    if (d->extended)
2081
295k
        d->extended->opacityChanged();
2082
0
    else
2083
0
        d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
2084
295k
}
2085
2086
2087
/*!
2088
    Returns the current brush origin.
2089
    Prefer using QPainter::brushOriginF() to get the precise origin.
2090
2091
    \sa setBrushOrigin(), {QPainter#Settings}{Settings}
2092
*/
2093
2094
QPoint QPainter::brushOrigin() const
2095
0
{
2096
0
    Q_D(const QPainter);
2097
0
    if (!d->engine) {
2098
0
        qWarning("QPainter::brushOrigin: Painter not active");
2099
0
        return QPoint();
2100
0
    }
2101
0
    return QPointF(d->state->brushOrigin).toPoint();
2102
0
}
2103
2104
/*!
2105
    Returns the current brush origin.
2106
2107
    \sa setBrushOrigin(), {QPainter#Settings}{Settings}
2108
    \since 6.11
2109
*/
2110
2111
QPointF QPainter::brushOriginF() const
2112
0
{
2113
0
    Q_D(const QPainter);
2114
0
    if (!d->engine) {
2115
0
        qWarning("QPainter::brushOrigin: Painter not active");
2116
0
        return QPointF();
2117
0
    }
2118
0
    return d->state->brushOrigin;
2119
0
}
2120
2121
/*!
2122
    \fn void QPainter::setBrushOrigin(const QPointF &position)
2123
2124
    Sets the brush origin to \a position.
2125
2126
    The brush origin specifies the (0, 0) coordinate of the painter's
2127
    brush.
2128
2129
    Note that while the brushOrigin() was necessary to adopt the
2130
    parent's background for a widget in Qt 3, this is no longer the
2131
    case since the Qt 4 painter doesn't paint the background unless
2132
    you explicitly tell it to do so by setting the widget's \l
2133
    {QWidget::autoFillBackground}{autoFillBackground} property to
2134
    true.
2135
2136
    \sa brushOrigin(), {QPainter#Settings}{Settings}
2137
*/
2138
2139
void QPainter::setBrushOrigin(const QPointF &p)
2140
0
{
2141
0
    Q_D(QPainter);
2142
#ifdef QT_DEBUG_DRAW
2143
    if constexpr (qt_show_painter_debug_output)
2144
        printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
2145
#endif
2146
2147
0
    if (!d->engine) {
2148
0
        qWarning("QPainter::setBrushOrigin: Painter not active");
2149
0
        return;
2150
0
    }
2151
2152
0
    d->state->brushOrigin = p;
2153
2154
0
    if (d->extended) {
2155
0
        d->extended->brushOriginChanged();
2156
0
        return;
2157
0
    }
2158
2159
0
    d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
2160
0
}
2161
2162
/*!
2163
    \fn void QPainter::setBrushOrigin(const QPoint &position)
2164
    \overload
2165
2166
    Sets the brush's origin to the given \a position.
2167
*/
2168
2169
/*!
2170
    \fn void QPainter::setBrushOrigin(int x, int y)
2171
2172
    \overload
2173
2174
    Sets the brush's origin to point (\a x, \a y).
2175
*/
2176
2177
/*!
2178
    \enum QPainter::CompositionMode
2179
2180
    Defines the modes supported for digital image compositing.
2181
    Composition modes are used to specify how the pixels in one image,
2182
    the source, are merged with the pixel in another image, the
2183
    destination.
2184
2185
    Please note that the bitwise raster operation modes, denoted with
2186
    a RasterOp prefix, are only natively supported in the X11 and
2187
    raster paint engines. This means that the only way to utilize
2188
    these modes on the Mac is via a QImage. The RasterOp denoted blend
2189
    modes are \e not supported for pens and brushes with alpha
2190
    components. Also, turning on the QPainter::Antialiasing render
2191
    hint will effectively disable the RasterOp modes.
2192
2193
2194
     \image qpainter-compositionmode1.png {Illustration showing Source,
2195
            Destination, SourceOver, DestinationOver, SourceIn,
2196
            DestinationIn composition modes}
2197
     \image qpainter-compositionmode2.png {Illustration showing SourceOut,
2198
            DestinationOut, SourceAtop, DestinationAtop, Clear and Xor
2199
            composition modes}
2200
2201
    The most common type is SourceOver (often referred to as just
2202
    alpha blending) where the source pixel is blended on top of the
2203
    destination pixel in such a way that the alpha component of the
2204
    source defines the translucency of the pixel.
2205
2206
    Several composition modes require an alpha channel in the source or
2207
    target images to have an effect. For optimal performance the
2208
    image format \l {QImage::Format}{Format_ARGB32_Premultiplied} is
2209
    preferred.
2210
2211
    When a composition mode is set it applies to all painting
2212
    operator, pens, brushes, gradients and pixmap/image drawing.
2213
2214
    \value CompositionMode_SourceOver This is the default mode. The
2215
    alpha of the source is used to blend the pixel on top of the
2216
    destination.
2217
2218
    \value CompositionMode_DestinationOver The alpha of the
2219
    destination is used to blend it on top of the source pixels. This
2220
    mode is the inverse of CompositionMode_SourceOver.
2221
2222
    \value CompositionMode_Clear The pixels in the destination are
2223
    cleared (set to fully transparent) independent of the source.
2224
2225
    \value CompositionMode_Source The output is the source
2226
    pixel. (This means a basic copy operation and is identical to
2227
    SourceOver when the source pixel is opaque).
2228
2229
    \value CompositionMode_Destination The output is the destination
2230
    pixel. This means that the blending has no effect. This mode is
2231
    the inverse of CompositionMode_Source.
2232
2233
    \value CompositionMode_SourceIn The output is the source, where
2234
    the alpha is reduced by that of the destination.
2235
2236
    \value CompositionMode_DestinationIn The output is the
2237
    destination, where the alpha is reduced by that of the
2238
    source. This mode is the inverse of CompositionMode_SourceIn.
2239
2240
    \value CompositionMode_SourceOut The output is the source, where
2241
    the alpha is reduced by the inverse of destination.
2242
2243
    \value CompositionMode_DestinationOut The output is the
2244
    destination, where the alpha is reduced by the inverse of the
2245
    source. This mode is the inverse of CompositionMode_SourceOut.
2246
2247
    \value CompositionMode_SourceAtop The source pixel is blended on
2248
    top of the destination, with the alpha of the source pixel reduced
2249
    by the alpha of the destination pixel.
2250
2251
    \value CompositionMode_DestinationAtop The destination pixel is
2252
    blended on top of the source, with the alpha of the destination
2253
    pixel is reduced by the alpha of the destination pixel. This mode
2254
    is the inverse of CompositionMode_SourceAtop.
2255
2256
    \value CompositionMode_Xor The source, whose alpha is reduced with
2257
    the inverse of the destination alpha, is merged with the
2258
    destination, whose alpha is reduced by the inverse of the source
2259
    alpha. CompositionMode_Xor is not the same as the bitwise Xor.
2260
2261
    \value CompositionMode_Plus Both the alpha and color of the source
2262
    and destination pixels are added together.
2263
2264
    \value CompositionMode_Multiply The output is the source color
2265
    multiplied by the destination. Multiplying a color with white
2266
    leaves the color unchanged, while multiplying a color
2267
    with black produces black.
2268
2269
    \value CompositionMode_Screen The source and destination colors
2270
    are inverted and then multiplied. Screening a color with white
2271
    produces white, whereas screening a color with black leaves the
2272
    color unchanged.
2273
2274
    \value CompositionMode_Overlay Multiplies or screens the colors
2275
    depending on the destination color. The destination color is mixed
2276
    with the source color to reflect the lightness or darkness of the
2277
    destination.
2278
2279
    \value CompositionMode_Darken The darker of the source and
2280
    destination colors is selected.
2281
2282
    \value CompositionMode_Lighten The lighter of the source and
2283
    destination colors is selected.
2284
2285
    \value CompositionMode_ColorDodge The destination color is
2286
    brightened to reflect the source color. A black source color
2287
    leaves the destination color unchanged.
2288
2289
    \value CompositionMode_ColorBurn The destination color is darkened
2290
    to reflect the source color. A white source color leaves the
2291
    destination color unchanged.
2292
2293
    \value CompositionMode_HardLight Multiplies or screens the colors
2294
    depending on the source color. A light source color will lighten
2295
    the destination color, whereas a dark source color will darken the
2296
    destination color.
2297
2298
    \value CompositionMode_SoftLight Darkens or lightens the colors
2299
    depending on the source color. Similar to
2300
    CompositionMode_HardLight.
2301
2302
    \value CompositionMode_Difference Subtracts the darker of the
2303
    colors from the lighter.  Painting with white inverts the
2304
    destination color, whereas painting with black leaves the
2305
    destination color unchanged.
2306
2307
    \value CompositionMode_Exclusion Similar to
2308
    CompositionMode_Difference, but with a lower contrast. Painting
2309
    with white inverts the destination color, whereas painting with
2310
    black leaves the destination color unchanged.
2311
2312
    \value RasterOp_SourceOrDestination Does a bitwise OR operation on
2313
    the source and destination pixels (src OR dst).
2314
2315
    \value RasterOp_SourceAndDestination Does a bitwise AND operation
2316
    on the source and destination pixels (src AND dst).
2317
2318
    \value RasterOp_SourceXorDestination Does a bitwise XOR operation
2319
    on the source and destination pixels (src XOR dst).
2320
2321
    \value RasterOp_NotSourceAndNotDestination Does a bitwise NOR
2322
    operation on the source and destination pixels ((NOT src) AND (NOT
2323
    dst)).
2324
2325
    \value RasterOp_NotSourceOrNotDestination Does a bitwise NAND
2326
    operation on the source and destination pixels ((NOT src) OR (NOT
2327
    dst)).
2328
2329
    \value RasterOp_NotSourceXorDestination Does a bitwise operation
2330
    where the source pixels are inverted and then XOR'ed with the
2331
    destination ((NOT src) XOR dst).
2332
2333
    \value RasterOp_NotSource Does a bitwise operation where the
2334
    source pixels are inverted (NOT src).
2335
2336
    \value RasterOp_NotSourceAndDestination Does a bitwise operation
2337
    where the source is inverted and then AND'ed with the destination
2338
    ((NOT src) AND dst).
2339
2340
    \value RasterOp_SourceAndNotDestination Does a bitwise operation
2341
    where the source is AND'ed with the inverted destination pixels
2342
    (src AND (NOT dst)).
2343
2344
    \value RasterOp_NotSourceOrDestination Does a bitwise operation
2345
    where the source is inverted and then OR'ed with the destination
2346
    ((NOT src) OR dst).
2347
2348
    \value RasterOp_ClearDestination The pixels in the destination are
2349
    cleared (set to 0) independent of the source.
2350
2351
    \value RasterOp_SetDestination The pixels in the destination are
2352
    set (set to 1) independent of the source.
2353
2354
    \value RasterOp_NotDestination Does a bitwise operation
2355
    where the destination pixels are inverted (NOT dst).
2356
2357
    \value RasterOp_SourceOrNotDestination Does a bitwise operation
2358
    where the source is OR'ed with the inverted destination pixels
2359
    (src OR (NOT dst)).
2360
2361
    \omitvalue NCompositionModes
2362
2363
    \sa compositionMode(), setCompositionMode(), {QPainter#Composition
2364
    Modes}{Composition Modes}, {Image Composition Example}
2365
*/
2366
2367
/*!
2368
    Sets the composition mode to the given \a mode.
2369
2370
    \warning Only a QPainter operating on a QImage fully supports all
2371
    composition modes. The RasterOp modes are supported for X11 as
2372
    described in compositionMode().
2373
2374
    \sa compositionMode()
2375
*/
2376
void QPainter::setCompositionMode(CompositionMode mode)
2377
1.39M
{
2378
1.39M
    Q_D(QPainter);
2379
1.39M
    if (!d->engine) {
2380
983
        qWarning("QPainter::setCompositionMode: Painter not active");
2381
983
        return;
2382
983
    }
2383
1.39M
    if (mode < 0 || mode >= CompositionMode::NCompositionModes) {
2384
0
        qWarning("QPainter::setCompositionMode: Invalid mode");
2385
0
        return;
2386
0
    }
2387
1.39M
    if (d->state->composition_mode == mode)
2388
3.84k
        return;
2389
1.39M
    if (d->extended) {
2390
1.39M
        d->state->composition_mode = mode;
2391
1.39M
        d->extended->compositionModeChanged();
2392
1.39M
        return;
2393
1.39M
    }
2394
2395
0
    if (mode >= QPainter::RasterOp_SourceOrDestination) {
2396
0
        if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
2397
0
            qWarning("QPainter::setCompositionMode: "
2398
0
                     "Raster operation modes not supported on device");
2399
0
            return;
2400
0
        }
2401
0
    } else if (mode >= QPainter::CompositionMode_Plus) {
2402
0
        if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
2403
0
            qWarning("QPainter::setCompositionMode: "
2404
0
                     "Blend modes not supported on device");
2405
0
            return;
2406
0
        }
2407
0
    } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
2408
0
        if (mode != CompositionMode_Source && mode != CompositionMode_SourceOver) {
2409
0
            qWarning("QPainter::setCompositionMode: "
2410
0
                     "PorterDuff modes not supported on device");
2411
0
            return;
2412
0
        }
2413
0
    }
2414
2415
0
    d->state->composition_mode = mode;
2416
0
    d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
2417
0
}
2418
2419
/*!
2420
  Returns the current composition mode.
2421
2422
  \sa CompositionMode, setCompositionMode()
2423
*/
2424
QPainter::CompositionMode QPainter::compositionMode() const
2425
0
{
2426
0
    Q_D(const QPainter);
2427
0
    if (!d->engine) {
2428
0
        qWarning("QPainter::compositionMode: Painter not active");
2429
0
        return QPainter::CompositionMode_SourceOver;
2430
0
    }
2431
0
    return d->state->composition_mode;
2432
0
}
2433
2434
/*!
2435
    Returns the current background brush.
2436
2437
    \sa setBackground(), {QPainter#Settings}{Settings}
2438
*/
2439
2440
const QBrush &QPainter::background() const
2441
0
{
2442
0
    Q_D(const QPainter);
2443
0
    if (!d->engine) {
2444
0
        qWarning("QPainter::background: Painter not active");
2445
0
        return d->fakeState()->brush;
2446
0
    }
2447
0
    return d->state->bgBrush;
2448
0
}
2449
2450
2451
/*!
2452
    Returns \c true if clipping has been set; otherwise returns \c false.
2453
2454
    \sa setClipping(), {QPainter#Clipping}{Clipping}
2455
*/
2456
2457
bool QPainter::hasClipping() const
2458
0
{
2459
0
    Q_D(const QPainter);
2460
0
    if (!d->engine) {
2461
0
        qWarning("QPainter::hasClipping: Painter not active");
2462
0
        return false;
2463
0
    }
2464
0
    return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
2465
0
}
2466
2467
2468
/*!
2469
    Enables clipping if  \a enable is true, or disables clipping if  \a
2470
    enable is false.
2471
2472
    \sa hasClipping(), {QPainter#Clipping}{Clipping}
2473
*/
2474
2475
void QPainter::setClipping(bool enable)
2476
0
{
2477
0
    Q_D(QPainter);
2478
#ifdef QT_DEBUG_DRAW
2479
    if constexpr (qt_show_painter_debug_output)
2480
        printf("QPainter::setClipping(), enable=%s, was=%s\n",
2481
               enable ? "on" : "off",
2482
               hasClipping() ? "on" : "off");
2483
#endif
2484
0
    if (!d->engine) {
2485
0
        qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
2486
0
        return;
2487
0
    }
2488
2489
0
    if (hasClipping() == enable)
2490
0
        return;
2491
2492
    // we can't enable clipping if we don't have a clip
2493
0
    if (enable
2494
0
        && (d->state->clipInfo.isEmpty() || d->state->clipInfo.constLast().operation == Qt::NoClip))
2495
0
        return;
2496
0
    d->state->clipEnabled = enable;
2497
2498
0
    if (d->extended) {
2499
0
        d->extended->clipEnabledChanged();
2500
0
        return;
2501
0
    }
2502
2503
0
    d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
2504
0
    d->updateState(d->state);
2505
0
}
2506
2507
2508
/*!
2509
    Returns the currently set clip region. Note that the clip region
2510
    is given in logical coordinates.
2511
2512
    \warning QPainter does not store the combined clip explicitly as
2513
    this is handled by the underlying QPaintEngine, so the path is
2514
    recreated on demand and transformed to the current logical
2515
    coordinate system. This is potentially an expensive operation.
2516
2517
    \sa setClipRegion(), clipPath(), setClipping()
2518
*/
2519
2520
QRegion QPainter::clipRegion() const
2521
0
{
2522
0
    Q_D(const QPainter);
2523
0
    if (!d->engine) {
2524
0
        qWarning("QPainter::clipRegion: Painter not active");
2525
0
        return QRegion();
2526
0
    }
2527
2528
0
    QRegion region;
2529
0
    bool lastWasNothing = true;
2530
2531
0
    if (!d->txinv)
2532
0
        const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2533
2534
    // ### Falcon: Use QPainterPath
2535
0
    for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2536
0
        switch (info.clipType) {
2537
2538
0
        case QPainterClipInfo::RegionClip: {
2539
0
            QTransform matrix = (info.matrix * d->invMatrix);
2540
0
            if (lastWasNothing) {
2541
0
                region = info.region * matrix;
2542
0
                lastWasNothing = false;
2543
0
                continue;
2544
0
            }
2545
0
            if (info.operation == Qt::IntersectClip)
2546
0
                region &= info.region * matrix;
2547
0
            else if (info.operation == Qt::NoClip) {
2548
0
                lastWasNothing = true;
2549
0
                region = QRegion();
2550
0
            } else
2551
0
                region = info.region * matrix;
2552
0
            break;
2553
0
        }
2554
2555
0
        case QPainterClipInfo::PathClip: {
2556
0
            QTransform matrix = (info.matrix * d->invMatrix);
2557
0
            if (lastWasNothing) {
2558
0
                region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2559
0
                                 info.path.fillRule());
2560
0
                lastWasNothing = false;
2561
0
                continue;
2562
0
            }
2563
0
            if (info.operation == Qt::IntersectClip) {
2564
0
                region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2565
0
                                  info.path.fillRule());
2566
0
            } else if (info.operation == Qt::NoClip) {
2567
0
                lastWasNothing = true;
2568
0
                region = QRegion();
2569
0
            } else {
2570
0
                region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2571
0
                                 info.path.fillRule());
2572
0
            }
2573
0
            break;
2574
0
        }
2575
2576
0
        case QPainterClipInfo::RectClip: {
2577
0
            QTransform matrix = (info.matrix * d->invMatrix);
2578
0
            if (lastWasNothing) {
2579
0
                region = QRegion(info.rect) * matrix;
2580
0
                lastWasNothing = false;
2581
0
                continue;
2582
0
            }
2583
0
            if (info.operation == Qt::IntersectClip) {
2584
                // Use rect intersection if possible.
2585
0
                if (matrix.type() <= QTransform::TxScale)
2586
0
                    region &= matrix.mapRect(info.rect);
2587
0
                else
2588
0
                    region &= matrix.map(QRegion(info.rect));
2589
0
            } else if (info.operation == Qt::NoClip) {
2590
0
                lastWasNothing = true;
2591
0
                region = QRegion();
2592
0
            } else {
2593
0
                region = QRegion(info.rect) * matrix;
2594
0
            }
2595
0
            break;
2596
0
        }
2597
2598
0
        case QPainterClipInfo::RectFClip: {
2599
0
            QTransform matrix = (info.matrix * d->invMatrix);
2600
0
            if (lastWasNothing) {
2601
0
                region = QRegion(info.rectf.toRect()) * matrix;
2602
0
                lastWasNothing = false;
2603
0
                continue;
2604
0
            }
2605
0
            if (info.operation == Qt::IntersectClip) {
2606
                // Use rect intersection if possible.
2607
0
                if (matrix.type() <= QTransform::TxScale)
2608
0
                    region &= matrix.mapRect(info.rectf.toRect());
2609
0
                else
2610
0
                    region &= matrix.map(QRegion(info.rectf.toRect()));
2611
0
            } else if (info.operation == Qt::NoClip) {
2612
0
                lastWasNothing = true;
2613
0
                region = QRegion();
2614
0
            } else {
2615
0
                region = QRegion(info.rectf.toRect()) * matrix;
2616
0
            }
2617
0
            break;
2618
0
        }
2619
0
        }
2620
0
    }
2621
2622
0
    return region;
2623
0
}
2624
2625
Q_GUI_EXPORT extern QPainterPath qt_regionToPath(const QRegion &region);
2626
2627
/*!
2628
    Returns the current clip path in logical coordinates.
2629
2630
    \warning QPainter does not store the combined clip explicitly as
2631
    this is handled by the underlying QPaintEngine, so the path is
2632
    recreated on demand and transformed to the current logical
2633
    coordinate system. This is potentially an expensive operation.
2634
2635
    \sa setClipPath(), clipRegion(), setClipping()
2636
*/
2637
QPainterPath QPainter::clipPath() const
2638
0
{
2639
0
    Q_D(const QPainter);
2640
2641
    // ### Since we do not support path intersections and path unions yet,
2642
    // we just use clipRegion() here...
2643
0
    if (!d->engine) {
2644
0
        qWarning("QPainter::clipPath: Painter not active");
2645
0
        return QPainterPath();
2646
0
    }
2647
2648
    // No clip, return empty
2649
0
    if (d->state->clipInfo.isEmpty()) {
2650
0
        return QPainterPath();
2651
0
    } else {
2652
2653
        // Update inverse matrix, used below.
2654
0
        if (!d->txinv)
2655
0
            const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2656
2657
        // For the simple case avoid conversion.
2658
0
        if (d->state->clipInfo.size() == 1
2659
0
            && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
2660
0
            QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2661
0
            return d->state->clipInfo.at(0).path * matrix;
2662
2663
0
        } else if (d->state->clipInfo.size() == 1
2664
0
                   && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
2665
0
            QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2666
0
            QPainterPath path;
2667
0
            path.addRect(d->state->clipInfo.at(0).rect);
2668
0
            return path * matrix;
2669
0
        } else {
2670
            // Fallback to clipRegion() for now, since we don't have isect/unite for paths
2671
0
            return qt_regionToPath(clipRegion());
2672
0
        }
2673
0
    }
2674
0
}
2675
2676
/*!
2677
    Returns the bounding rectangle of the current clip if there is a clip;
2678
    otherwise returns an empty rectangle. Note that the clip region is
2679
    given in logical coordinates.
2680
2681
    The bounding rectangle is not guaranteed to be tight.
2682
2683
    \sa setClipRect(), setClipPath(), setClipRegion()
2684
2685
    \since 4.8
2686
 */
2687
2688
QRectF QPainter::clipBoundingRect() const
2689
0
{
2690
0
    Q_D(const QPainter);
2691
2692
0
    if (!d->engine) {
2693
0
        qWarning("QPainter::clipBoundingRect: Painter not active");
2694
0
        return QRectF();
2695
0
    }
2696
2697
    // Accumulate the bounding box in device space. This is not 100%
2698
    // precise, but it fits within the guarantee and it is reasonably
2699
    // fast.
2700
0
    QRectF bounds;
2701
0
    bool first = true;
2702
0
    for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2703
0
         QRectF r;
2704
2705
0
         if (info.clipType == QPainterClipInfo::RectClip)
2706
0
             r = info.rect;
2707
0
         else if (info.clipType == QPainterClipInfo::RectFClip)
2708
0
             r = info.rectf;
2709
0
         else if (info.clipType == QPainterClipInfo::RegionClip)
2710
0
             r = info.region.boundingRect();
2711
0
         else
2712
0
             r = info.path.boundingRect();
2713
2714
0
         r = info.matrix.mapRect(r);
2715
2716
0
         if (first)
2717
0
             bounds = r;
2718
0
         else if (info.operation == Qt::IntersectClip)
2719
0
             bounds &= r;
2720
0
         first = false;
2721
0
    }
2722
2723
2724
    // Map the rectangle back into logical space using the inverse
2725
    // matrix.
2726
0
    if (!d->txinv)
2727
0
        const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2728
2729
0
    return d->invMatrix.mapRect(bounds);
2730
0
}
2731
2732
/*!
2733
    \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
2734
2735
    Enables clipping, and sets the clip region to the given \a
2736
    rectangle using the given clip \a operation. The default operation
2737
    is to replace the current clip rectangle.
2738
2739
    Note that the clip rectangle is specified in logical (painter)
2740
    coordinates.
2741
2742
    \sa clipRegion(), setClipping(), {QPainter#Clipping}{Clipping}
2743
*/
2744
void QPainter::setClipRect(const QRectF &rect, Qt::ClipOperation op)
2745
0
{
2746
0
    Q_D(QPainter);
2747
2748
0
    if (d->extended) {
2749
0
        if (!d->engine) {
2750
0
            qWarning("QPainter::setClipRect: Painter not active");
2751
0
            return;
2752
0
        }
2753
0
        bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2754
0
        if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2755
0
            op = Qt::ReplaceClip;
2756
2757
0
        qreal right = rect.x() + rect.width();
2758
0
        qreal bottom = rect.y() + rect.height();
2759
0
        qreal pts[] = { rect.x(), rect.y(),
2760
0
                        right, rect.y(),
2761
0
                        right, bottom,
2762
0
                        rect.x(), bottom };
2763
0
        QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
2764
0
        d->state->clipEnabled = true;
2765
0
        d->extended->clip(vp, op);
2766
0
        if (op == Qt::ReplaceClip || op == Qt::NoClip)
2767
0
            d->state->clipInfo.clear();
2768
0
        d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2769
0
        d->state->clipOperation = op;
2770
0
        return;
2771
0
    }
2772
2773
0
    if (qreal(int(rect.top())) == rect.top()
2774
0
        && qreal(int(rect.bottom())) == rect.bottom()
2775
0
        && qreal(int(rect.left())) == rect.left()
2776
0
        && qreal(int(rect.right())) == rect.right())
2777
0
    {
2778
0
        setClipRect(rect.toRect(), op);
2779
0
        return;
2780
0
    }
2781
2782
0
    if (rect.isEmpty()) {
2783
0
        setClipRegion(QRegion(), op);
2784
0
        return;
2785
0
    }
2786
2787
0
    QPainterPath path;
2788
0
    path.addRect(rect);
2789
0
    setClipPath(path, op);
2790
0
}
2791
2792
/*!
2793
    \fn void QPainter::setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
2794
    \overload
2795
2796
    Enables clipping, and sets the clip region to the given \a rectangle using the given
2797
    clip \a operation.
2798
*/
2799
void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
2800
0
{
2801
0
    Q_D(QPainter);
2802
2803
0
    if (!d->engine) {
2804
0
        qWarning("QPainter::setClipRect: Painter not active");
2805
0
        return;
2806
0
    }
2807
0
    bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2808
2809
0
    if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2810
0
        op = Qt::ReplaceClip;
2811
2812
0
    if (d->extended) {
2813
0
        d->state->clipEnabled = true;
2814
0
        d->extended->clip(rect, op);
2815
0
        if (op == Qt::ReplaceClip || op == Qt::NoClip)
2816
0
            d->state->clipInfo.clear();
2817
0
        d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2818
0
        d->state->clipOperation = op;
2819
0
        return;
2820
0
    }
2821
2822
0
    if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2823
0
        op = Qt::ReplaceClip;
2824
2825
0
    d->state->clipRegion = rect;
2826
0
    d->state->clipOperation = op;
2827
0
    if (op == Qt::NoClip || op == Qt::ReplaceClip)
2828
0
        d->state->clipInfo.clear();
2829
0
    d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2830
0
    d->state->clipEnabled = true;
2831
0
    d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2832
0
    d->updateState(d->state);
2833
0
}
2834
2835
/*!
2836
    \fn void QPainter::setClipRect(int x, int y, int width, int height, Qt::ClipOperation operation)
2837
2838
    Enables clipping, and sets the clip region to the rectangle beginning at (\a x, \a y)
2839
    with the given \a width and \a height.
2840
*/
2841
2842
/*!
2843
    \fn void QPainter::setClipRegion(const QRegion &region, Qt::ClipOperation operation)
2844
2845
    Sets the clip region to the given \a region using the specified clip
2846
    \a operation. The default clip operation is to replace the current
2847
    clip region.
2848
2849
    Note that the clip region is given in logical coordinates.
2850
2851
    \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
2852
*/
2853
void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
2854
0
{
2855
0
    Q_D(QPainter);
2856
#ifdef QT_DEBUG_DRAW
2857
    QRect rect = r.boundingRect();
2858
    if constexpr (qt_show_painter_debug_output)
2859
        printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2860
           r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2861
#endif
2862
0
    if (!d->engine) {
2863
0
        qWarning("QPainter::setClipRegion: Painter not active");
2864
0
        return;
2865
0
    }
2866
0
    bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2867
2868
0
    if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2869
0
        op = Qt::ReplaceClip;
2870
2871
0
    if (d->extended) {
2872
0
        d->state->clipEnabled = true;
2873
0
        d->extended->clip(r, op);
2874
0
        if (op == Qt::NoClip || op == Qt::ReplaceClip)
2875
0
            d->state->clipInfo.clear();
2876
0
        d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2877
0
        d->state->clipOperation = op;
2878
0
        return;
2879
0
    }
2880
2881
0
    if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2882
0
        op = Qt::ReplaceClip;
2883
2884
0
    d->state->clipRegion = r;
2885
0
    d->state->clipOperation = op;
2886
0
    if (op == Qt::NoClip || op == Qt::ReplaceClip)
2887
0
        d->state->clipInfo.clear();
2888
0
    d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2889
0
    d->state->clipEnabled = true;
2890
0
    d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2891
0
    d->updateState(d->state);
2892
0
}
2893
2894
/*!
2895
    \since 4.2
2896
2897
    Enables transformations if \a enable is true, or disables
2898
    transformations if \a enable is false. The world transformation
2899
    matrix is not changed.
2900
2901
    \sa worldMatrixEnabled(), worldTransform(), {QPainter#Coordinate
2902
    Transformations}{Coordinate Transformations}
2903
*/
2904
2905
void QPainter::setWorldMatrixEnabled(bool enable)
2906
0
{
2907
0
    Q_D(QPainter);
2908
#ifdef QT_DEBUG_DRAW
2909
    if constexpr (qt_show_painter_debug_output)
2910
        printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
2911
#endif
2912
2913
0
    if (!d->engine) {
2914
0
        qWarning("QPainter::setMatrixEnabled: Painter not active");
2915
0
        return;
2916
0
    }
2917
0
    if (enable == d->state->WxF)
2918
0
        return;
2919
2920
0
    d->state->WxF = enable;
2921
0
    d->updateMatrix();
2922
0
}
2923
2924
/*!
2925
    \since 4.2
2926
2927
    Returns \c true if world transformation is enabled; otherwise returns
2928
    false.
2929
2930
    \sa setWorldMatrixEnabled(), worldTransform(), {Coordinate System}
2931
*/
2932
2933
bool QPainter::worldMatrixEnabled() const
2934
0
{
2935
0
    Q_D(const QPainter);
2936
0
    if (!d->engine) {
2937
0
        qWarning("QPainter::worldMatrixEnabled: Painter not active");
2938
0
        return false;
2939
0
    }
2940
0
    return d->state->WxF;
2941
0
}
2942
2943
/*!
2944
    Scales the coordinate system by (\a{sx}, \a{sy}).
2945
2946
    \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
2947
*/
2948
2949
void QPainter::scale(qreal sx, qreal sy)
2950
0
{
2951
#ifdef QT_DEBUG_DRAW
2952
    if constexpr (qt_show_painter_debug_output)
2953
        printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
2954
#endif
2955
0
    Q_D(QPainter);
2956
0
    if (!d->engine) {
2957
0
        qWarning("QPainter::scale: Painter not active");
2958
0
        return;
2959
0
    }
2960
2961
0
    d->state->worldMatrix.scale(sx,sy);
2962
0
    d->state->WxF = true;
2963
0
    d->updateMatrix();
2964
0
}
2965
2966
/*!
2967
    Shears the coordinate system by (\a{sh}, \a{sv}).
2968
2969
    \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
2970
*/
2971
2972
void QPainter::shear(qreal sh, qreal sv)
2973
0
{
2974
#ifdef QT_DEBUG_DRAW
2975
    if constexpr (qt_show_painter_debug_output)
2976
        printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
2977
#endif
2978
0
    Q_D(QPainter);
2979
0
    if (!d->engine) {
2980
0
        qWarning("QPainter::shear: Painter not active");
2981
0
        return;
2982
0
    }
2983
2984
0
    d->state->worldMatrix.shear(sh, sv);
2985
0
    d->state->WxF = true;
2986
0
    d->updateMatrix();
2987
0
}
2988
2989
/*!
2990
    \fn void QPainter::rotate(qreal angle)
2991
2992
    Rotates the coordinate system clockwise. The given \a angle parameter is in degrees.
2993
2994
    \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
2995
*/
2996
2997
void QPainter::rotate(qreal a)
2998
0
{
2999
#ifdef QT_DEBUG_DRAW
3000
    if constexpr (qt_show_painter_debug_output)
3001
        printf("QPainter::rotate(), angle=%f\n", a);
3002
#endif
3003
0
    Q_D(QPainter);
3004
0
    if (!d->engine) {
3005
0
        qWarning("QPainter::rotate: Painter not active");
3006
0
        return;
3007
0
    }
3008
3009
0
    d->state->worldMatrix.rotate(a);
3010
0
    d->state->WxF = true;
3011
0
    d->updateMatrix();
3012
0
}
3013
3014
/*!
3015
    Translates the coordinate system by the given \a offset; i.e. the
3016
    given \a offset is added to points.
3017
3018
    \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
3019
*/
3020
void QPainter::translate(const QPointF &offset)
3021
0
{
3022
0
    qreal dx = offset.x();
3023
0
    qreal dy = offset.y();
3024
#ifdef QT_DEBUG_DRAW
3025
    if constexpr (qt_show_painter_debug_output)
3026
        printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
3027
#endif
3028
0
    Q_D(QPainter);
3029
0
    if (!d->engine) {
3030
0
        qWarning("QPainter::translate: Painter not active");
3031
0
        return;
3032
0
    }
3033
3034
0
    d->state->worldMatrix.translate(dx, dy);
3035
0
    d->state->WxF = true;
3036
0
    d->updateMatrix();
3037
0
}
3038
3039
/*!
3040
    \fn void QPainter::translate(const QPoint &offset)
3041
    \overload
3042
3043
    Translates the coordinate system by the given \a offset.
3044
*/
3045
3046
/*!
3047
    \fn void QPainter::translate(qreal dx, qreal dy)
3048
    \overload
3049
3050
    Translates the coordinate system by the vector (\a dx, \a dy).
3051
*/
3052
3053
/*!
3054
    \fn void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
3055
3056
    Enables clipping, and sets the clip path for the painter to the
3057
    given \a path, with the clip \a operation.
3058
3059
    Note that the clip path is specified in logical (painter)
3060
    coordinates.
3061
3062
    \sa clipPath(), clipRegion(), {QPainter#Clipping}{Clipping}
3063
3064
*/
3065
void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
3066
0
{
3067
#ifdef QT_DEBUG_DRAW
3068
    if constexpr (qt_show_painter_debug_output) {
3069
        QRectF b = path.boundingRect();
3070
        printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3071
               path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3072
    }
3073
#endif
3074
0
    Q_D(QPainter);
3075
3076
0
    if (!d->engine) {
3077
0
        qWarning("QPainter::setClipPath: Painter not active");
3078
0
        return;
3079
0
    }
3080
3081
0
    bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3082
0
    if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3083
0
        op = Qt::ReplaceClip;
3084
3085
0
    if (d->extended) {
3086
0
        d->state->clipEnabled = true;
3087
0
        d->extended->clip(path, op);
3088
0
        if (op == Qt::NoClip || op == Qt::ReplaceClip)
3089
0
            d->state->clipInfo.clear();
3090
0
        d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3091
0
        d->state->clipOperation = op;
3092
0
        return;
3093
0
    }
3094
3095
0
    if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3096
0
        op = Qt::ReplaceClip;
3097
3098
0
    d->state->clipPath = path;
3099
0
    d->state->clipOperation = op;
3100
0
    if (op == Qt::NoClip || op == Qt::ReplaceClip)
3101
0
        d->state->clipInfo.clear();
3102
0
    d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3103
0
    d->state->clipEnabled = true;
3104
0
    d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3105
0
    d->updateState(d->state);
3106
0
}
3107
3108
/*!
3109
    Draws the outline (strokes) the path \a path with the pen specified
3110
    by \a pen
3111
3112
    \sa fillPath(), {QPainter#Drawing}{Drawing}
3113
*/
3114
void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
3115
0
{
3116
0
    Q_D(QPainter);
3117
3118
0
    if (!d->engine) {
3119
0
        qWarning("QPainter::strokePath: Painter not active");
3120
0
        return;
3121
0
    }
3122
3123
0
    if (path.isEmpty())
3124
0
        return;
3125
3126
0
    if (d->extended && !needsEmulation(pen.brush())) {
3127
0
        d->extended->stroke(qtVectorPathForPath(path), pen);
3128
0
        return;
3129
0
    }
3130
3131
0
    QBrush oldBrush = d->state->brush;
3132
0
    QPen oldPen = d->state->pen;
3133
3134
0
    setPen(pen);
3135
0
    setBrush(Qt::NoBrush);
3136
3137
0
    drawPath(path);
3138
3139
    // Reset old state
3140
0
    setPen(oldPen);
3141
0
    setBrush(oldBrush);
3142
0
}
3143
3144
/*!
3145
    Fills the given \a path using the given \a brush. The outline is
3146
    not drawn.
3147
3148
    Alternatively, you can specify a QColor instead of a QBrush; the
3149
    QBrush constructor (taking a QColor argument) will automatically
3150
    create a solid pattern brush.
3151
3152
    \sa drawPath()
3153
*/
3154
void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
3155
0
{
3156
0
    Q_D(QPainter);
3157
3158
0
    if (!d->engine) {
3159
0
        qWarning("QPainter::fillPath: Painter not active");
3160
0
        return;
3161
0
    }
3162
3163
0
    if (path.isEmpty())
3164
0
        return;
3165
3166
0
    if (d->extended && !needsEmulation(brush)) {
3167
0
        d->extended->fill(qtVectorPathForPath(path), brush);
3168
0
        return;
3169
0
    }
3170
3171
0
    QBrush oldBrush = d->state->brush;
3172
0
    QPen oldPen = d->state->pen;
3173
3174
0
    setPen(Qt::NoPen);
3175
0
    setBrush(brush);
3176
3177
0
    drawPath(path);
3178
3179
    // Reset old state
3180
0
    setPen(oldPen);
3181
0
    setBrush(oldBrush);
3182
0
}
3183
3184
/*!
3185
    Draws the given painter \a path using the current pen for outline
3186
    and the current brush for filling.
3187
3188
    \table 100%
3189
    \row
3190
    \li \inlineimage qpainter-path.png {Bezier curve path}
3191
    \li
3192
    \snippet code/src_gui_painting_qpainter.cpp 5
3193
    \endtable
3194
3195
    \sa {painting/painterpaths}{the Painter Paths
3196
    example},{painting/deform}{the Vector Deformation example}
3197
*/
3198
void QPainter::drawPath(const QPainterPath &path)
3199
0
{
3200
#ifdef QT_DEBUG_DRAW
3201
    QRectF pathBounds = path.boundingRect();
3202
    if constexpr (qt_show_painter_debug_output)
3203
        printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
3204
               path.elementCount(),
3205
               pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
3206
#endif
3207
3208
0
    Q_D(QPainter);
3209
3210
0
    if (!d->engine) {
3211
0
        qWarning("QPainter::drawPath: Painter not active");
3212
0
        return;
3213
0
    }
3214
3215
0
    if (d->extended) {
3216
0
        d->extended->drawPath(path);
3217
0
        return;
3218
0
    }
3219
0
    d->updateState(d->state);
3220
3221
0
    if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
3222
0
        d->engine->drawPath(path);
3223
0
    } else {
3224
0
        d->draw_helper(path);
3225
0
    }
3226
0
}
3227
3228
/*!
3229
    \fn void QPainter::drawLine(const QLineF &line)
3230
3231
    Draws a line defined by \a line.
3232
3233
    \table 100%
3234
    \row
3235
    \li \inlineimage qpainter-line.png {Diagonal line}
3236
    \li
3237
    \snippet code/src_gui_painting_qpainter.cpp 6
3238
    \endtable
3239
3240
    \sa drawLines(), drawPolyline(), {Coordinate System}
3241
*/
3242
3243
/*!
3244
    \fn void QPainter::drawLine(const QLine &line)
3245
    \overload
3246
3247
    Draws a line defined by \a line.
3248
*/
3249
3250
/*!
3251
    \fn void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
3252
    \overload
3253
3254
    Draws a line from \a p1 to \a p2.
3255
*/
3256
3257
/*!
3258
    \fn void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
3259
    \overload
3260
3261
    Draws a line from \a p1 to \a p2.
3262
*/
3263
3264
/*!
3265
    \fn void QPainter::drawLine(int x1, int y1, int x2, int y2)
3266
    \overload
3267
3268
    Draws a line from (\a x1, \a y1) to (\a x2, \a y2).
3269
*/
3270
3271
/*!
3272
    \fn void QPainter::drawRect(const QRectF &rectangle)
3273
3274
    Draws the current \a rectangle with the current pen and brush.
3275
3276
    A filled rectangle has a size of \a{rectangle}.size(). A stroked
3277
    rectangle has a size of \a{rectangle}.size() plus the pen width.
3278
3279
    \table 100%
3280
    \row
3281
    \li \inlineimage qpainter-rectangle.png {Rectangle outline}
3282
    \li
3283
    \snippet code/src_gui_painting_qpainter.cpp 7
3284
    \endtable
3285
3286
    \sa drawRects(), drawPolygon(), {Coordinate System}
3287
*/
3288
3289
/*!
3290
    \fn void QPainter::drawRect(const QRect &rectangle)
3291
3292
    \overload
3293
3294
    Draws the current \a rectangle with the current pen and brush.
3295
*/
3296
3297
/*!
3298
    \fn void QPainter::drawRect(int x, int y, int width, int height)
3299
3300
    \overload
3301
3302
    Draws a rectangle with upper left corner at (\a{x}, \a{y}) and
3303
    with the given \a width and \a height.
3304
*/
3305
3306
/*!
3307
    \fn void QPainter::drawRects(const QRectF *rectangles, int rectCount)
3308
3309
    Draws the first \a rectCount of the given \a rectangles using the
3310
    current pen and brush.
3311
3312
    \sa drawRect()
3313
*/
3314
void QPainter::drawRects(const QRectF *rects, int rectCount)
3315
0
{
3316
#ifdef QT_DEBUG_DRAW
3317
    if constexpr (qt_show_painter_debug_output)
3318
        printf("QPainter::drawRects(), count=%d\n", rectCount);
3319
#endif
3320
0
    Q_D(QPainter);
3321
3322
0
    if (!d->engine) {
3323
0
        qWarning("QPainter::drawRects: Painter not active");
3324
0
        return;
3325
0
    }
3326
3327
0
    if (rectCount <= 0)
3328
0
        return;
3329
3330
0
    if (d->extended) {
3331
0
        d->extended->drawRects(rects, rectCount);
3332
0
        return;
3333
0
    }
3334
3335
0
    d->updateState(d->state);
3336
3337
0
    if (!d->state->emulationSpecifier) {
3338
0
        d->engine->drawRects(rects, rectCount);
3339
0
        return;
3340
0
    }
3341
3342
0
    if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3343
0
        && d->state->matrix.type() == QTransform::TxTranslate) {
3344
0
        for (int i=0; i<rectCount; ++i) {
3345
0
            QRectF r(rects[i].x() + d->state->matrix.dx(),
3346
0
                     rects[i].y() + d->state->matrix.dy(),
3347
0
                     rects[i].width(),
3348
0
                     rects[i].height());
3349
0
            d->engine->drawRects(&r, 1);
3350
0
        }
3351
0
    } else {
3352
0
        if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3353
0
            for (int i=0; i<rectCount; ++i) {
3354
0
                QPainterPath rectPath;
3355
0
                rectPath.addRect(rects[i]);
3356
0
                d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3357
0
            }
3358
0
        } else {
3359
0
            QPainterPath rectPath;
3360
0
            for (int i=0; i<rectCount; ++i)
3361
0
                rectPath.addRect(rects[i]);
3362
0
            d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3363
0
        }
3364
0
    }
3365
0
}
3366
3367
/*!
3368
    \fn void QPainter::drawRects(const QRect *rectangles, int rectCount)
3369
    \overload
3370
3371
    Draws the first \a rectCount of the given \a rectangles using the
3372
    current pen and brush.
3373
*/
3374
void QPainter::drawRects(const QRect *rects, int rectCount)
3375
0
{
3376
#ifdef QT_DEBUG_DRAW
3377
    if constexpr (qt_show_painter_debug_output)
3378
        printf("QPainter::drawRects(), count=%d\n", rectCount);
3379
#endif
3380
0
    Q_D(QPainter);
3381
3382
0
    if (!d->engine) {
3383
0
        qWarning("QPainter::drawRects: Painter not active");
3384
0
        return;
3385
0
    }
3386
3387
0
    if (rectCount <= 0)
3388
0
        return;
3389
3390
0
    if (d->extended) {
3391
0
        d->extended->drawRects(rects, rectCount);
3392
0
        return;
3393
0
    }
3394
3395
0
    d->updateState(d->state);
3396
3397
0
    if (!d->state->emulationSpecifier) {
3398
0
        d->engine->drawRects(rects, rectCount);
3399
0
        return;
3400
0
    }
3401
3402
0
    if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3403
0
        && d->state->matrix.type() == QTransform::TxTranslate) {
3404
0
        for (int i=0; i<rectCount; ++i) {
3405
0
            QRectF r(rects[i].x() + d->state->matrix.dx(),
3406
0
                     rects[i].y() + d->state->matrix.dy(),
3407
0
                     rects[i].width(),
3408
0
                     rects[i].height());
3409
3410
0
            d->engine->drawRects(&r, 1);
3411
0
        }
3412
0
    } else {
3413
0
        if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3414
0
            for (int i=0; i<rectCount; ++i) {
3415
0
                QPainterPath rectPath;
3416
0
                rectPath.addRect(rects[i]);
3417
0
                d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3418
0
            }
3419
0
        } else {
3420
0
            QPainterPath rectPath;
3421
0
            for (int i=0; i<rectCount; ++i)
3422
0
                rectPath.addRect(rects[i]);
3423
3424
0
            d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3425
0
        }
3426
0
    }
3427
0
}
3428
3429
/*!
3430
    \fn void QPainter::drawRects(const QList<QRectF> &rectangles)
3431
    \overload
3432
3433
    Draws the given \a rectangles using the current pen and brush.
3434
*/
3435
3436
/*!
3437
    \fn void QPainter::drawRects(const QList<QRect> &rectangles)
3438
3439
    \overload
3440
3441
    Draws the given \a rectangles using the current pen and brush.
3442
*/
3443
3444
/*!
3445
  \fn void QPainter::drawPoint(const QPointF &position)
3446
3447
    Draws a single point at the given \a position using the current
3448
    pen's color.
3449
3450
    \sa {Coordinate System}
3451
*/
3452
3453
/*!
3454
    \fn void QPainter::drawPoint(const QPoint &position)
3455
    \overload
3456
3457
    Draws a single point at the given \a position using the current
3458
    pen's color.
3459
*/
3460
3461
/*! \fn void QPainter::drawPoint(int x, int y)
3462
3463
    \overload
3464
3465
    Draws a single point at position (\a x, \a y).
3466
*/
3467
3468
/*!
3469
    Draws the first \a pointCount points in the array \a points using
3470
    the current pen's color.
3471
3472
    \sa {Coordinate System}
3473
*/
3474
void QPainter::drawPoints(const QPointF *points, int pointCount)
3475
0
{
3476
#ifdef QT_DEBUG_DRAW
3477
    if constexpr (qt_show_painter_debug_output)
3478
        printf("QPainter::drawPoints(), count=%d\n", pointCount);
3479
#endif
3480
0
    Q_D(QPainter);
3481
3482
0
    if (!d->engine) {
3483
0
        qWarning("QPainter::drawPoints: Painter not active");
3484
0
        return;
3485
0
    }
3486
3487
0
    if (pointCount <= 0)
3488
0
        return;
3489
3490
0
    if (d->extended) {
3491
0
        d->extended->drawPoints(points, pointCount);
3492
0
        return;
3493
0
    }
3494
3495
0
    d->updateState(d->state);
3496
3497
0
    if (!d->state->emulationSpecifier) {
3498
0
        d->engine->drawPoints(points, pointCount);
3499
0
        return;
3500
0
    }
3501
3502
0
    if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3503
0
        && d->state->matrix.type() == QTransform::TxTranslate) {
3504
        // ### use drawPoints function
3505
0
        for (int i=0; i<pointCount; ++i) {
3506
0
            QPointF pt(points[i].x() + d->state->matrix.dx(),
3507
0
                       points[i].y() + d->state->matrix.dy());
3508
0
            d->engine->drawPoints(&pt, 1);
3509
0
        }
3510
0
    } else {
3511
0
        QPen pen = d->state->pen;
3512
0
        bool flat_pen = pen.capStyle() == Qt::FlatCap;
3513
0
        if (flat_pen) {
3514
0
            save();
3515
0
            pen.setCapStyle(Qt::SquareCap);
3516
0
            setPen(pen);
3517
0
        }
3518
0
        QPainterPath path;
3519
0
        for (int i=0; i<pointCount; ++i) {
3520
0
            path.moveTo(points[i].x(), points[i].y());
3521
0
            path.lineTo(points[i].x() + 0.0001, points[i].y());
3522
0
        }
3523
0
        d->draw_helper(path, QPainterPrivate::StrokeDraw);
3524
0
        if (flat_pen)
3525
0
            restore();
3526
0
    }
3527
0
}
3528
3529
/*!
3530
    \overload
3531
3532
    Draws the first \a pointCount points in the array \a points using
3533
    the current pen's color.
3534
*/
3535
3536
void QPainter::drawPoints(const QPoint *points, int pointCount)
3537
0
{
3538
#ifdef QT_DEBUG_DRAW
3539
    if constexpr (qt_show_painter_debug_output)
3540
        printf("QPainter::drawPoints(), count=%d\n", pointCount);
3541
#endif
3542
0
    Q_D(QPainter);
3543
3544
0
    if (!d->engine) {
3545
0
        qWarning("QPainter::drawPoints: Painter not active");
3546
0
        return;
3547
0
    }
3548
3549
0
    if (pointCount <= 0)
3550
0
        return;
3551
3552
0
    if (d->extended) {
3553
0
        d->extended->drawPoints(points, pointCount);
3554
0
        return;
3555
0
    }
3556
3557
0
    d->updateState(d->state);
3558
3559
0
    if (!d->state->emulationSpecifier) {
3560
0
        d->engine->drawPoints(points, pointCount);
3561
0
        return;
3562
0
    }
3563
3564
0
    if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3565
0
        && d->state->matrix.type() == QTransform::TxTranslate) {
3566
        // ### use drawPoints function
3567
0
        for (int i=0; i<pointCount; ++i) {
3568
0
            QPointF pt(points[i].x() + d->state->matrix.dx(),
3569
0
                       points[i].y() + d->state->matrix.dy());
3570
0
            d->engine->drawPoints(&pt, 1);
3571
0
        }
3572
0
    } else {
3573
0
        QPen pen = d->state->pen;
3574
0
        bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3575
0
        if (flat_pen) {
3576
0
            save();
3577
0
            pen.setCapStyle(Qt::SquareCap);
3578
0
            setPen(pen);
3579
0
        }
3580
0
        QPainterPath path;
3581
0
        for (int i=0; i<pointCount; ++i) {
3582
0
            path.moveTo(points[i].x(), points[i].y());
3583
0
            path.lineTo(points[i].x() + 0.0001, points[i].y());
3584
0
        }
3585
0
        d->draw_helper(path, QPainterPrivate::StrokeDraw);
3586
0
        if (flat_pen)
3587
0
            restore();
3588
0
    }
3589
0
}
3590
3591
/*!
3592
    \fn void QPainter::drawPoints(const QPolygonF &points)
3593
3594
    \overload
3595
3596
    Draws the points in the vector \a points.
3597
*/
3598
3599
/*!
3600
    \fn void QPainter::drawPoints(const QPolygon &points)
3601
3602
    \overload
3603
3604
    Draws the points in the vector \a points.
3605
*/
3606
3607
/*!
3608
    Sets the background mode of the painter to the given \a mode
3609
3610
    Qt::TransparentMode (the default) draws stippled lines and text
3611
    without setting the background pixels.  Qt::OpaqueMode fills these
3612
    space with the current background color.
3613
3614
    Note that in order to draw a bitmap or pixmap transparently, you
3615
    must use QPixmap::setMask().
3616
3617
    \sa backgroundMode(), setBackground(),
3618
    {QPainter#Settings}{Settings}
3619
*/
3620
3621
void QPainter::setBackgroundMode(Qt::BGMode mode)
3622
0
{
3623
#ifdef QT_DEBUG_DRAW
3624
    if constexpr (qt_show_painter_debug_output)
3625
        printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
3626
#endif
3627
3628
0
    Q_D(QPainter);
3629
0
    if (!d->engine) {
3630
0
        qWarning("QPainter::setBackgroundMode: Painter not active");
3631
0
        return;
3632
0
    }
3633
0
    if (d->state->bgMode == mode)
3634
0
        return;
3635
3636
0
    d->state->bgMode = mode;
3637
0
    if (d->extended) {
3638
0
        d->checkEmulation();
3639
0
    } else {
3640
0
        d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
3641
0
    }
3642
0
}
3643
3644
/*!
3645
    Returns the current background mode.
3646
3647
    \sa setBackgroundMode(), {QPainter#Settings}{Settings}
3648
*/
3649
Qt::BGMode QPainter::backgroundMode() const
3650
0
{
3651
0
    Q_D(const QPainter);
3652
0
    if (!d->engine) {
3653
0
        qWarning("QPainter::backgroundMode: Painter not active");
3654
0
        return Qt::TransparentMode;
3655
0
    }
3656
0
    return d->state->bgMode;
3657
0
}
3658
3659
3660
/*!
3661
    \overload
3662
3663
    Sets the painter's pen to have style Qt::SolidLine, width 1 and the
3664
    specified \a color.
3665
*/
3666
3667
void QPainter::setPen(const QColor &color)
3668
0
{
3669
#ifdef QT_DEBUG_DRAW
3670
    if constexpr (qt_show_painter_debug_output)
3671
        printf("QPainter::setPen(), color=%04x\n", color.rgb());
3672
#endif
3673
0
    Q_D(QPainter);
3674
0
    if (!d->engine) {
3675
0
        qWarning("QPainter::setPen: Painter not active");
3676
0
        return;
3677
0
    }
3678
3679
0
    const QColor actualColor = color.isValid() ? color : QColor(Qt::black);
3680
0
    if (d->state->pen == actualColor)
3681
0
        return;
3682
3683
0
    d->state->pen = actualColor;
3684
0
    if (d->extended)
3685
0
        d->extended->penChanged();
3686
0
    else
3687
0
        d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3688
0
}
3689
3690
/*!
3691
    \fn void QPainter::setPen(const QPen &pen)
3692
3693
    Sets the painter's pen to be the given \a pen.
3694
3695
    The \a pen defines how to draw lines and outlines, and it also
3696
    defines the text color.
3697
3698
    \sa pen(), {QPainter#Settings}{Settings}
3699
*/
3700
3701
/*!
3702
    \fn void QPainter::setPen(QPen &&pen)
3703
    \since 6.11
3704
    \overload
3705
*/
3706
3707
void QPainter::doSetPen(const QPen &pen, QPen *rvalue)
3708
0
{
3709
3710
#ifdef QT_DEBUG_DRAW
3711
    if constexpr (qt_show_painter_debug_output)
3712
        printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
3713
           pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
3714
#endif
3715
0
    Q_D(QPainter);
3716
0
    if (!d->engine) {
3717
0
        qWarning("QPainter::setPen: Painter not active");
3718
0
        return;
3719
0
    }
3720
3721
0
    if (d->state->pen == pen)
3722
0
        return;
3723
3724
0
    q_choose_assign(d->state->pen, pen, rvalue);
3725
3726
0
    if (d->extended) {
3727
0
        d->checkEmulation();
3728
0
        d->extended->penChanged();
3729
0
        return;
3730
0
    }
3731
3732
0
    d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3733
0
}
3734
3735
/*!
3736
    \overload
3737
3738
    Sets the painter's pen to have the given \a style, width 1 and
3739
    black color.
3740
*/
3741
3742
void QPainter::setPen(Qt::PenStyle style)
3743
0
{
3744
0
    Q_D(QPainter);
3745
0
    if (!d->engine) {
3746
0
        qWarning("QPainter::setPen: Painter not active");
3747
0
        return;
3748
0
    }
3749
3750
0
    if (d->state->pen == style)
3751
0
        return;
3752
3753
0
    d->state->pen = style;
3754
3755
0
    if (d->extended)
3756
0
        d->extended->penChanged();
3757
0
    else
3758
0
        d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3759
3760
0
}
3761
3762
/*!
3763
    Returns the painter's current pen.
3764
3765
    \sa setPen(), {QPainter#Settings}{Settings}
3766
*/
3767
3768
const QPen &QPainter::pen() const
3769
0
{
3770
0
    Q_D(const QPainter);
3771
0
    if (!d->engine) {
3772
0
        qWarning("QPainter::pen: Painter not active");
3773
0
        return d->fakeState()->pen;
3774
0
    }
3775
0
    return d->state->pen;
3776
0
}
3777
3778
3779
/*!
3780
    \fn void QPainter::setBrush(const QBrush &brush)
3781
3782
    Sets the painter's brush to the given \a brush.
3783
3784
    The painter's brush defines how shapes are filled.
3785
3786
    \sa brush(), {QPainter#Settings}{Settings}
3787
*/
3788
3789
/*!
3790
    \fn void QPainter::setBrush(QBrush &&brush)
3791
    \since 6.11
3792
    \overload
3793
*/
3794
3795
void QPainter::doSetBrush(const QBrush &brush, QBrush *rvalue)
3796
0
{
3797
#ifdef QT_DEBUG_DRAW
3798
    if constexpr (qt_show_painter_debug_output)
3799
        printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
3800
#endif
3801
0
    Q_D(QPainter);
3802
0
    if (!d->engine) {
3803
0
        qWarning("QPainter::setBrush: Painter not active");
3804
0
        return;
3805
0
    }
3806
3807
0
    if (d->state->brush.d == brush.d)
3808
0
        return;
3809
3810
0
    if (d->extended) {
3811
0
        q_choose_assign(d->state->brush, brush, rvalue);
3812
0
        d->checkEmulation();
3813
0
        d->extended->brushChanged();
3814
0
        return;
3815
0
    }
3816
3817
0
    q_choose_assign(d->state->brush, brush, rvalue);
3818
0
    d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3819
0
}
3820
3821
3822
/*!
3823
    \overload
3824
3825
    Sets the painter's brush to black color and the specified \a
3826
    style.
3827
*/
3828
3829
void QPainter::setBrush(Qt::BrushStyle style)
3830
0
{
3831
0
    Q_D(QPainter);
3832
0
    if (!d->engine) {
3833
0
        qWarning("QPainter::setBrush: Painter not active");
3834
0
        return;
3835
0
    }
3836
0
    if (d->state->brush == style)
3837
0
        return;
3838
0
    d->state->brush = QBrush(Qt::black, style);
3839
0
    if (d->extended)
3840
0
        d->extended->brushChanged();
3841
0
    else
3842
0
        d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3843
0
}
3844
3845
/*!
3846
    \overload
3847
    \since 6.9
3848
3849
    Sets the painter's brush to a solid brush with the specified
3850
    \a color.
3851
*/
3852
3853
void QPainter::setBrush(QColor color)
3854
0
{
3855
0
    Q_D(QPainter);
3856
0
    if (!d->engine) {
3857
0
        qWarning("QPainter::setBrush: Painter not active");
3858
0
        return;
3859
0
    }
3860
3861
0
    const QColor actualColor = color.isValid() ? color : QColor(Qt::black);
3862
0
    if (d->state->brush == actualColor)
3863
0
        return;
3864
0
    d->state->brush = actualColor;
3865
0
    if (d->extended)
3866
0
        d->extended->brushChanged();
3867
0
    else
3868
0
        d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3869
0
}
3870
3871
/*!
3872
    \fn void QPainter::setBrush(Qt::GlobalColor color)
3873
    \overload
3874
    \since 6.9
3875
3876
    Sets the painter's brush to a solid brush with the specified
3877
    \a color.
3878
*/
3879
3880
3881
/*!
3882
    Returns the painter's current brush.
3883
3884
    \sa QPainter::setBrush(), {QPainter#Settings}{Settings}
3885
*/
3886
3887
const QBrush &QPainter::brush() const
3888
0
{
3889
0
    Q_D(const QPainter);
3890
0
    if (!d->engine) {
3891
0
        qWarning("QPainter::brush: Painter not active");
3892
0
        return d->fakeState()->brush;
3893
0
    }
3894
0
    return d->state->brush;
3895
0
}
3896
3897
/*!
3898
    \fn void QPainter::setBackground(const QBrush &brush)
3899
3900
    Sets the background brush of the painter to the given \a brush.
3901
3902
    The background brush is the brush that is filled in when drawing
3903
    opaque text, stippled lines and bitmaps. The background brush has
3904
    no effect in transparent background mode (which is the default).
3905
3906
    \sa background(), setBackgroundMode(),
3907
    {QPainter#Settings}{Settings}
3908
*/
3909
3910
void QPainter::setBackground(const QBrush &bg)
3911
0
{
3912
#ifdef QT_DEBUG_DRAW
3913
    if constexpr (qt_show_painter_debug_output)
3914
        printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
3915
#endif
3916
3917
0
    Q_D(QPainter);
3918
0
    if (!d->engine) {
3919
0
        qWarning("QPainter::setBackground: Painter not active");
3920
0
        return;
3921
0
    }
3922
0
    d->state->bgBrush = bg;
3923
0
    if (!d->extended)
3924
0
        d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
3925
0
}
3926
3927
/*!
3928
    Sets the painter's font to the given \a font.
3929
3930
    This font is used by subsequent drawText() functions. The text
3931
    color is the same as the pen color.
3932
3933
    If you set a font that isn't available, Qt finds a close match.
3934
    font() will return what you set using setFont() and fontInfo() returns the
3935
    font actually being used (which may be the same).
3936
3937
    \sa font(), drawText(), {QPainter#Settings}{Settings}
3938
*/
3939
3940
void QPainter::setFont(const QFont &font)
3941
0
{
3942
0
    Q_D(QPainter);
3943
3944
#ifdef QT_DEBUG_DRAW
3945
    if constexpr (qt_show_painter_debug_output)
3946
        printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.family().toLatin1().constData(), font.pointSize());
3947
#endif
3948
3949
0
    if (!d->engine) {
3950
0
        qWarning("QPainter::setFont: Painter not active");
3951
0
        return;
3952
0
    }
3953
3954
0
    d->state->font = QFont(font.resolve(d->state->deviceFont), device());
3955
0
    if (!d->extended)
3956
0
        d->state->dirtyFlags |= QPaintEngine::DirtyFont;
3957
0
}
3958
3959
/*!
3960
    Returns the currently set font used for drawing text.
3961
3962
    \sa setFont(), drawText(), {QPainter#Settings}{Settings}
3963
*/
3964
const QFont &QPainter::font() const
3965
0
{
3966
0
    Q_D(const QPainter);
3967
0
    if (!d->engine) {
3968
0
        qWarning("QPainter::font: Painter not active");
3969
0
        return d->fakeState()->font;
3970
0
    }
3971
0
    return d->state->font;
3972
0
}
3973
3974
/*!
3975
    \since 4.4
3976
3977
    Draws the given rectangle \a rect with rounded corners.
3978
3979
    The \a xRadius and \a yRadius arguments specify the radii
3980
    of the ellipses defining the corners of the rounded rectangle.
3981
    When \a mode is Qt::RelativeSize, \a xRadius and
3982
    \a yRadius are specified in percentage of half the rectangle's
3983
    width and height respectively, and should be in the range
3984
    0.0 to 100.0.
3985
3986
    A filled rectangle has a size of rect.size(). A stroked rectangle
3987
    has a size of rect.size() plus the pen width.
3988
3989
    \table 100%
3990
    \row
3991
    \li \inlineimage qpainter-roundrect.png {Rounded rectangle outline}
3992
    \li
3993
    \snippet code/src_gui_painting_qpainter.cpp 8
3994
    \endtable
3995
3996
    \sa drawRect(), QPen
3997
*/
3998
void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
3999
0
{
4000
#ifdef QT_DEBUG_DRAW
4001
    if constexpr (qt_show_painter_debug_output)
4002
        printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
4003
#endif
4004
0
    Q_D(QPainter);
4005
4006
0
    if (!d->engine) {
4007
0
        qWarning("QPainter::drawRoundedRect: Painter not active");
4008
0
        return;
4009
0
    }
4010
4011
0
    if (xRadius <= 0 || yRadius <= 0) {             // draw normal rectangle
4012
0
        drawRect(rect);
4013
0
        return;
4014
0
    }
4015
4016
0
    if (d->extended) {
4017
0
        d->extended->drawRoundedRect(rect, xRadius, yRadius, mode);
4018
0
        return;
4019
0
    }
4020
4021
0
    QPainterPath path;
4022
0
    path.addRoundedRect(rect, xRadius, yRadius, mode);
4023
0
    drawPath(path);
4024
0
}
4025
4026
/*!
4027
    \fn void QPainter::drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius,
4028
                                       Qt::SizeMode mode = Qt::AbsoluteSize);
4029
    \since 4.4
4030
    \overload
4031
4032
    Draws the given rectangle \a rect with rounded corners.
4033
*/
4034
4035
/*!
4036
    \fn void QPainter::drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius,
4037
                                       Qt::SizeMode mode = Qt::AbsoluteSize);
4038
    \since 4.4
4039
    \overload
4040
4041
    Draws the given rectangle \a x, \a y, \a w, \a h with rounded corners.
4042
*/
4043
4044
/*!
4045
    \fn void QPainter::drawEllipse(const QRectF &rectangle)
4046
4047
    Draws the ellipse defined by the given \a rectangle.
4048
4049
    A filled ellipse has a size of \a{rectangle}.\l
4050
    {QRect::size()}{size()}. A stroked ellipse has a size of
4051
    \a{rectangle}.\l {QRect::size()}{size()} plus the pen width.
4052
4053
    \table 100%
4054
    \row
4055
    \li \inlineimage qpainter-ellipse.png {Ellipse outline}
4056
    \li
4057
    \snippet code/src_gui_painting_qpainter.cpp 9
4058
    \endtable
4059
4060
    \sa drawPie(), {Coordinate System}
4061
*/
4062
void QPainter::drawEllipse(const QRectF &r)
4063
0
{
4064
#ifdef QT_DEBUG_DRAW
4065
    if constexpr (qt_show_painter_debug_output)
4066
        printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
4067
#endif
4068
0
    Q_D(QPainter);
4069
4070
0
    if (!d->engine) {
4071
0
        qWarning("QPainter::drawEllipse: Painter not active");
4072
0
        return;
4073
0
    }
4074
4075
0
    QRectF rect(r.normalized());
4076
4077
0
    if (d->extended) {
4078
0
        d->extended->drawEllipse(rect);
4079
0
        return;
4080
0
    }
4081
4082
0
    d->updateState(d->state);
4083
0
    if (d->state->emulationSpecifier) {
4084
0
        if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4085
0
            && d->state->matrix.type() == QTransform::TxTranslate) {
4086
0
            rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
4087
0
        } else {
4088
0
            QPainterPath path;
4089
0
            path.addEllipse(rect);
4090
0
            d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
4091
0
            return;
4092
0
        }
4093
0
    }
4094
4095
0
    d->engine->drawEllipse(rect);
4096
0
}
4097
4098
/*!
4099
    \fn void QPainter::drawEllipse(const QRect &rectangle)
4100
4101
    \overload
4102
4103
    Draws the ellipse defined by the given \a rectangle.
4104
*/
4105
void QPainter::drawEllipse(const QRect &r)
4106
0
{
4107
#ifdef QT_DEBUG_DRAW
4108
    if constexpr (qt_show_painter_debug_output)
4109
        printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
4110
#endif
4111
0
    Q_D(QPainter);
4112
4113
0
    if (!d->engine) {
4114
0
        qWarning("QPainter::drawEllipse: Painter not active");
4115
0
        return;
4116
0
    }
4117
4118
0
    QRect rect(r.normalized());
4119
4120
0
    if (d->extended) {
4121
0
        d->extended->drawEllipse(rect);
4122
0
        return;
4123
0
    }
4124
4125
0
    d->updateState(d->state);
4126
4127
0
    if (d->state->emulationSpecifier) {
4128
0
        if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4129
0
            && d->state->matrix.type() == QTransform::TxTranslate) {
4130
0
            rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
4131
0
        } else {
4132
0
            QPainterPath path;
4133
0
            path.addEllipse(rect);
4134
0
            d->draw_helper(path, QPainterPrivate::StrokeAndFillDraw);
4135
0
            return;
4136
0
        }
4137
0
    }
4138
4139
0
    d->engine->drawEllipse(rect);
4140
0
}
4141
4142
/*!
4143
    \fn void QPainter::drawEllipse(int x, int y, int width, int height)
4144
4145
    \overload
4146
4147
    Draws the ellipse defined by the rectangle beginning at (\a{x},
4148
    \a{y}) with the given \a width and \a height.
4149
*/
4150
4151
/*!
4152
    \since 4.4
4153
4154
    \fn void QPainter::drawEllipse(const QPointF &center, qreal rx, qreal ry)
4155
4156
    \overload
4157
4158
    Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
4159
*/
4160
4161
/*!
4162
    \since 4.4
4163
4164
    \fn void QPainter::drawEllipse(const QPoint &center, int rx, int ry)
4165
4166
    \overload
4167
4168
    Draws the ellipse positioned at \a{center} with radii \a{rx} and \a{ry}.
4169
*/
4170
4171
/*!
4172
    \fn void QPainter::drawArc(const QRectF &rectangle, int startAngle, int spanAngle)
4173
4174
    Draws the arc defined by the given \a rectangle, \a startAngle and
4175
    \a spanAngle.
4176
4177
    The \a startAngle and \a spanAngle must be specified in 1/16th of
4178
    a degree, i.e. a full circle equals 5760 (16 * 360). Positive
4179
    values for the angles mean counter-clockwise while negative values
4180
    mean the clockwise direction. Zero degrees is at the 3 o'clock
4181
    position. If \a rectangle is not square, the angles are eccentric
4182
    angles and do not measure the direction from the center of the
4183
    rectangle, as described in \l{QPainterPath#Arcs and Ellipses}{Arcs
4184
    and Ellipses}.
4185
4186
    \table 100%
4187
    \row
4188
    \li \inlineimage qpainter-arc.png {Arc curve}
4189
    \li
4190
    \snippet code/src_gui_painting_qpainter.cpp 10
4191
    \endtable
4192
4193
    \sa drawPie(), drawChord(), {Coordinate System}
4194
*/
4195
4196
void QPainter::drawArc(const QRectF &r, int a, int alen)
4197
0
{
4198
#ifdef QT_DEBUG_DRAW
4199
    if constexpr (qt_show_painter_debug_output)
4200
        printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4201
           r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4202
#endif
4203
0
    Q_D(QPainter);
4204
4205
0
    if (!d->engine) {
4206
0
        qWarning("QPainter::drawArc: Painter not active");
4207
0
        return;
4208
0
    }
4209
4210
0
    QRectF rect = r.normalized();
4211
4212
0
    QPainterPath path;
4213
0
    path.arcMoveTo(rect, a/16.0);
4214
0
    path.arcTo(rect, a/16.0, alen/16.0);
4215
0
    strokePath(path, d->state->pen);
4216
0
}
4217
4218
/*! \fn void QPainter::drawArc(const QRect &rectangle, int startAngle,
4219
                               int spanAngle)
4220
4221
    \overload
4222
4223
    Draws the arc defined by the given \a rectangle, \a startAngle and
4224
    \a spanAngle.
4225
*/
4226
4227
/*!
4228
    \fn void QPainter::drawArc(int x, int y, int width, int height,
4229
                               int startAngle, int spanAngle)
4230
4231
    \overload
4232
4233
    Draws the arc defined by the rectangle beginning at (\a x, \a y)
4234
    with the specified \a width and \a height, and the given \a
4235
    startAngle and \a spanAngle.
4236
*/
4237
4238
/*!
4239
    \fn void QPainter::drawPie(const QRectF &rectangle, int startAngle, int spanAngle)
4240
4241
    Draws a pie defined by the given \a rectangle, \a startAngle and \a spanAngle.
4242
4243
    The pie is filled with the current brush().
4244
4245
    The startAngle and spanAngle must be specified in 1/16th of a
4246
    degree, i.e. a full circle equals 5760 (16 * 360). Positive values
4247
    for the angles mean counter-clockwise while negative values mean
4248
    the clockwise direction. Zero degrees is at the 3 o'clock
4249
    position. If \a rectangle is not square, the angles are eccentric
4250
    angles and do not measure the direction from the center of the
4251
    rectangle, as described in \l{QPainterPath#Arcs and Ellipses}{Arcs
4252
    and Ellipses}.
4253
4254
    \table 100%
4255
    \row
4256
    \li \inlineimage qpainter-pie.png {Pie slice shape}
4257
    \li
4258
    \snippet code/src_gui_painting_qpainter.cpp 11
4259
    \endtable
4260
4261
    \sa drawEllipse(), drawChord(), {Coordinate System}
4262
*/
4263
void QPainter::drawPie(const QRectF &r, int a, int alen)
4264
0
{
4265
#ifdef QT_DEBUG_DRAW
4266
    if constexpr (qt_show_painter_debug_output)
4267
        printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4268
           r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4269
#endif
4270
0
    Q_D(QPainter);
4271
4272
0
    if (!d->engine) {
4273
0
        qWarning("QPainter::drawPie: Painter not active");
4274
0
        return;
4275
0
    }
4276
4277
0
    if (a > (360*16)) {
4278
0
        a = a % (360*16);
4279
0
    } else if (a < 0) {
4280
0
        a = a % (360*16);
4281
0
        if (a < 0) a += (360*16);
4282
0
    }
4283
4284
0
    QRectF rect = r.normalized();
4285
4286
0
    QPainterPath path;
4287
0
    path.moveTo(rect.center());
4288
0
    path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/16.0, alen/16.0);
4289
0
    path.closeSubpath();
4290
0
    drawPath(path);
4291
4292
0
}
4293
4294
/*!
4295
    \fn void QPainter::drawPie(const QRect &rectangle, int startAngle, int spanAngle)
4296
    \overload
4297
4298
    Draws a pie defined by the given \a rectangle, \a startAngle and
4299
    and \a spanAngle.
4300
*/
4301
4302
/*!
4303
    \fn void QPainter::drawPie(int x, int y, int width, int height, int
4304
    startAngle, int spanAngle)
4305
4306
    \overload
4307
4308
    Draws the pie defined by the rectangle beginning at (\a x, \a y) with
4309
    the specified \a width and \a height, and the given \a startAngle and
4310
    \a spanAngle.
4311
*/
4312
4313
/*!
4314
    \fn void QPainter::drawChord(const QRectF &rectangle, int startAngle, int spanAngle)
4315
4316
    Draws the chord defined by the given \a rectangle, \a startAngle and
4317
    \a spanAngle.  The chord is filled with the current brush().
4318
4319
    The startAngle and spanAngle must be specified in 1/16th of a
4320
    degree, i.e. a full circle equals 5760 (16 * 360). Positive values
4321
    for the angles mean counter-clockwise while negative values mean
4322
    the clockwise direction. Zero degrees is at the 3 o'clock
4323
    position. If \a rectangle is not square, the angles are eccentric
4324
    angles and do not measure the direction from the center of the
4325
    rectangle, as described in \l{QPainterPath#Arcs and Ellipses}{Arcs
4326
    and Ellipses}.
4327
4328
    \table 100%
4329
    \row
4330
    \li \inlineimage qpainter-chord.png {Chord shape}
4331
    \li
4332
    \snippet code/src_gui_painting_qpainter.cpp 12
4333
    \endtable
4334
4335
    \sa drawArc(), drawPie(), {Coordinate System}
4336
*/
4337
void QPainter::drawChord(const QRectF &r, int a, int alen)
4338
0
{
4339
#ifdef QT_DEBUG_DRAW
4340
    if constexpr (qt_show_painter_debug_output)
4341
        printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4342
           r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4343
#endif
4344
0
    Q_D(QPainter);
4345
4346
0
    if (!d->engine) {
4347
0
        qWarning("QPainter::drawChord: Painter not active");
4348
0
        return;
4349
0
    }
4350
4351
0
    QRectF rect = r.normalized();
4352
4353
0
    QPainterPath path;
4354
0
    path.arcMoveTo(rect, a/16.0);
4355
0
    path.arcTo(rect, a/16.0, alen/16.0);
4356
0
    path.closeSubpath();
4357
0
    drawPath(path);
4358
0
}
4359
/*!
4360
    \fn void QPainter::drawChord(const QRect &rectangle, int startAngle, int spanAngle)
4361
4362
    \overload
4363
4364
    Draws the chord defined by the given \a rectangle, \a startAngle and
4365
    \a spanAngle.
4366
*/
4367
4368
/*!
4369
    \fn void QPainter::drawChord(int x, int y, int width, int height, int
4370
    startAngle, int spanAngle)
4371
4372
    \overload
4373
4374
   Draws the chord defined by the rectangle beginning at (\a x, \a y)
4375
   with the specified \a width and \a height, and the given \a
4376
   startAngle and \a spanAngle.
4377
*/
4378
4379
4380
/*!
4381
    Draws the first \a lineCount lines in the array \a lines
4382
    using the current pen.
4383
4384
    \sa drawLine(), drawPolyline()
4385
*/
4386
void QPainter::drawLines(const QLineF *lines, int lineCount)
4387
0
{
4388
#ifdef QT_DEBUG_DRAW
4389
    if constexpr (qt_show_painter_debug_output)
4390
        printf("QPainter::drawLines(), line count=%d\n", lineCount);
4391
#endif
4392
4393
0
    Q_D(QPainter);
4394
4395
0
    if (!d->engine || lineCount < 1)
4396
0
        return;
4397
4398
0
    if (d->extended) {
4399
0
        d->extended->drawLines(lines, lineCount);
4400
0
        return;
4401
0
    }
4402
4403
0
    d->updateState(d->state);
4404
4405
0
    uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4406
4407
0
    if (lineEmulation) {
4408
0
        if (lineEmulation == QPaintEngine::PrimitiveTransform
4409
0
            && d->state->matrix.type() == QTransform::TxTranslate) {
4410
0
            for (int i = 0; i < lineCount; ++i) {
4411
0
                QLineF line = lines[i];
4412
0
                line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4413
0
                d->engine->drawLines(&line, 1);
4414
0
            }
4415
0
        } else {
4416
0
            QPainterPath linePath;
4417
0
            for (int i = 0; i < lineCount; ++i) {
4418
0
                linePath.moveTo(lines[i].p1());
4419
0
                linePath.lineTo(lines[i].p2());
4420
0
            }
4421
0
            d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4422
0
        }
4423
0
        return;
4424
0
    }
4425
0
    d->engine->drawLines(lines, lineCount);
4426
0
}
4427
4428
/*!
4429
    \fn void QPainter::drawLines(const QLine *lines, int lineCount)
4430
    \overload
4431
4432
    Draws the first \a lineCount lines in the array \a lines
4433
    using the current pen.
4434
*/
4435
void QPainter::drawLines(const QLine *lines, int lineCount)
4436
0
{
4437
#ifdef QT_DEBUG_DRAW
4438
    if constexpr (qt_show_painter_debug_output)
4439
        printf("QPainter::drawLine(), line count=%d\n", lineCount);
4440
#endif
4441
4442
0
    Q_D(QPainter);
4443
4444
0
    if (!d->engine || lineCount < 1)
4445
0
        return;
4446
4447
0
    if (d->extended) {
4448
0
        d->extended->drawLines(lines, lineCount);
4449
0
        return;
4450
0
    }
4451
4452
0
    d->updateState(d->state);
4453
4454
0
    uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4455
4456
0
    if (lineEmulation) {
4457
0
        if (lineEmulation == QPaintEngine::PrimitiveTransform
4458
0
            && d->state->matrix.type() == QTransform::TxTranslate) {
4459
0
            for (int i = 0; i < lineCount; ++i) {
4460
0
                QLineF line = lines[i];
4461
0
                line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4462
0
                d->engine->drawLines(&line, 1);
4463
0
            }
4464
0
        } else {
4465
0
            QPainterPath linePath;
4466
0
            for (int i = 0; i < lineCount; ++i) {
4467
0
                linePath.moveTo(lines[i].p1());
4468
0
                linePath.lineTo(lines[i].p2());
4469
0
            }
4470
0
            d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4471
0
        }
4472
0
        return;
4473
0
    }
4474
0
    d->engine->drawLines(lines, lineCount);
4475
0
}
4476
4477
/*!
4478
    \overload
4479
4480
    Draws the first \a lineCount lines in the array \a pointPairs
4481
    using the current pen.  The lines are specified as pairs of points
4482
    so the number of entries in \a pointPairs must be at least \a
4483
    lineCount * 2.
4484
*/
4485
void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
4486
0
{
4487
0
    Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
4488
4489
0
    drawLines((const QLineF*)pointPairs, lineCount);
4490
0
}
4491
4492
/*!
4493
    \overload
4494
4495
    Draws the first \a lineCount lines in the array \a pointPairs
4496
    using the current pen.
4497
*/
4498
void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
4499
0
{
4500
0
    Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
4501
4502
0
    drawLines((const QLine*)pointPairs, lineCount);
4503
0
}
4504
4505
4506
/*!
4507
    \fn void QPainter::drawLines(const QList<QPointF> &pointPairs)
4508
    \overload
4509
4510
    Draws a line for each pair of points in the vector \a pointPairs
4511
    using the current pen. If there is an odd number of points in the
4512
    array, the last point will be ignored.
4513
*/
4514
4515
/*!
4516
    \fn void QPainter::drawLines(const QList<QPoint> &pointPairs)
4517
    \overload
4518
4519
    Draws a line for each pair of points in the vector \a pointPairs
4520
    using the current pen.
4521
*/
4522
4523
/*!
4524
    \fn void QPainter::drawLines(const QList<QLineF> &lines)
4525
    \overload
4526
4527
    Draws the set of lines defined by the list \a lines using the
4528
    current pen and brush.
4529
*/
4530
4531
/*!
4532
    \fn void QPainter::drawLines(const QList<QLine> &lines)
4533
    \overload
4534
4535
    Draws the set of lines defined by the list \a lines using the
4536
    current pen and brush.
4537
*/
4538
4539
/*!
4540
    Draws the polyline defined by the first \a pointCount points in \a
4541
    points using the current pen.
4542
4543
    Note that unlike the drawPolygon() function the last point is \e
4544
    not connected to the first, neither is the polyline filled.
4545
4546
    \table 100%
4547
    \row
4548
    \li
4549
    \snippet code/src_gui_painting_qpainter.cpp 13
4550
    \endtable
4551
4552
    \sa drawLines(), drawPolygon(), {Coordinate System}
4553
*/
4554
void QPainter::drawPolyline(const QPointF *points, int pointCount)
4555
0
{
4556
#ifdef QT_DEBUG_DRAW
4557
    if constexpr (qt_show_painter_debug_output)
4558
        printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4559
#endif
4560
0
    Q_D(QPainter);
4561
4562
0
    if (!d->engine || pointCount < 2)
4563
0
        return;
4564
4565
0
    if (d->extended) {
4566
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4567
0
        return;
4568
0
    }
4569
4570
0
    d->updateState(d->state);
4571
4572
0
    uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4573
4574
0
    if (lineEmulation) {
4575
        // ###
4576
//         if (lineEmulation == QPaintEngine::PrimitiveTransform
4577
//             && d->state->matrix.type() == QTransform::TxTranslate) {
4578
//         } else {
4579
0
        QPainterPath polylinePath(points[0]);
4580
0
        for (int i=1; i<pointCount; ++i)
4581
0
            polylinePath.lineTo(points[i]);
4582
0
        d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4583
//         }
4584
0
    } else {
4585
0
        d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4586
0
    }
4587
0
}
4588
4589
/*!
4590
    \overload
4591
4592
    Draws the polyline defined by the first \a pointCount points in \a
4593
    points using the current pen.
4594
 */
4595
void QPainter::drawPolyline(const QPoint *points, int pointCount)
4596
0
{
4597
#ifdef QT_DEBUG_DRAW
4598
    if constexpr (qt_show_painter_debug_output)
4599
        printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4600
#endif
4601
0
    Q_D(QPainter);
4602
4603
0
    if (!d->engine || pointCount < 2)
4604
0
        return;
4605
4606
0
    if (d->extended) {
4607
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4608
0
        return;
4609
0
    }
4610
4611
0
    d->updateState(d->state);
4612
4613
0
    uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4614
4615
0
    if (lineEmulation) {
4616
        // ###
4617
//         if (lineEmulation == QPaintEngine::PrimitiveTransform
4618
//             && d->state->matrix.type() == QTransform::TxTranslate) {
4619
//         } else {
4620
0
        QPainterPath polylinePath(points[0]);
4621
0
        for (int i=1; i<pointCount; ++i)
4622
0
            polylinePath.lineTo(points[i]);
4623
0
        d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4624
//         }
4625
0
    } else {
4626
0
        d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4627
0
    }
4628
0
}
4629
4630
/*!
4631
    \fn void QPainter::drawPolyline(const QPolygonF &points)
4632
4633
    \overload
4634
4635
    Draws the polyline defined by the given \a points using the
4636
    current pen.
4637
*/
4638
4639
/*!
4640
    \fn void QPainter::drawPolyline(const QPolygon &points)
4641
4642
    \overload
4643
4644
    Draws the polyline defined by the given \a points using the
4645
    current pen.
4646
*/
4647
4648
/*!
4649
    Draws the polygon defined by the first \a pointCount points in the
4650
    array \a points using the current pen and brush.
4651
4652
    \table 100%
4653
    \row
4654
    \li \inlineimage qpainter-polygon.png {Four-sided polygon}
4655
    \li
4656
    \snippet code/src_gui_painting_qpainter.cpp 14
4657
    \endtable
4658
4659
    The first point is implicitly connected to the last point, and the
4660
    polygon is filled with the current brush().
4661
4662
    If \a fillRule is Qt::WindingFill, the polygon is filled using the
4663
    winding fill algorithm.  If \a fillRule is Qt::OddEvenFill, the
4664
    polygon is filled using the odd-even fill algorithm. See
4665
    \l{Qt::FillRule} for a more detailed description of these fill
4666
    rules.
4667
4668
    \sa drawConvexPolygon(), drawPolyline(), {Coordinate System}
4669
*/
4670
void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
4671
0
{
4672
#ifdef QT_DEBUG_DRAW
4673
    if constexpr (qt_show_painter_debug_output)
4674
        printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4675
#endif
4676
4677
0
    Q_D(QPainter);
4678
4679
0
    if (!d->engine || pointCount < 2)
4680
0
        return;
4681
4682
0
    if (d->extended) {
4683
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4684
0
        return;
4685
0
    }
4686
4687
0
    d->updateState(d->state);
4688
4689
0
    uint emulationSpecifier = d->state->emulationSpecifier;
4690
4691
0
    if (emulationSpecifier) {
4692
0
        QPainterPath polygonPath(points[0]);
4693
0
        for (int i=1; i<pointCount; ++i)
4694
0
            polygonPath.lineTo(points[i]);
4695
0
        polygonPath.closeSubpath();
4696
0
        polygonPath.setFillRule(fillRule);
4697
0
        d->draw_helper(polygonPath);
4698
0
        return;
4699
0
    }
4700
4701
0
    d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4702
0
}
4703
4704
/*! \overload
4705
4706
    Draws the polygon defined by the first \a pointCount points in the
4707
    array \a points.
4708
*/
4709
void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
4710
0
{
4711
#ifdef QT_DEBUG_DRAW
4712
    if constexpr (qt_show_painter_debug_output)
4713
        printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4714
#endif
4715
4716
0
    Q_D(QPainter);
4717
4718
0
    if (!d->engine || pointCount < 2)
4719
0
        return;
4720
4721
0
    if (d->extended) {
4722
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4723
0
        return;
4724
0
    }
4725
4726
0
    d->updateState(d->state);
4727
4728
0
    uint emulationSpecifier = d->state->emulationSpecifier;
4729
4730
0
    if (emulationSpecifier) {
4731
0
        QPainterPath polygonPath(points[0]);
4732
0
        for (int i=1; i<pointCount; ++i)
4733
0
            polygonPath.lineTo(points[i]);
4734
0
        polygonPath.closeSubpath();
4735
0
        polygonPath.setFillRule(fillRule);
4736
0
        d->draw_helper(polygonPath);
4737
0
        return;
4738
0
    }
4739
4740
0
    d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4741
0
}
4742
4743
/*! \fn void QPainter::drawPolygon(const QPolygonF &points, Qt::FillRule fillRule)
4744
4745
    \overload
4746
4747
    Draws the polygon defined by the given \a points using the fill
4748
    rule \a fillRule.
4749
*/
4750
4751
/*! \fn void QPainter::drawPolygon(const QPolygon &points, Qt::FillRule fillRule)
4752
4753
    \overload
4754
4755
    Draws the polygon defined by the given \a points using the fill
4756
    rule \a fillRule.
4757
*/
4758
4759
/*!
4760
    \fn void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
4761
4762
    Draws the convex polygon defined by the first \a pointCount points
4763
    in the array \a points using the current pen.
4764
4765
    \table 100%
4766
    \row
4767
    \li \inlineimage qpainter-polygon.png {Four-sided polygon}
4768
    \li
4769
    \snippet code/src_gui_painting_qpainter.cpp 15
4770
    \endtable
4771
4772
    The first point is implicitly connected to the last point, and the
4773
    polygon is filled with the current brush().  If the supplied
4774
    polygon is not convex, i.e. it contains at least one angle larger
4775
    than 180 degrees, the results are undefined.
4776
4777
    On some platforms (e.g. X11), the drawConvexPolygon() function can
4778
    be faster than the drawPolygon() function.
4779
4780
    \sa drawPolygon(), drawPolyline(), {Coordinate System}
4781
*/
4782
4783
/*!
4784
    \fn void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
4785
    \overload
4786
4787
    Draws the convex polygon defined by the first \a pointCount points
4788
    in the array \a points using the current pen.
4789
*/
4790
4791
/*!
4792
    \fn void QPainter::drawConvexPolygon(const QPolygonF &polygon)
4793
4794
    \overload
4795
4796
    Draws the convex polygon defined by \a polygon using the current
4797
    pen and brush.
4798
*/
4799
4800
/*!
4801
    \fn void QPainter::drawConvexPolygon(const QPolygon &polygon)
4802
    \overload
4803
4804
    Draws the convex polygon defined by \a polygon using the current
4805
    pen and brush.
4806
*/
4807
4808
void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
4809
0
{
4810
#ifdef QT_DEBUG_DRAW
4811
    if constexpr (qt_show_painter_debug_output)
4812
        printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4813
#endif
4814
4815
0
    Q_D(QPainter);
4816
4817
0
    if (!d->engine || pointCount < 2)
4818
0
        return;
4819
4820
0
    if (d->extended) {
4821
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4822
0
        return;
4823
0
    }
4824
4825
0
    d->updateState(d->state);
4826
4827
0
    uint emulationSpecifier = d->state->emulationSpecifier;
4828
4829
0
    if (emulationSpecifier) {
4830
0
        QPainterPath polygonPath(points[0]);
4831
0
        for (int i=1; i<pointCount; ++i)
4832
0
            polygonPath.lineTo(points[i]);
4833
0
        polygonPath.closeSubpath();
4834
0
        polygonPath.setFillRule(Qt::WindingFill);
4835
0
        d->draw_helper(polygonPath);
4836
0
        return;
4837
0
    }
4838
4839
0
    d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4840
0
}
4841
4842
void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
4843
0
{
4844
#ifdef QT_DEBUG_DRAW
4845
    if constexpr (qt_show_painter_debug_output)
4846
        printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4847
#endif
4848
4849
0
    Q_D(QPainter);
4850
4851
0
    if (!d->engine || pointCount < 2)
4852
0
        return;
4853
4854
0
    if (d->extended) {
4855
0
        d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4856
0
        return;
4857
0
    }
4858
4859
0
    d->updateState(d->state);
4860
4861
0
    uint emulationSpecifier = d->state->emulationSpecifier;
4862
4863
0
    if (emulationSpecifier) {
4864
0
        QPainterPath polygonPath(points[0]);
4865
0
        for (int i=1; i<pointCount; ++i)
4866
0
            polygonPath.lineTo(points[i]);
4867
0
        polygonPath.closeSubpath();
4868
0
        polygonPath.setFillRule(Qt::WindingFill);
4869
0
        d->draw_helper(polygonPath);
4870
0
        return;
4871
0
    }
4872
4873
0
    d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4874
0
}
4875
4876
static inline QPointF roundInDeviceCoordinates(const QPointF &p, const QTransform &m)
4877
0
{
4878
0
    return m.inverted().map(QPointF(m.map(p).toPoint()));
4879
0
}
4880
4881
/*!
4882
    \fn void QPainter::drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
4883
4884
    Draws the rectangular portion \a source of the given \a pixmap
4885
    into the given \a target in the paint device.
4886
4887
    \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
4888
    \note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
4889
    by QPixmap::devicePixelRatio().
4890
4891
    \table 100%
4892
    \row
4893
    \li
4894
    \snippet code/src_gui_painting_qpainter.cpp 16
4895
    \endtable
4896
4897
    If \a pixmap is a QBitmap it is drawn with the bits that are "set"
4898
    using the pens color. If backgroundMode is Qt::OpaqueMode, the
4899
    "unset" bits are drawn using the color of the background brush; if
4900
    backgroundMode is Qt::TransparentMode, the "unset" bits are
4901
    transparent. Drawing bitmaps with gradient or texture colors is
4902
    not supported.
4903
4904
    \sa drawImage(), QPixmap::devicePixelRatio()
4905
*/
4906
void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
4907
0
{
4908
#if defined QT_DEBUG_DRAW
4909
    if constexpr (qt_show_painter_debug_output)
4910
        printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4911
               p.x(), p.y(),
4912
               pm.width(), pm.height());
4913
#endif
4914
4915
0
    Q_D(QPainter);
4916
4917
0
    if (!d->engine || pm.isNull())
4918
0
        return;
4919
4920
0
#ifndef QT_NO_DEBUG
4921
0
    qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4922
0
#endif
4923
4924
0
    if (d->extended) {
4925
0
        d->extended->drawPixmap(p, pm);
4926
0
        return;
4927
0
    }
4928
4929
0
    qreal x = p.x();
4930
0
    qreal y = p.y();
4931
4932
0
    int w = pm.width();
4933
0
    int h = pm.height();
4934
4935
0
    if (w <= 0)
4936
0
        return;
4937
4938
    // Emulate opaque background for bitmaps
4939
0
    if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4940
0
        fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4941
0
    }
4942
4943
0
    d->updateState(d->state);
4944
4945
0
    if ((d->state->matrix.type() > QTransform::TxTranslate
4946
0
         && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4947
0
        || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4948
0
        || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4949
0
    {
4950
0
        save();
4951
        // If there is no rotation involved we have to make sure we use the
4952
        // antialiased and not the aliased coordinate system by rounding the coordinates.
4953
0
        if (d->state->matrix.type() <= QTransform::TxScale) {
4954
0
            const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4955
0
            x = p.x();
4956
0
            y = p.y();
4957
0
        }
4958
0
        translate(x, y);
4959
0
        setBackgroundMode(Qt::TransparentMode);
4960
0
        setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
4961
0
        QBrush brush(d->state->pen.color(), pm);
4962
0
        setBrush(brush);
4963
0
        setPen(Qt::NoPen);
4964
0
        setBrushOrigin(QPointF(0, 0));
4965
4966
0
        drawRect(pm.rect());
4967
0
        restore();
4968
0
    } else {
4969
0
        if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4970
0
            x += d->state->matrix.dx();
4971
0
            y += d->state->matrix.dy();
4972
0
        }
4973
0
        qreal scale = pm.devicePixelRatio();
4974
0
        d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4975
0
    }
4976
0
}
4977
4978
void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
4979
0
{
4980
#if defined QT_DEBUG_DRAW
4981
    if constexpr (qt_show_painter_debug_output)
4982
        printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4983
               r.x(), r.y(), r.width(), r.height(),
4984
               pm.width(), pm.height(),
4985
               sr.x(), sr.y(), sr.width(), sr.height());
4986
#endif
4987
4988
0
    Q_D(QPainter);
4989
0
    if (!d->engine || pm.isNull())
4990
0
        return;
4991
0
#ifndef QT_NO_DEBUG
4992
0
    qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4993
0
#endif
4994
4995
0
    qreal x = r.x();
4996
0
    qreal y = r.y();
4997
0
    qreal w = r.width();
4998
0
    qreal h = r.height();
4999
0
    qreal sx = sr.x();
5000
0
    qreal sy = sr.y();
5001
0
    qreal sw = sr.width();
5002
0
    qreal sh = sr.height();
5003
5004
    // Get pixmap scale. Use it when calculating the target
5005
    // rect size from pixmap size. For example, a 2X 64x64 pixel
5006
    // pixmap should result in a 32x32 point target rect.
5007
0
    const qreal pmscale = pm.devicePixelRatio();
5008
5009
    // Sanity-check clipping
5010
0
    if (sw <= 0)
5011
0
        sw = pm.width() - sx;
5012
5013
0
    if (sh <= 0)
5014
0
        sh = pm.height() - sy;
5015
5016
0
    if (w < 0)
5017
0
        w = sw / pmscale;
5018
0
    if (h < 0)
5019
0
        h = sh / pmscale;
5020
5021
0
    if (sx < 0) {
5022
0
        qreal w_ratio = sx * w/sw;
5023
0
        x -= w_ratio;
5024
0
        w += w_ratio;
5025
0
        sw += sx;
5026
0
        sx = 0;
5027
0
    }
5028
5029
0
    if (sy < 0) {
5030
0
        qreal h_ratio = sy * h/sh;
5031
0
        y -= h_ratio;
5032
0
        h += h_ratio;
5033
0
        sh += sy;
5034
0
        sy = 0;
5035
0
    }
5036
5037
0
    if (sw + sx > pm.width()) {
5038
0
        qreal delta = sw - (pm.width() - sx);
5039
0
        qreal w_ratio = delta * w/sw;
5040
0
        sw -= delta;
5041
0
        w -= w_ratio;
5042
0
    }
5043
5044
0
    if (sh + sy > pm.height()) {
5045
0
        qreal delta = sh - (pm.height() - sy);
5046
0
        qreal h_ratio = delta * h/sh;
5047
0
        sh -= delta;
5048
0
        h -= h_ratio;
5049
0
    }
5050
5051
0
    if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5052
0
        return;
5053
5054
0
    if (d->extended) {
5055
0
        d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5056
0
        return;
5057
0
    }
5058
5059
    // Emulate opaque background for bitmaps
5060
0
    if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
5061
0
        fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
5062
5063
0
    d->updateState(d->state);
5064
5065
0
    if ((d->state->matrix.type() > QTransform::TxTranslate
5066
0
         && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5067
0
        || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5068
0
        || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
5069
0
        || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
5070
0
    {
5071
0
        save();
5072
        // If there is no rotation involved we have to make sure we use the
5073
        // antialiased and not the aliased coordinate system by rounding the coordinates.
5074
0
        if (d->state->matrix.type() <= QTransform::TxScale) {
5075
0
            const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5076
0
            x = p.x();
5077
0
            y = p.y();
5078
0
        }
5079
5080
0
        if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5081
0
            sx = qRound(sx);
5082
0
            sy = qRound(sy);
5083
0
            sw = qRound(sw);
5084
0
            sh = qRound(sh);
5085
0
        }
5086
5087
0
        translate(x, y);
5088
0
        scale(w / sw, h / sh);
5089
0
        setBackgroundMode(Qt::TransparentMode);
5090
0
        setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5091
0
        QBrush brush;
5092
5093
0
        if (sw == pm.width() && sh == pm.height())
5094
0
            brush = QBrush(d->state->pen.color(), pm);
5095
0
        else
5096
0
            brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
5097
5098
0
        setBrush(brush);
5099
0
        setPen(Qt::NoPen);
5100
5101
0
        drawRect(QRectF(0, 0, sw, sh));
5102
0
        restore();
5103
0
    } else {
5104
0
        if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5105
0
            x += d->state->matrix.dx();
5106
0
            y += d->state->matrix.dy();
5107
0
        }
5108
0
        d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5109
0
    }
5110
0
}
5111
5112
5113
/*!
5114
    \fn void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap,
5115
                                  const QRect &source)
5116
    \overload
5117
5118
    Draws the rectangular portion \a source of the given \a pixmap
5119
    into the given \a target in the paint device.
5120
5121
    \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
5122
*/
5123
5124
/*!
5125
    \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap,
5126
                                  const QRectF &source)
5127
    \overload
5128
5129
    Draws the rectangular portion \a source of the given \a pixmap
5130
    with its origin at the given \a point.
5131
*/
5132
5133
/*!
5134
    \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap,
5135
                                  const QRect &source)
5136
5137
    \overload
5138
5139
    Draws the rectangular portion \a source of the given \a pixmap
5140
    with its origin at the given \a point.
5141
*/
5142
5143
/*!
5144
    \fn void QPainter::drawPixmap(const QPointF &point, const QPixmap &pixmap)
5145
    \overload
5146
5147
    Draws the given \a pixmap with its origin at the given \a point.
5148
*/
5149
5150
/*!
5151
    \fn void QPainter::drawPixmap(const QPoint &point, const QPixmap &pixmap)
5152
    \overload
5153
5154
    Draws the given \a pixmap with its origin at the given \a point.
5155
*/
5156
5157
/*!
5158
    \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap)
5159
5160
    \overload
5161
5162
    Draws the given \a pixmap at position (\a{x}, \a{y}).
5163
*/
5164
5165
/*!
5166
    \fn void QPainter::drawPixmap(const QRect &rectangle, const QPixmap &pixmap)
5167
    \overload
5168
5169
    Draws the given \a  pixmap into the given \a rectangle.
5170
5171
    \note The pixmap is scaled to fit the rectangle, if both the pixmap and rectangle size disagree.
5172
*/
5173
5174
/*!
5175
    \fn void QPainter::drawPixmap(int x, int y, int width, int height,
5176
    const QPixmap &pixmap)
5177
5178
    \overload
5179
5180
    Draws the \a pixmap into the rectangle at position (\a{x}, \a{y})
5181
    with  the given \a width and \a height.
5182
*/
5183
5184
/*!
5185
    \fn void QPainter::drawPixmap(int x, int y, int w, int h, const QPixmap &pixmap,
5186
                                  int sx, int sy, int sw, int sh)
5187
5188
    \overload
5189
5190
    Draws the rectangular portion with the origin (\a{sx}, \a{sy}),
5191
    width \a sw and height \a sh, of the given \a pixmap , at the
5192
    point (\a{x}, \a{y}), with a width of \a w and a height of \a h.
5193
    If sw or sh are equal to zero the width/height of the pixmap
5194
    is used and adjusted by the offset sx/sy;
5195
*/
5196
5197
/*!
5198
    \fn void QPainter::drawPixmap(int x, int y, const QPixmap &pixmap,
5199
                                  int sx, int sy, int sw, int sh)
5200
5201
    \overload
5202
5203
    Draws a pixmap at (\a{x}, \a{y}) by copying a part of the given \a
5204
    pixmap into the paint device.
5205
5206
    (\a{x}, \a{y}) specifies the top-left point in the paint device that is
5207
    to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
5208
    pixmap that is to be drawn. The default is (0, 0).
5209
5210
    (\a{sw}, \a{sh}) specifies the size of the pixmap that is to be drawn.
5211
    The default, (0, 0) (and negative) means all the way to the
5212
    bottom-right of the pixmap.
5213
*/
5214
5215
void QPainter::drawImage(const QPointF &p, const QImage &image)
5216
2.41M
{
5217
2.41M
    Q_D(QPainter);
5218
5219
2.41M
    if (!d->engine || image.isNull())
5220
66.4k
        return;
5221
5222
2.34M
    if (d->extended) {
5223
2.34M
        d->extended->drawImage(p, image);
5224
2.34M
        return;
5225
2.34M
    }
5226
5227
0
    qreal x = p.x();
5228
0
    qreal y = p.y();
5229
5230
0
    int w = image.width();
5231
0
    int h = image.height();
5232
0
    qreal scale = image.devicePixelRatio();
5233
5234
0
    d->updateState(d->state);
5235
5236
0
    if (((d->state->matrix.type() > QTransform::TxTranslate)
5237
0
         && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5238
0
        || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5239
0
        || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5240
0
    {
5241
0
        save();
5242
        // If there is no rotation involved we have to make sure we use the
5243
        // antialiased and not the aliased coordinate system by rounding the coordinates.
5244
0
        if (d->state->matrix.type() <= QTransform::TxScale) {
5245
0
            const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5246
0
            x = p.x();
5247
0
            y = p.y();
5248
0
        }
5249
0
        translate(x, y);
5250
0
        setBackgroundMode(Qt::TransparentMode);
5251
0
        setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5252
0
        QBrush brush(image);
5253
0
        setBrush(brush);
5254
0
        setPen(Qt::NoPen);
5255
0
        setBrushOrigin(QPointF(0, 0));
5256
0
        drawRect(QRect(QPoint(0, 0), image.size() / scale));
5257
0
        restore();
5258
0
        return;
5259
0
    }
5260
5261
0
    if (d->state->matrix.type() == QTransform::TxTranslate
5262
0
        && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5263
0
        x += d->state->matrix.dx();
5264
0
        y += d->state->matrix.dy();
5265
0
    }
5266
5267
0
    d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5268
0
}
5269
5270
void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
5271
                         Qt::ImageConversionFlags flags)
5272
0
{
5273
0
    Q_D(QPainter);
5274
5275
0
    if (!d->engine || image.isNull())
5276
0
        return;
5277
5278
0
    qreal x = targetRect.x();
5279
0
    qreal y = targetRect.y();
5280
0
    qreal w = targetRect.width();
5281
0
    qreal h = targetRect.height();
5282
0
    qreal sx = sourceRect.x();
5283
0
    qreal sy = sourceRect.y();
5284
0
    qreal sw = sourceRect.width();
5285
0
    qreal sh = sourceRect.height();
5286
0
    qreal imageScale = image.devicePixelRatio();
5287
5288
    // Sanity-check clipping
5289
0
    if (sw <= 0)
5290
0
        sw = image.width() - sx;
5291
5292
0
    if (sh <= 0)
5293
0
        sh = image.height() - sy;
5294
5295
0
    if (w < 0)
5296
0
        w = sw / imageScale;
5297
0
    if (h < 0)
5298
0
        h = sh / imageScale;
5299
5300
0
    if (sx < 0) {
5301
0
        qreal w_ratio = sx * w/sw;
5302
0
        x -= w_ratio;
5303
0
        w += w_ratio;
5304
0
        sw += sx;
5305
0
        sx = 0;
5306
0
    }
5307
5308
0
    if (sy < 0) {
5309
0
        qreal h_ratio = sy * h/sh;
5310
0
        y -= h_ratio;
5311
0
        h += h_ratio;
5312
0
        sh += sy;
5313
0
        sy = 0;
5314
0
    }
5315
5316
0
    if (sw + sx > image.width()) {
5317
0
        qreal delta = sw - (image.width() - sx);
5318
0
        qreal w_ratio = delta * w/sw;
5319
0
        sw -= delta;
5320
0
        w -= w_ratio;
5321
0
    }
5322
5323
0
    if (sh + sy > image.height()) {
5324
0
        qreal delta = sh - (image.height() - sy);
5325
0
        qreal h_ratio = delta * h/sh;
5326
0
        sh -= delta;
5327
0
        h -= h_ratio;
5328
0
    }
5329
5330
0
    if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5331
0
        return;
5332
5333
0
    if (d->extended) {
5334
0
        d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5335
0
        return;
5336
0
    }
5337
5338
0
    d->updateState(d->state);
5339
5340
0
    if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5341
0
         && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5342
0
        || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5343
0
        || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5344
0
    {
5345
0
        save();
5346
        // If there is no rotation involved we have to make sure we use the
5347
        // antialiased and not the aliased coordinate system by rounding the coordinates.
5348
0
        if (d->state->matrix.type() <= QTransform::TxScale) {
5349
0
            const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5350
0
            x = p.x();
5351
0
            y = p.y();
5352
0
        }
5353
5354
0
        if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5355
0
            sx = qRound(sx);
5356
0
            sy = qRound(sy);
5357
0
            sw = qRound(sw);
5358
0
            sh = qRound(sh);
5359
0
        }
5360
0
        translate(x, y);
5361
0
        scale(w / sw, h / sh);
5362
0
        setBackgroundMode(Qt::TransparentMode);
5363
0
        setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5364
0
        QBrush brush(image);
5365
0
        setBrush(brush);
5366
0
        setPen(Qt::NoPen);
5367
0
        setBrushOrigin(QPointF(-sx, -sy));
5368
5369
0
        drawRect(QRectF(0, 0, sw, sh));
5370
0
        restore();
5371
0
        return;
5372
0
    }
5373
5374
0
    if (d->state->matrix.type() == QTransform::TxTranslate
5375
0
        && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5376
0
        x += d->state->matrix.dx();
5377
0
        y += d->state->matrix.dy();
5378
0
    }
5379
5380
0
    d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5381
0
}
5382
5383
/*!
5384
    \fn void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphs)
5385
5386
    Draws the glyphs represented by \a glyphs at \a position. The \a position gives the
5387
    edge of the baseline for the string of glyphs. The glyphs will be retrieved from the font
5388
    selected on \a glyphs and at offsets given by the positions in \a glyphs.
5389
5390
    \since 4.8
5391
5392
    \sa QGlyphRun::setRawFont(), QGlyphRun::setPositions(), QGlyphRun::setGlyphIndexes()
5393
*/
5394
#if !defined(QT_NO_RAWFONT)
5395
void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
5396
0
{
5397
0
    Q_D(QPainter);
5398
5399
0
    if (!d->engine) {
5400
0
        qWarning("QPainter::drawGlyphRun: Painter not active");
5401
0
        return;
5402
0
    }
5403
5404
0
    QRawFont font = glyphRun.rawFont();
5405
0
    if (!font.isValid())
5406
0
        return;
5407
5408
0
    QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5409
5410
0
    const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5411
0
    const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5412
5413
0
    int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5414
0
    QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5415
5416
0
    QRawFontPrivate *fontD = QRawFontPrivate::get(font);
5417
0
    bool engineRequiresPretransformedGlyphPositions = d->extended
5418
0
        ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5419
0
        : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5420
5421
0
    for (int i=0; i<count; ++i) {
5422
0
        QPointF processedPosition = position + glyphPositions[i];
5423
0
        if (engineRequiresPretransformedGlyphPositions)
5424
0
            processedPosition = d->state->transform().map(processedPosition);
5425
0
        fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5426
0
    }
5427
5428
0
    d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5429
0
                    ? d->state->transform().map(position)
5430
0
                    : position,
5431
0
                  glyphIndexes,
5432
0
                  fixedPointPositions.data(),
5433
0
                  count,
5434
0
                  fontD->fontEngine,
5435
0
                  glyphRun.overline(),
5436
0
                  glyphRun.underline(),
5437
0
                  glyphRun.strikeOut());
5438
0
}
5439
5440
void QPainterPrivate::drawGlyphs(const QPointF &decorationPosition,
5441
                                 const quint32 *glyphArray,
5442
                                 QFixedPoint *positions,
5443
                                 int glyphCount,
5444
                                 QFontEngine *fontEngine,
5445
                                 bool overline,
5446
                                 bool underline,
5447
                                 bool strikeOut)
5448
0
{
5449
0
    Q_Q(QPainter);
5450
5451
0
    updateState(state);
5452
5453
0
    if (extended != nullptr && state->matrix.isAffine()) {
5454
0
        QStaticTextItem staticTextItem;
5455
0
        staticTextItem.color = state->pen.color();
5456
0
        staticTextItem.font = state->font;
5457
0
        staticTextItem.setFontEngine(fontEngine);
5458
0
        staticTextItem.numGlyphs = glyphCount;
5459
0
        staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray));
5460
0
        staticTextItem.glyphPositions = positions;
5461
        // The font property is meaningless, the fontengine must be used directly:
5462
0
        staticTextItem.usesRawFont = true;
5463
5464
0
        extended->drawStaticTextItem(&staticTextItem);
5465
0
    } else {
5466
0
        QTextItemInt textItem;
5467
0
        textItem.fontEngine = fontEngine;
5468
5469
0
        QVarLengthArray<QFixed, 128> advances(glyphCount);
5470
0
        QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5471
0
        QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5472
0
        memset(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(QGlyphAttributes));
5473
0
        memset(static_cast<void *>(advances.data()), 0, advances.size() * sizeof(QFixed));
5474
0
        memset(static_cast<void *>(glyphJustifications.data()), 0, glyphJustifications.size() * sizeof(QGlyphJustification));
5475
5476
0
        textItem.glyphs.numGlyphs = glyphCount;
5477
0
        textItem.glyphs.glyphs = const_cast<glyph_t *>(glyphArray);
5478
0
        textItem.glyphs.offsets = positions;
5479
0
        textItem.glyphs.advances = advances.data();
5480
0
        textItem.glyphs.justifications = glyphJustifications.data();
5481
0
        textItem.glyphs.attributes = glyphAttributes.data();
5482
5483
0
        engine->drawTextItem(QPointF(0, 0), textItem);
5484
0
    }
5485
5486
0
    qt_draw_decoration_for_glyphs(q,
5487
0
                                  decorationPosition,
5488
0
                                  glyphArray,
5489
0
                                  positions,
5490
0
                                  glyphCount,
5491
0
                                  fontEngine,
5492
0
                                  underline,
5493
0
                                  overline,
5494
0
                                  strikeOut);
5495
0
}
5496
#endif // QT_NO_RAWFONT
5497
5498
/*!
5499
5500
    \fn void QPainter::drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText)
5501
    \since 4.7
5502
    \overload
5503
5504
    Draws the \a staticText at the \a topLeftPosition.
5505
5506
    \note The y-position is used as the top of the font.
5507
5508
*/
5509
5510
/*!
5511
    \fn void QPainter::drawStaticText(int left, int top, const QStaticText &staticText)
5512
    \since 4.7
5513
    \overload
5514
5515
    Draws the \a staticText at coordinates \a left and \a top.
5516
5517
    \note The y-position is used as the top of the font.
5518
*/
5519
5520
/*!
5521
    \fn void QPainter::drawText(const QPointF &position, const QString &text)
5522
5523
    Draws the given \a text with the currently defined text direction,
5524
    beginning at the given \a position.
5525
5526
    This function does not handle the newline character (\\n), as it cannot
5527
    break text into multiple lines, and it cannot display the newline character.
5528
    Use the QPainter::drawText() overload that takes a rectangle instead
5529
    if you want to draw multiple lines of text with the newline character, or
5530
    if you want the text to be wrapped.
5531
5532
    By default, QPainter draws text anti-aliased.
5533
5534
    \note The y-position is used as the baseline of the font.
5535
5536
    \sa setFont(), setPen()
5537
*/
5538
5539
void QPainter::drawText(const QPointF &p, const QString &str)
5540
0
{
5541
0
    drawText(p, str, 0, 0);
5542
0
}
5543
5544
/*!
5545
    \since 4.7
5546
5547
    Draws the given \a staticText at the given \a topLeftPosition.
5548
5549
    The text will be drawn using the font and the transformation set on the painter. If the
5550
    font and/or transformation set on the painter are different from the ones used to initialize
5551
    the layout of the QStaticText, then the layout will have to be recalculated. Use
5552
    QStaticText::prepare() to initialize \a staticText with the font and transformation with which
5553
    it will later be drawn.
5554
5555
    If \a topLeftPosition is not the same as when \a staticText was initialized, or when it was
5556
    last drawn, then there will be a slight overhead when translating the text to its new position.
5557
5558
    \note If the painter's transformation is not affine, then \a staticText will be drawn using
5559
    regular calls to drawText(), losing any potential for performance improvement.
5560
5561
    \note The y-position is used as the top of the font.
5562
5563
    \sa QStaticText
5564
*/
5565
void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
5566
0
{
5567
0
    Q_D(QPainter);
5568
0
    if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5569
0
        return;
5570
5571
0
    QStaticTextPrivate *staticText_d =
5572
0
            const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5573
5574
0
    QFontPrivate *fp = QFontPrivate::get(font());
5575
0
    QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5576
0
    if (font() != staticText_d->font || fp == nullptr || stfp == nullptr || fp->dpi != stfp->dpi) {
5577
0
        staticText_d->font = font();
5578
0
        staticText_d->needsRelayout = true;
5579
0
    } else if (stfp->engineData == nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5580
0
        staticText_d->needsRelayout = true;
5581
0
    }
5582
5583
0
    QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5584
0
    if (fe->type() == QFontEngine::Multi)
5585
0
        fe = static_cast<QFontEngineMulti *>(fe)->engine(0);
5586
5587
    // If we don't have an extended paint engine, if the painter is projected,
5588
    // or if the font engine does not support the matrix, we go through standard
5589
    // code path
5590
0
    if (d->extended == nullptr
5591
0
            || !d->state->matrix.isAffine()
5592
0
            || !fe->supportsTransformation(d->state->matrix)) {
5593
0
        staticText_d->paintText(topLeftPosition, this, pen().color());
5594
0
        return;
5595
0
    }
5596
5597
0
    bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5598
0
    if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5599
        // The coordinates are untransformed, and the engine can't deal with that
5600
        // nativly, so we have to pre-transform the static text.
5601
0
        staticText_d->untransformedCoordinates = false;
5602
0
        staticText_d->needsRelayout = true;
5603
0
    } else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5604
        // The coordinates are already transformed, but the engine can handle that
5605
        // nativly, so undo the transform of the static text.
5606
0
        staticText_d->untransformedCoordinates = true;
5607
0
        staticText_d->needsRelayout = true;
5608
0
    }
5609
5610
    // Don't recalculate entire layout because of translation, rather add the dx and dy
5611
    // into the position to move each text item the correct distance.
5612
0
    QPointF transformedPosition = topLeftPosition;
5613
0
    if (!staticText_d->untransformedCoordinates)
5614
0
        transformedPosition = transformedPosition * d->state->matrix;
5615
0
    QTransform oldMatrix;
5616
5617
    // The translation has been applied to transformedPosition. Remove translation
5618
    // component from matrix.
5619
0
    if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5620
0
        qreal m11 = d->state->matrix.m11();
5621
0
        qreal m12 = d->state->matrix.m12();
5622
0
        qreal m13 = d->state->matrix.m13();
5623
0
        qreal m21 = d->state->matrix.m21();
5624
0
        qreal m22 = d->state->matrix.m22();
5625
0
        qreal m23 = d->state->matrix.m23();
5626
0
        qreal m33 = d->state->matrix.m33();
5627
5628
0
        oldMatrix = d->state->matrix;
5629
0
        d->state->matrix.setMatrix(m11, m12, m13,
5630
0
                                   m21, m22, m23,
5631
0
                                   0.0, 0.0, m33);
5632
0
    }
5633
5634
    // If the transform is not identical to the text transform,
5635
    // we have to relayout the text (for other transformations than plain translation)
5636
0
    bool staticTextNeedsReinit = staticText_d->needsRelayout;
5637
0
    if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5638
0
        staticText_d->matrix = d->state->matrix;
5639
0
        staticTextNeedsReinit = true;
5640
0
    }
5641
5642
    // Recreate the layout of the static text because the matrix or font has changed
5643
0
    if (staticTextNeedsReinit)
5644
0
        staticText_d->init();
5645
5646
0
    if (transformedPosition != staticText_d->position) { // Translate to actual position
5647
0
        QFixed fx = QFixed::fromReal(transformedPosition.x());
5648
0
        QFixed fy = QFixed::fromReal(transformedPosition.y());
5649
0
        QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5650
0
        QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5651
0
        for (int item=0; item<staticText_d->itemCount;++item) {
5652
0
            QStaticTextItem *textItem = staticText_d->items + item;
5653
0
            for (int i=0; i<textItem->numGlyphs; ++i) {
5654
0
                textItem->glyphPositions[i].x += fx - oldX;
5655
0
                textItem->glyphPositions[i].y += fy - oldY;
5656
0
            }
5657
0
            textItem->userDataNeedsUpdate = true;
5658
0
        }
5659
5660
0
        staticText_d->position = transformedPosition;
5661
0
    }
5662
5663
0
    QPen oldPen = d->state->pen;
5664
0
    QColor currentColor = oldPen.color();
5665
0
    static const QColor bodyIndicator(0, 0, 0, 0);
5666
0
    for (int i=0; i<staticText_d->itemCount; ++i) {
5667
0
        QStaticTextItem *item = staticText_d->items + i;
5668
0
        if (item->color.isValid() && currentColor != item->color
5669
0
            && item->color != bodyIndicator) {
5670
0
                setPen(item->color);
5671
0
                currentColor = item->color;
5672
0
        } else if (item->color == bodyIndicator) {
5673
0
            setPen(oldPen);
5674
0
            currentColor = oldPen.color();
5675
0
        }
5676
0
        d->extended->drawStaticTextItem(item);
5677
5678
0
        qt_draw_decoration_for_glyphs(this,
5679
0
                                      topLeftPosition,
5680
0
                                      item->glyphs,
5681
0
                                      item->glyphPositions,
5682
0
                                      item->numGlyphs,
5683
0
                                      item->fontEngine(),
5684
0
                                      staticText_d->font.underline(),
5685
0
                                      staticText_d->font.overline(),
5686
0
                                      staticText_d->font.strikeOut());
5687
0
    }
5688
0
    if (currentColor != oldPen.color())
5689
0
        setPen(oldPen);
5690
5691
0
    if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5692
0
        d->state->matrix = oldMatrix;
5693
0
}
5694
5695
/*!
5696
   \internal
5697
*/
5698
void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
5699
0
{
5700
#ifdef QT_DEBUG_DRAW
5701
    if constexpr (qt_show_painter_debug_output)
5702
        printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5703
#endif
5704
5705
0
    Q_D(QPainter);
5706
5707
0
    if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5708
0
        return;
5709
5710
0
    Q_DECL_UNINITIALIZED QStackTextEngine engine(str, d->state->font);
5711
0
    engine.option.setTextDirection(d->state->layoutDirection);
5712
0
    if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
5713
0
        engine.ignoreBidi = true;
5714
0
        engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5715
0
    }
5716
0
    engine.itemize();
5717
0
    QScriptLine line;
5718
0
    line.length = str.size();
5719
0
    engine.shapeLine(line);
5720
5721
0
    int nItems = engine.layoutData->items.size();
5722
0
    QVarLengthArray<int> visualOrder(nItems);
5723
0
    QVarLengthArray<uchar> levels(nItems);
5724
0
    for (int i = 0; i < nItems; ++i)
5725
0
        levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5726
0
    QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5727
5728
0
    if (justificationPadding > 0) {
5729
0
        engine.option.setAlignment(Qt::AlignJustify);
5730
0
        engine.forceJustification = true;
5731
        // this works because justify() is only interested in the difference between width and textWidth
5732
0
        line.width = justificationPadding;
5733
0
        engine.justify(line);
5734
0
    }
5735
0
    QFixed x = QFixed::fromReal(p.x());
5736
5737
0
    for (int i = 0; i < nItems; ++i) {
5738
0
        int item = visualOrder[i];
5739
0
        const QScriptItem &si = engine.layoutData->items.at(item);
5740
0
        if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
5741
0
            x += si.width;
5742
0
            continue;
5743
0
        }
5744
0
        QFont f = engine.font(si);
5745
0
        QTextItemInt gf(si, &f);
5746
0
        gf.glyphs = engine.shapedGlyphs(&si);
5747
0
        gf.chars = engine.layoutData->string.unicode() + si.position;
5748
0
        gf.num_chars = engine.length(item);
5749
0
        if (engine.forceJustification) {
5750
0
            for (int j=0; j<gf.glyphs.numGlyphs; ++j)
5751
0
                gf.width += gf.glyphs.effectiveAdvance(j);
5752
0
        } else {
5753
0
            gf.width = si.width;
5754
0
        }
5755
0
        gf.logClusters = engine.logClusters(&si);
5756
5757
0
        drawTextItem(QPointF(x.toReal(), p.y()), gf);
5758
5759
0
        x += gf.width;
5760
0
    }
5761
0
}
5762
5763
void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
5764
0
{
5765
#ifdef QT_DEBUG_DRAW
5766
    if constexpr (qt_show_painter_debug_output)
5767
        printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
5768
           r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5769
#endif
5770
5771
0
    Q_D(QPainter);
5772
5773
0
    if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5774
0
        return;
5775
5776
0
    if (!d->extended)
5777
0
        d->updateState(d->state);
5778
5779
0
    QRectF bounds;
5780
0
    qt_format_text(d->state->font, r, flags, nullptr, str, br ? &bounds : nullptr, 0, nullptr, 0, this);
5781
0
    if (br)
5782
0
        *br = bounds.toAlignedRect();
5783
0
}
5784
5785
/*!
5786
    \fn void QPainter::drawText(const QPoint &position, const QString &text)
5787
5788
    \overload
5789
5790
    Draws the given \a text with the currently defined text direction,
5791
    beginning at the given \a position.
5792
5793
    By default, QPainter draws text anti-aliased.
5794
5795
    \note The y-position is used as the baseline of the font.
5796
5797
    \sa setFont(), setPen()
5798
*/
5799
5800
/*!
5801
    \fn void QPainter::drawText(const QRectF &rectangle, int flags, const QString &text, QRectF *boundingRect)
5802
    \overload
5803
5804
    Draws the given \a text within the provided \a rectangle.
5805
    The \a rectangle along with alignment \a flags defines the anchors for the \a text.
5806
5807
    \table 100%
5808
    \row
5809
    \li \inlineimage qpainter-text.png {Text showing Qt Project}
5810
    \li
5811
    \snippet code/src_gui_painting_qpainter.cpp 17
5812
    \endtable
5813
5814
    The \a boundingRect (if not null) is set to what the bounding rectangle
5815
    should be in order to enclose the whole text. For example, in the following
5816
    image, the dotted line represents \a boundingRect as calculated by the
5817
    function, and the dashed line represents \a rectangle:
5818
5819
    \table 100%
5820
    \row
5821
    \li \inlineimage qpainter-text-bounds.png {Text with bounding rectangles}
5822
    \li \snippet code/src_gui_painting_qpainter.cpp drawText
5823
    \endtable
5824
5825
    The \a flags argument is a bitwise OR of the following flags:
5826
5827
    \list
5828
    \li Qt::AlignLeft
5829
    \li Qt::AlignRight
5830
    \li Qt::AlignHCenter
5831
    \li Qt::AlignJustify
5832
    \li Qt::AlignTop
5833
    \li Qt::AlignBottom
5834
    \li Qt::AlignVCenter
5835
    \li Qt::AlignCenter
5836
    \li Qt::TextDontClip
5837
    \li Qt::TextSingleLine
5838
    \li Qt::TextExpandTabs
5839
    \li Qt::TextShowMnemonic
5840
    \li Qt::TextWordWrap
5841
    \li Qt::TextIncludeTrailingSpaces
5842
    \endlist
5843
5844
    \sa Qt::AlignmentFlag, Qt::TextFlag, boundingRect(), layoutDirection()
5845
5846
    By default, QPainter draws text anti-aliased.
5847
5848
    \note The y-coordinate of \a rectangle is used as the top of the font.
5849
*/
5850
void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
5851
0
{
5852
#ifdef QT_DEBUG_DRAW
5853
    if constexpr (qt_show_painter_debug_output)
5854
        printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
5855
           r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5856
#endif
5857
5858
0
    Q_D(QPainter);
5859
5860
0
    if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5861
0
        return;
5862
5863
0
    if (!d->extended)
5864
0
        d->updateState(d->state);
5865
5866
0
    qt_format_text(d->state->font, r, flags, nullptr, str, br, 0, nullptr, 0, this);
5867
0
}
5868
5869
/*!
5870
    \fn void QPainter::drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect)
5871
    \overload
5872
5873
    Draws the given \a text within the provided \a rectangle according
5874
    to the specified \a flags.
5875
5876
    The \a boundingRect (if not null) is set to the what the bounding rectangle
5877
    should be in order to enclose the whole text. For example, in the following
5878
    image, the dotted line represents \a boundingRect as calculated by the
5879
    function, and the dashed line represents \a rectangle:
5880
5881
    \table 100%
5882
    \row
5883
    \li \inlineimage qpainter-text-bounds.png {Text with bounding rectangles}
5884
    \li \snippet code/src_gui_painting_qpainter.cpp drawText
5885
    \endtable
5886
5887
    By default, QPainter draws text anti-aliased.
5888
5889
    \note The y-coordinate of \a rectangle is used as the top of the font.
5890
5891
    \sa setFont(), setPen()
5892
*/
5893
5894
/*!
5895
    \fn void QPainter::drawText(int x, int y, const QString &text)
5896
5897
    \overload
5898
5899
    Draws the given \a text at position (\a{x}, \a{y}), using the painter's
5900
    currently defined text direction.
5901
5902
    By default, QPainter draws text anti-aliased.
5903
5904
    \note The y-position is used as the baseline of the font.
5905
5906
    \sa setFont(), setPen()
5907
*/
5908
5909
/*!
5910
    \fn void QPainter::drawText(int x, int y, int width, int height, int flags,
5911
                                const QString &text, QRect *boundingRect)
5912
5913
    \overload
5914
5915
    Draws the given \a text within the rectangle with origin (\a{x},
5916
    \a{y}), \a width and \a height.
5917
5918
    The \a boundingRect (if not null) is set to the what the bounding rectangle
5919
    should be in order to enclose the whole text. For example, in the following
5920
    image, the dotted line represents \a boundingRect as calculated by the
5921
    function, and the dashed line represents the rectangle defined by
5922
    \a x, \a y, \a width and \a height:
5923
5924
    \table 100%
5925
    \row
5926
    \li \inlineimage qpainter-text-bounds.png {Text with bounding rectangles}
5927
    \li \snippet code/src_gui_painting_qpainter.cpp drawText
5928
    \endtable
5929
5930
    The \a flags argument is a bitwise OR of the following flags:
5931
5932
    \list
5933
    \li Qt::AlignLeft
5934
    \li Qt::AlignRight
5935
    \li Qt::AlignHCenter
5936
    \li Qt::AlignJustify
5937
    \li Qt::AlignTop
5938
    \li Qt::AlignBottom
5939
    \li Qt::AlignVCenter
5940
    \li Qt::AlignCenter
5941
    \li Qt::TextSingleLine
5942
    \li Qt::TextExpandTabs
5943
    \li Qt::TextShowMnemonic
5944
    \li Qt::TextWordWrap
5945
    \endlist
5946
5947
    By default, QPainter draws text anti-aliased.
5948
5949
    \note The y-position is used as the top of the font.
5950
5951
    \sa Qt::AlignmentFlag, Qt::TextFlag, setFont(), setPen()
5952
*/
5953
5954
/*!
5955
    \fn void QPainter::drawText(const QRectF &rectangle, const QString &text,
5956
        const QTextOption &option)
5957
    \overload
5958
5959
    Draws the given \a text in the \a rectangle specified using the \a option
5960
    to control its positioning, direction, and orientation. The options given
5961
    in \a option override those set on the QPainter object itself.
5962
5963
    By default, QPainter draws text anti-aliased.
5964
5965
    \note The y-coordinate of \a rectangle is used as the top of the font.
5966
5967
    \sa setFont(), setPen()
5968
*/
5969
void QPainter::drawText(const QRectF &r, const QString &text, const QTextOption &o)
5970
0
{
5971
#ifdef QT_DEBUG_DRAW
5972
    if constexpr (qt_show_painter_debug_output)
5973
        printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
5974
           r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
5975
#endif
5976
5977
0
    Q_D(QPainter);
5978
5979
0
    if (!d->engine || text.size() == 0 || pen().style() == Qt::NoPen)
5980
0
        return;
5981
5982
0
    if (!d->extended)
5983
0
        d->updateState(d->state);
5984
5985
0
    qt_format_text(d->state->font, r, 0, &o, text, nullptr, 0, nullptr, 0, this);
5986
0
}
5987
5988
/*!
5989
    \fn void QPainter::drawTextItem(int x, int y, const QTextItem &ti)
5990
5991
    \internal
5992
    \overload
5993
*/
5994
5995
/*!
5996
    \fn void QPainter::drawTextItem(const QPoint &p, const QTextItem &ti)
5997
5998
    \internal
5999
    \overload
6000
6001
    Draws the text item \a ti at position \a p.
6002
*/
6003
6004
/*!
6005
    \fn void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti)
6006
6007
    \internal
6008
    \since 4.1
6009
6010
    Draws the text item \a ti at position \a p.
6011
6012
    This method ignores the painters background mode and
6013
    color. drawText and qt_format_text have to do it themselves, as
6014
    only they know the extents of the complete string.
6015
6016
    It ignores the font set on the painter as the text item has one of its own.
6017
6018
    The underline and strikeout parameters of the text items font are
6019
    ignored as well. You'll need to pass in the correct flags to get
6020
    underlining and strikeout.
6021
*/
6022
6023
static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
6024
0
{
6025
0
    const qreal radiusBase = qMax(qreal(1), maxRadius);
6026
6027
0
    QString key = "WaveUnderline-"_L1
6028
0
                  % pen.color().name()
6029
0
                  % HexString<qreal>(radiusBase)
6030
0
                  % HexString<qreal>(pen.widthF());
6031
6032
0
    QPixmap pixmap;
6033
0
    if (QPixmapCache::find(key, &pixmap))
6034
0
        return pixmap;
6035
6036
0
    const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio
6037
0
    const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
6038
0
    const qreal radius = qFloor(radiusBase * 2) / 2.;
6039
6040
0
    QPainterPath path;
6041
6042
0
    qreal xs = 0;
6043
0
    qreal ys = radius;
6044
6045
0
    while (xs < width) {
6046
0
        xs += halfPeriod;
6047
0
        ys = -ys;
6048
0
        path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
6049
0
    }
6050
6051
0
    pixmap = QPixmap(width, radius * 2);
6052
0
    pixmap.fill(Qt::transparent);
6053
0
    {
6054
0
        QPen wavePen = pen;
6055
0
        wavePen.setCapStyle(Qt::SquareCap);
6056
6057
        // This is to protect against making the line too fat, as happens on OS X
6058
        // due to it having a rather thick width for the regular underline.
6059
0
        const qreal maxPenWidth = .8 * radius;
6060
0
        if (wavePen.widthF() > maxPenWidth)
6061
0
            wavePen.setWidthF(maxPenWidth);
6062
6063
0
        QPainter imgPainter(&pixmap);
6064
0
        imgPainter.setPen(wavePen);
6065
0
        imgPainter.setRenderHint(QPainter::Antialiasing);
6066
0
        imgPainter.translate(0, radius);
6067
0
        imgPainter.drawPath(path);
6068
0
    }
6069
6070
0
    QPixmapCache::insert(key, pixmap);
6071
6072
0
    return pixmap;
6073
0
}
6074
6075
static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine,
6076
                                   QTextCharFormat::UnderlineStyle underlineStyle,
6077
                                   QTextItem::RenderFlags flags, qreal width,
6078
                                   const QTextCharFormat &charFormat)
6079
0
{
6080
0
    if (underlineStyle == QTextCharFormat::NoUnderline
6081
0
        && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
6082
0
        return;
6083
6084
0
    const QPen oldPen = painter->pen();
6085
0
    const QBrush oldBrush = painter->brush();
6086
0
    painter->setBrush(Qt::NoBrush);
6087
0
    QPen pen = oldPen;
6088
0
    pen.setStyle(Qt::SolidLine);
6089
0
    pen.setWidthF(fe->lineThickness().toReal());
6090
0
    pen.setCapStyle(Qt::FlatCap);
6091
6092
0
    QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
6093
6094
0
    const qreal underlineOffset = fe->underlinePosition().toReal();
6095
6096
0
    if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
6097
0
        QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
6098
0
        if (theme)
6099
0
            underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt());
6100
0
        if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved
6101
0
            underlineStyle = QTextCharFormat::WaveUnderline;
6102
0
    }
6103
6104
0
    if (underlineStyle == QTextCharFormat::WaveUnderline) {
6105
0
        painter->save();
6106
0
        painter->translate(0, pos.y() + 1);
6107
0
        qreal maxHeight = fe->descent().toReal() - qreal(1);
6108
6109
0
        QColor uc = charFormat.underlineColor();
6110
0
        if (uc.isValid())
6111
0
            pen.setColor(uc);
6112
6113
        // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
6114
0
        const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
6115
0
        const int descent = qFloor(maxHeight);
6116
6117
0
        painter->setBrushOrigin(painter->brushOrigin().x(), 0);
6118
0
        painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
6119
0
        painter->restore();
6120
0
    } else if (underlineStyle != QTextCharFormat::NoUnderline) {
6121
0
        const bool isAntialiasing = painter->renderHints().testFlag(QPainter::Antialiasing);
6122
0
        if (!isAntialiasing)
6123
0
            pen.setWidthF(qMax(fe->lineThickness().round(), QFixed(1)).toReal());
6124
0
        const qreal lineThicknessOffset = pen.widthF() / 2.0;
6125
6126
        // Deliberately ceil the offset to avoid the underline coming too close to
6127
        // the text above it, but limit it to stay within descent.
6128
0
        qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + lineThicknessOffset;
6129
0
        if (underlineOffset <= fe->descent().toReal())
6130
0
            adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - lineThicknessOffset);
6131
0
        const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6132
0
        QColor uc = charFormat.underlineColor();
6133
0
        if (uc.isValid())
6134
0
            pen.setColor(uc);
6135
6136
0
        pen.setStyle((Qt::PenStyle)(underlineStyle));
6137
0
        painter->setPen(pen);
6138
0
        QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6139
0
        if (textEngine)
6140
0
            textEngine->addUnderline(painter, underline);
6141
0
        else
6142
0
            painter->drawLine(underline);
6143
6144
0
        if (!isAntialiasing)
6145
0
            pen.setWidthF(fe->lineThickness().toReal());
6146
0
    }
6147
6148
0
    pen.setStyle(Qt::SolidLine);
6149
0
    pen.setColor(oldPen.color());
6150
6151
0
    if (flags & QTextItem::StrikeOut) {
6152
0
        QLineF strikeOutLine = line;
6153
0
        strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6154
0
        QColor uc = charFormat.underlineColor();
6155
0
        if (uc.isValid())
6156
0
            pen.setColor(uc);
6157
0
        painter->setPen(pen);
6158
0
        if (textEngine)
6159
0
            textEngine->addStrikeOut(painter, strikeOutLine);
6160
0
        else
6161
0
            painter->drawLine(strikeOutLine);
6162
0
    }
6163
6164
0
    if (flags & QTextItem::Overline) {
6165
0
        QLineF overline = line;
6166
0
        overline.translate(0., - fe->ascent().toReal());
6167
0
        QColor uc = charFormat.underlineColor();
6168
0
        if (uc.isValid())
6169
0
            pen.setColor(uc);
6170
0
        painter->setPen(pen);
6171
0
        if (textEngine)
6172
0
            textEngine->addOverline(painter, overline);
6173
0
        else
6174
0
            painter->drawLine(overline);
6175
0
    }
6176
6177
0
    painter->setPen(oldPen);
6178
0
    painter->setBrush(oldBrush);
6179
0
}
6180
6181
static void qt_draw_decoration_for_glyphs(QPainter *painter,
6182
                                          const QPointF &decorationPosition,
6183
                                          const glyph_t *glyphArray,
6184
                                          const QFixedPoint *positions,
6185
                                          int glyphCount,
6186
                                          QFontEngine *fontEngine,
6187
                                          bool underline,
6188
                                          bool overline,
6189
                                          bool strikeOut)
6190
0
{
6191
0
    if (!underline && !overline && !strikeOut)
6192
0
        return;
6193
6194
0
    QTextItem::RenderFlags flags;
6195
0
    if (underline)
6196
0
        flags |= QTextItem::Underline;
6197
0
    if (overline)
6198
0
        flags |= QTextItem::Overline;
6199
0
    if (strikeOut)
6200
0
        flags |= QTextItem::StrikeOut;
6201
6202
0
    bool rtl = positions[glyphCount - 1].x < positions[0].x;
6203
0
    QFixed baseline = positions[0].y;
6204
0
    glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[rtl ? 0 : glyphCount - 1]);
6205
6206
0
    qreal width = rtl
6207
0
            ? (positions[0].x + gm.xoff - positions[glyphCount - 1].x).toReal()
6208
0
            : (positions[glyphCount - 1].x + gm.xoff - positions[0].x).toReal();
6209
6210
0
    drawTextItemDecoration(painter,
6211
0
                           QPointF(decorationPosition.x(), baseline.toReal()),
6212
0
                           fontEngine,
6213
0
                           nullptr, // textEngine
6214
0
                           underline ? QTextCharFormat::SingleUnderline
6215
0
                                     : QTextCharFormat::NoUnderline,
6216
0
                           flags,
6217
0
                           width,
6218
0
                           QTextCharFormat());
6219
0
}
6220
6221
void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti)
6222
0
{
6223
0
    Q_D(QPainter);
6224
6225
0
    d->drawTextItem(p, ti, static_cast<QTextEngine *>(nullptr));
6226
0
}
6227
6228
void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine)
6229
0
{
6230
#ifdef QT_DEBUG_DRAW
6231
    if constexpr (qt_show_painter_debug_output)
6232
        printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6233
               p.x(), p.y(), qPrintable(_ti.text()));
6234
#endif
6235
6236
0
    Q_Q(QPainter);
6237
6238
0
    if (!engine)
6239
0
        return;
6240
6241
0
    QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
6242
6243
0
    if (!extended && state->bgMode == Qt::OpaqueMode) {
6244
0
        QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6245
0
        q->fillRect(rect, state->bgBrush);
6246
0
    }
6247
6248
0
    if (q->pen().style() == Qt::NoPen)
6249
0
        return;
6250
6251
0
    const QPainter::RenderHints oldRenderHints = state->renderHints;
6252
0
    if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6253
        // draw antialias decoration (underline/overline/strikeout) with
6254
        // transformed text
6255
6256
0
        bool aa = true;
6257
0
        const QTransform &m = state->matrix;
6258
0
        if (state->matrix.type() < QTransform::TxShear) {
6259
0
            bool isPlain90DegreeRotation =
6260
0
                (qFuzzyIsNull(m.m11())
6261
0
                 && qFuzzyIsNull(m.m12() - qreal(1))
6262
0
                 && qFuzzyIsNull(m.m21() + qreal(1))
6263
0
                 && qFuzzyIsNull(m.m22())
6264
0
                    )
6265
0
                ||
6266
0
                (qFuzzyIsNull(m.m11() + qreal(1))
6267
0
                 && qFuzzyIsNull(m.m12())
6268
0
                 && qFuzzyIsNull(m.m21())
6269
0
                 && qFuzzyIsNull(m.m22() + qreal(1))
6270
0
                    )
6271
0
                ||
6272
0
                (qFuzzyIsNull(m.m11())
6273
0
                 && qFuzzyIsNull(m.m12() + qreal(1))
6274
0
                 && qFuzzyIsNull(m.m21() - qreal(1))
6275
0
                 && qFuzzyIsNull(m.m22())
6276
0
                    )
6277
0
                ;
6278
0
            aa = !isPlain90DegreeRotation;
6279
0
        }
6280
0
        if (aa)
6281
0
            q->setRenderHint(QPainter::Antialiasing, true);
6282
0
    }
6283
6284
0
    if (!extended)
6285
0
        updateState(state);
6286
6287
0
    if (!ti.glyphs.numGlyphs) {
6288
0
        drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6289
0
            ti.flags, ti.width.toReal(), ti.charFormat);
6290
0
    } else if (ti.fontEngine->type() == QFontEngine::Multi) {
6291
0
        QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
6292
6293
0
        const QGlyphLayout &glyphs = ti.glyphs;
6294
0
        int which = glyphs.glyphs[0] >> 24;
6295
6296
0
        qreal x = p.x();
6297
0
        qreal y = p.y();
6298
6299
0
        bool rtl = ti.flags & QTextItem::RightToLeft;
6300
0
        if (rtl)
6301
0
            x += ti.width.toReal();
6302
6303
0
        int start = 0;
6304
0
        int end, i;
6305
0
        for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6306
0
            const int e = glyphs.glyphs[end] >> 24;
6307
0
            if (e == which)
6308
0
                continue;
6309
6310
6311
0
            multi->ensureEngineAt(which);
6312
0
            QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6313
0
            ti2.width = 0;
6314
            // set the high byte to zero and calc the width
6315
0
            for (i = start; i < end; ++i) {
6316
0
                glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6317
0
                ti2.width += ti.glyphs.effectiveAdvance(i);
6318
0
            }
6319
6320
0
            if (rtl)
6321
0
                x -= ti2.width.toReal();
6322
6323
0
            if (extended)
6324
0
                extended->drawTextItem(QPointF(x, y), ti2);
6325
0
            else
6326
0
                engine->drawTextItem(QPointF(x, y), ti2);
6327
0
            drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6328
0
                                   ti2.flags, ti2.width.toReal(), ti2.charFormat);
6329
6330
0
            if (!rtl)
6331
0
                x += ti2.width.toReal();
6332
6333
            // reset the high byte for all glyphs and advance to the next sub-string
6334
0
            const int hi = which << 24;
6335
0
            for (i = start; i < end; ++i) {
6336
0
                glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6337
0
            }
6338
6339
            // change engine
6340
0
            start = end;
6341
0
            which = e;
6342
0
        }
6343
6344
0
        multi->ensureEngineAt(which);
6345
0
        QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6346
0
        ti2.width = 0;
6347
        // set the high byte to zero and calc the width
6348
0
        for (i = start; i < end; ++i) {
6349
0
            glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6350
0
            ti2.width += ti.glyphs.effectiveAdvance(i);
6351
0
        }
6352
6353
0
        if (rtl)
6354
0
            x -= ti2.width.toReal();
6355
6356
0
        if (extended)
6357
0
            extended->drawTextItem(QPointF(x, y), ti2);
6358
0
        else
6359
0
            engine->drawTextItem(QPointF(x,y), ti2);
6360
0
        drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6361
0
                               ti2.flags, ti2.width.toReal(), ti2.charFormat);
6362
6363
        // reset the high byte for all glyphs
6364
0
        const int hi = which << 24;
6365
0
        for (i = start; i < end; ++i)
6366
0
            glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6367
6368
0
    } else {
6369
0
        if (extended)
6370
0
            extended->drawTextItem(p, ti);
6371
0
        else
6372
0
            engine->drawTextItem(p, ti);
6373
0
        drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6374
0
                               ti.flags, ti.width.toReal(), ti.charFormat);
6375
0
    }
6376
6377
0
    if (state->renderHints != oldRenderHints) {
6378
0
        state->renderHints = oldRenderHints;
6379
0
        if (extended)
6380
0
            extended->renderHintsChanged();
6381
0
        else
6382
0
            state->dirtyFlags |= QPaintEngine::DirtyHints;
6383
0
    }
6384
0
}
6385
6386
/*!
6387
    \fn QRectF QPainter::boundingRect(const QRectF &rectangle, int flags, const QString &text)
6388
6389
    Returns the bounding rectangle of the \a text as it will appear
6390
    when drawn inside the given \a rectangle with the specified \a
6391
    flags using the currently set font(); i.e the function tells you
6392
    where the drawText() function will draw when given the same
6393
    arguments.
6394
6395
    If the \a text does not fit within the given \a rectangle using
6396
    the specified \a flags, the function returns the required
6397
    rectangle.
6398
6399
    The \a flags argument is a bitwise OR of the following flags:
6400
    \list
6401
         \li Qt::AlignLeft
6402
         \li Qt::AlignRight
6403
         \li Qt::AlignHCenter
6404
         \li Qt::AlignTop
6405
         \li Qt::AlignBottom
6406
         \li Qt::AlignVCenter
6407
         \li Qt::AlignCenter
6408
         \li Qt::TextSingleLine
6409
         \li Qt::TextExpandTabs
6410
         \li Qt::TextShowMnemonic
6411
         \li Qt::TextWordWrap
6412
         \li Qt::TextIncludeTrailingSpaces
6413
    \endlist
6414
    If several of the horizontal or several of the vertical alignment
6415
    flags are set, the resulting alignment is undefined.
6416
6417
    \sa drawText(), Qt::Alignment, Qt::TextFlag
6418
*/
6419
6420
/*!
6421
    \fn QRect QPainter::boundingRect(const QRect &rectangle, int flags,
6422
                                     const QString &text)
6423
6424
    \overload
6425
6426
    Returns the bounding rectangle of the \a text as it will appear
6427
    when drawn inside the given \a rectangle with the specified \a
6428
    flags using the currently set font().
6429
*/
6430
6431
/*!
6432
    \fn QRect QPainter::boundingRect(int x, int y, int w, int h, int flags,
6433
                                     const QString &text);
6434
6435
    \overload
6436
6437
    Returns the bounding rectangle of the given \a text as it will
6438
    appear when drawn inside the rectangle beginning at the point
6439
    (\a{x}, \a{y}) with width \a w and height \a h.
6440
*/
6441
QRect QPainter::boundingRect(const QRect &rect, int flags, const QString &str)
6442
0
{
6443
0
    if (str.isEmpty())
6444
0
        return QRect(rect.x(),rect.y(), 0,0);
6445
0
    QRect brect;
6446
0
    drawText(rect, flags | Qt::TextDontPrint, str, &brect);
6447
0
    return brect;
6448
0
}
6449
6450
6451
6452
QRectF QPainter::boundingRect(const QRectF &rect, int flags, const QString &str)
6453
0
{
6454
0
    if (str.isEmpty())
6455
0
        return QRectF(rect.x(),rect.y(), 0,0);
6456
0
    QRectF brect;
6457
0
    drawText(rect, flags | Qt::TextDontPrint, str, &brect);
6458
0
    return brect;
6459
0
}
6460
6461
/*!
6462
    \fn QRectF QPainter::boundingRect(const QRectF &rectangle,
6463
        const QString &text, const QTextOption &option)
6464
6465
    \overload
6466
6467
    Instead of specifying flags as a bitwise OR of the
6468
    Qt::AlignmentFlag and Qt::TextFlag, this overloaded function takes
6469
    an \a option argument. The QTextOption class provides a
6470
    description of general rich text properties.
6471
6472
    \sa QTextOption
6473
*/
6474
QRectF QPainter::boundingRect(const QRectF &r, const QString &text, const QTextOption &o)
6475
0
{
6476
0
    Q_D(QPainter);
6477
6478
0
    if (!d->engine || text.size() == 0)
6479
0
        return QRectF(r.x(),r.y(), 0,0);
6480
6481
0
    QRectF br;
6482
0
    qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, nullptr, 0, this);
6483
0
    return br;
6484
0
}
6485
6486
/*!
6487
    \fn void QPainter::drawTiledPixmap(const QRectF &rectangle, const QPixmap &pixmap, const QPointF &position)
6488
6489
    Draws a tiled \a pixmap, inside the given \a rectangle with its
6490
    origin at the given \a position.
6491
6492
    Calling drawTiledPixmap() is similar to calling drawPixmap()
6493
    several times to fill (tile) an area with a pixmap, but is
6494
    potentially much more efficient depending on the underlying window
6495
    system.
6496
6497
    drawTiledPixmap() will produce the same visual tiling pattern on
6498
    high-dpi displays (with devicePixelRatio > 1), compared to normal-
6499
    dpi displays. Set the devicePixelRatio on the \a pixmap to control
6500
    the tile size. For example, setting it to 2 halves the tile width
6501
    and height (on both 1x and 2x displays), and produces high-resolution
6502
    output on 2x displays.
6503
6504
    The \a position offset is provided in the device independent pixels
6505
    relative to the top-left corner of the \a rectangle. The \a position
6506
    can be used to align the repeating pattern inside the \a rectangle.
6507
6508
    \sa drawPixmap()
6509
*/
6510
void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sp)
6511
0
{
6512
#ifdef QT_DEBUG_DRAW
6513
    if constexpr (qt_show_painter_debug_output)
6514
        printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6515
               r.x(), r.y(), r.width(), r.height(),
6516
               pixmap.width(), pixmap.height(),
6517
               sp.x(), sp.y());
6518
#endif
6519
6520
0
    Q_D(QPainter);
6521
0
    if (!d->engine || pixmap.isNull() || r.isEmpty())
6522
0
        return;
6523
6524
0
#ifndef QT_NO_DEBUG
6525
0
    qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawTiledPixmap()");
6526
0
#endif
6527
6528
0
    const qreal sw = pixmap.width() / pixmap.devicePixelRatio();
6529
0
    const qreal sh = pixmap.height() / pixmap.devicePixelRatio();
6530
0
    qreal sx = sp.x();
6531
0
    qreal sy = sp.y();
6532
0
    if (sx < 0)
6533
0
        sx = qRound(sw) - qRound(-sx) % qRound(sw);
6534
0
    else
6535
0
        sx = qRound(sx) % qRound(sw);
6536
0
    if (sy < 0)
6537
0
        sy = qRound(sh) - -qRound(sy) % qRound(sh);
6538
0
    else
6539
0
        sy = qRound(sy) % qRound(sh);
6540
6541
6542
0
    if (d->extended) {
6543
0
        d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6544
0
        return;
6545
0
    }
6546
6547
0
    if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6548
0
        fillRect(r, d->state->bgBrush);
6549
6550
0
    d->updateState(d->state);
6551
0
    if ((d->state->matrix.type() > QTransform::TxTranslate
6552
0
        && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6553
0
        || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6554
0
    {
6555
0
        save();
6556
0
        setBackgroundMode(Qt::TransparentMode);
6557
0
        setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
6558
0
        setBrush(QBrush(d->state->pen.color(), pixmap));
6559
0
        setPen(Qt::NoPen);
6560
6561
        // If there is no rotation involved we have to make sure we use the
6562
        // antialiased and not the aliased coordinate system by rounding the coordinates.
6563
0
        if (d->state->matrix.type() <= QTransform::TxScale) {
6564
0
            const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6565
6566
0
            if (d->state->matrix.type() <= QTransform::TxTranslate) {
6567
0
                sx = qRound(sx);
6568
0
                sy = qRound(sy);
6569
0
            }
6570
6571
0
            setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6572
0
            drawRect(QRectF(p, r.size()));
6573
0
        } else {
6574
0
            setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6575
0
            drawRect(r);
6576
0
        }
6577
0
        restore();
6578
0
        return;
6579
0
    }
6580
6581
0
    qreal x = r.x();
6582
0
    qreal y = r.y();
6583
0
    if (d->state->matrix.type() == QTransform::TxTranslate
6584
0
        && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6585
0
        x += d->state->matrix.dx();
6586
0
        y += d->state->matrix.dy();
6587
0
    }
6588
6589
0
    d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
6590
0
}
6591
6592
/*!
6593
    \fn void QPainter::drawTiledPixmap(const QRect &rectangle, const QPixmap &pixmap,
6594
                                  const QPoint &position = QPoint())
6595
    \overload
6596
6597
    Draws a tiled \a pixmap, inside the given \a rectangle with its
6598
    origin at the given \a position.
6599
*/
6600
6601
/*!
6602
    \fn void QPainter::drawTiledPixmap(int x, int y, int width, int height, const
6603
         QPixmap &pixmap, int sx, int sy);
6604
    \overload
6605
6606
    Draws a tiled \a pixmap in the specified rectangle.
6607
6608
    (\a{x}, \a{y}) specifies the top-left point in the paint device
6609
    that is to be drawn onto; with the given \a width and \a
6610
    height.
6611
6612
    (\a{sx}, \a{sy}) specifies the origin inside the specified rectangle
6613
    where the pixmap will be drawn. The origin position is specified in
6614
    the device independent pixels relative to (\a{x}, \a{y}). This defaults
6615
    to (0, 0).
6616
*/
6617
6618
#ifndef QT_NO_PICTURE
6619
6620
/*!
6621
    \fn void QPainter::drawPicture(const QPointF &point, const QPicture &picture)
6622
6623
    Replays the given \a picture at the given \a point.
6624
6625
    The QPicture class is a paint device that records and replays
6626
    QPainter commands. A picture serializes the painter commands to an
6627
    IO device in a platform-independent format. Everything that can be
6628
    painted on a widget or pixmap can also be stored in a picture.
6629
6630
    This function does exactly the same as QPicture::play() when
6631
    called with \a point = QPointF(0, 0).
6632
6633
    \note The state of the painter is preserved by this function.
6634
6635
    \table 100%
6636
    \row
6637
    \li
6638
    \snippet code/src_gui_painting_qpainter.cpp 18
6639
    \endtable
6640
6641
    \sa QPicture::play()
6642
*/
6643
6644
void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
6645
0
{
6646
0
    Q_D(QPainter);
6647
6648
0
    if (!d->engine) {
6649
0
        qWarning("QPainter::drawPicture: Painter not active");
6650
0
        return;
6651
0
    }
6652
6653
0
    if (!d->extended)
6654
0
        d->updateState(d->state);
6655
6656
0
    save();
6657
0
    translate(p);
6658
0
    const_cast<QPicture *>(&picture)->play(this);
6659
0
    restore();
6660
0
}
6661
6662
/*!
6663
    \fn void QPainter::drawPicture(const QPoint &point, const QPicture &picture)
6664
    \overload
6665
6666
    Replays the given \a picture at the given \a point.
6667
*/
6668
6669
/*!
6670
    \fn void QPainter::drawPicture(int x, int y, const QPicture &picture)
6671
    \overload
6672
6673
    Draws the given \a picture at point (\a x, \a y).
6674
*/
6675
6676
#endif // QT_NO_PICTURE
6677
6678
/*!
6679
    \fn void QPainter::eraseRect(const QRectF &rectangle)
6680
6681
    Erases the area inside the given \a rectangle. Equivalent to
6682
    calling
6683
    \snippet code/src_gui_painting_qpainter.cpp 19
6684
6685
    \sa fillRect()
6686
*/
6687
void QPainter::eraseRect(const QRectF &r)
6688
0
{
6689
0
    Q_D(QPainter);
6690
6691
0
    fillRect(r, d->state->bgBrush);
6692
0
}
6693
6694
static inline bool needsResolving(const QBrush &brush)
6695
0
{
6696
0
    Qt::BrushStyle s = brush.style();
6697
0
    return ((s == Qt::LinearGradientPattern || s == Qt::RadialGradientPattern ||
6698
0
             s == Qt::ConicalGradientPattern) &&
6699
0
            (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ||
6700
0
             brush.gradient()->coordinateMode() == QGradient::ObjectMode));
6701
0
}
6702
6703
/*!
6704
    \fn void QPainter::eraseRect(const QRect &rectangle)
6705
    \overload
6706
6707
    Erases the area inside the given  \a rectangle.
6708
*/
6709
6710
/*!
6711
    \fn void QPainter::eraseRect(int x, int y, int width, int height)
6712
    \overload
6713
6714
    Erases the area inside the rectangle beginning at (\a x, \a y)
6715
    with the given \a width and \a height.
6716
*/
6717
6718
6719
/*!
6720
    \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::BrushStyle style)
6721
    \overload
6722
6723
    Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6724
    width and \a height, using the brush \a style specified.
6725
6726
    \since 4.5
6727
*/
6728
6729
/*!
6730
    \fn void QPainter::fillRect(const QRect &rectangle, Qt::BrushStyle style)
6731
    \overload
6732
6733
    Fills the given \a rectangle  with the brush \a style specified.
6734
6735
    \since 4.5
6736
*/
6737
6738
/*!
6739
    \fn void QPainter::fillRect(const QRectF &rectangle, Qt::BrushStyle style)
6740
    \overload
6741
6742
    Fills the given \a rectangle  with the brush \a style specified.
6743
6744
    \since 4.5
6745
*/
6746
6747
/*!
6748
    \fn void QPainter::fillRect(const QRectF &rectangle, const QBrush &brush)
6749
6750
    Fills the given \a rectangle  with the \a brush specified.
6751
6752
    Alternatively, you can specify a QColor instead of a QBrush; the
6753
    QBrush constructor (taking a QColor argument) will automatically
6754
    create a solid pattern brush.
6755
6756
    \sa drawRect()
6757
*/
6758
void QPainter::fillRect(const QRectF &r, const QBrush &brush)
6759
0
{
6760
0
    Q_D(QPainter);
6761
6762
0
    if (!d->engine) {
6763
0
        qWarning("QPainter::fillRect: Painter not active");
6764
0
        return;
6765
0
    }
6766
6767
0
    if (d->extended && !needsEmulation(brush)) {
6768
0
        d->extended->fillRect(r, brush);
6769
0
        return;
6770
0
    }
6771
6772
0
    QPen oldPen = pen();
6773
0
    QBrush oldBrush = this->brush();
6774
0
    setPen(Qt::NoPen);
6775
0
    if (brush.style() == Qt::SolidPattern) {
6776
0
        d->colorBrush.setStyle(Qt::SolidPattern);
6777
0
        d->colorBrush.setColor(brush.color());
6778
0
        setBrush(d->colorBrush);
6779
0
    } else {
6780
0
        setBrush(brush);
6781
0
    }
6782
6783
0
    drawRect(r);
6784
0
    setBrush(oldBrush);
6785
0
    setPen(oldPen);
6786
0
}
6787
6788
/*!
6789
    \fn void QPainter::fillRect(const QRect &rectangle, const QBrush &brush)
6790
    \overload
6791
6792
    Fills the given \a rectangle with the specified \a brush.
6793
*/
6794
6795
void QPainter::fillRect(const QRect &r, const QBrush &brush)
6796
0
{
6797
0
    Q_D(QPainter);
6798
6799
0
    if (!d->engine) {
6800
0
        qWarning("QPainter::fillRect: Painter not active");
6801
0
        return;
6802
0
    }
6803
6804
0
    if (d->extended && !needsEmulation(brush)) {
6805
0
        d->extended->fillRect(r, brush);
6806
0
        return;
6807
0
    }
6808
6809
0
    QPen oldPen = pen();
6810
0
    QBrush oldBrush = this->brush();
6811
0
    setPen(Qt::NoPen);
6812
0
    if (brush.style() == Qt::SolidPattern) {
6813
0
        d->colorBrush.setStyle(Qt::SolidPattern);
6814
0
        d->colorBrush.setColor(brush.color());
6815
0
        setBrush(d->colorBrush);
6816
0
    } else {
6817
0
        setBrush(brush);
6818
0
    }
6819
6820
0
    drawRect(r);
6821
0
    setBrush(oldBrush);
6822
0
    setPen(oldPen);
6823
0
}
6824
6825
6826
6827
/*!
6828
    \fn void QPainter::fillRect(const QRect &rectangle, const QColor &color)
6829
    \overload
6830
6831
    Fills the given \a rectangle with the \a color specified.
6832
6833
    \since 4.5
6834
*/
6835
void QPainter::fillRect(const QRect &r, const QColor &color)
6836
0
{
6837
0
    Q_D(QPainter);
6838
6839
0
    if (!d->engine) {
6840
0
        qWarning("QPainter::fillRect: Painter not active");
6841
0
        return;
6842
0
    }
6843
6844
0
    if (d->extended) {
6845
0
        d->extended->fillRect(r, color);
6846
0
        return;
6847
0
    }
6848
6849
0
    fillRect(r, QBrush(color));
6850
0
}
6851
6852
6853
/*!
6854
    \fn void QPainter::fillRect(const QRectF &rectangle, const QColor &color)
6855
    \overload
6856
6857
    Fills the given \a rectangle with the \a color specified.
6858
6859
    \since 4.5
6860
*/
6861
void QPainter::fillRect(const QRectF &r, const QColor &color)
6862
0
{
6863
0
    Q_D(QPainter);
6864
6865
0
    if (!d->engine)
6866
0
        return;
6867
6868
0
    if (d->extended) {
6869
0
        d->extended->fillRect(r, color);
6870
0
        return;
6871
0
    }
6872
6873
0
    fillRect(r, QBrush(color));
6874
0
}
6875
6876
/*!
6877
    \fn void QPainter::fillRect(int x, int y, int width, int height, const QBrush &brush)
6878
6879
    \overload
6880
6881
    Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6882
    width and \a height, using the given \a brush.
6883
*/
6884
6885
/*!
6886
    \fn void QPainter::fillRect(int x, int y, int width, int height, const QColor &color)
6887
6888
    \overload
6889
6890
    Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6891
    width and \a height, using the given \a color.
6892
6893
    \since 4.5
6894
*/
6895
6896
/*!
6897
    \fn void QPainter::fillRect(int x, int y, int width, int height, Qt::GlobalColor color)
6898
6899
    \overload
6900
6901
    Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6902
    width and \a height, using the given \a color.
6903
6904
    \since 4.5
6905
*/
6906
6907
/*!
6908
    \fn void QPainter::fillRect(const QRect &rectangle, Qt::GlobalColor color);
6909
6910
    \overload
6911
6912
    Fills the given \a rectangle with the specified \a color.
6913
6914
    \since 4.5
6915
*/
6916
6917
/*!
6918
    \fn void QPainter::fillRect(const QRectF &rectangle, Qt::GlobalColor color);
6919
6920
    \overload
6921
6922
    Fills the given \a rectangle with the specified \a color.
6923
6924
    \since 4.5
6925
*/
6926
6927
/*!
6928
    \fn void QPainter::fillRect(int x, int y, int width, int height, QGradient::Preset preset)
6929
6930
    \overload
6931
6932
    Fills the rectangle beginning at (\a{x}, \a{y}) with the given \a
6933
    width and \a height, using the given gradient \a preset.
6934
6935
    \since 5.12
6936
*/
6937
6938
/*!
6939
    \fn void QPainter::fillRect(const QRect &rectangle, QGradient::Preset preset);
6940
6941
    \overload
6942
6943
    Fills the given \a rectangle with the specified gradient \a preset.
6944
6945
    \since 5.12
6946
*/
6947
6948
/*!
6949
    \fn void QPainter::fillRect(const QRectF &rectangle, QGradient::Preset preset);
6950
6951
    \overload
6952
6953
    Fills the given \a rectangle with the specified gradient \a preset.
6954
6955
    \since 5.12
6956
*/
6957
6958
/*!
6959
    Sets the given render \a hint on the painter if \a on is true;
6960
    otherwise clears the render hint.
6961
6962
    \sa setRenderHints(), renderHints(), {QPainter#Rendering
6963
    Quality}{Rendering Quality}
6964
*/
6965
void QPainter::setRenderHint(RenderHint hint, bool on)
6966
0
{
6967
#ifdef QT_DEBUG_DRAW
6968
    if constexpr (qt_show_painter_debug_output)
6969
        printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
6970
#endif
6971
6972
0
#ifndef QT_NO_DEBUG
6973
0
    static const bool antialiasingDisabled = qEnvironmentVariableIntValue("QT_NO_ANTIALIASING");
6974
0
    if (hint == QPainter::Antialiasing && antialiasingDisabled)
6975
0
        return;
6976
0
#endif
6977
6978
0
    setRenderHints(hint, on);
6979
0
}
6980
6981
/*!
6982
    \since 4.2
6983
6984
    Sets the given render \a hints on the painter if \a on is true;
6985
    otherwise clears the render hints.
6986
6987
    \sa setRenderHint(), renderHints(), {QPainter#Rendering
6988
    Quality}{Rendering Quality}
6989
*/
6990
6991
void QPainter::setRenderHints(RenderHints hints, bool on)
6992
0
{
6993
0
    Q_D(QPainter);
6994
6995
0
    if (!d->engine) {
6996
0
        qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
6997
0
        return;
6998
0
    }
6999
7000
0
    if (on)
7001
0
        d->state->renderHints |= hints;
7002
0
    else
7003
0
        d->state->renderHints &= ~hints;
7004
7005
0
    if (d->extended)
7006
0
        d->extended->renderHintsChanged();
7007
0
    else
7008
0
        d->state->dirtyFlags |= QPaintEngine::DirtyHints;
7009
0
}
7010
7011
/*!
7012
    Returns a flag that specifies the rendering hints that are set for
7013
    this painter.
7014
7015
    \sa testRenderHint(), {QPainter#Rendering Quality}{Rendering Quality}
7016
*/
7017
QPainter::RenderHints QPainter::renderHints() const
7018
0
{
7019
0
    Q_D(const QPainter);
7020
7021
0
    if (!d->engine)
7022
0
        return { };
7023
7024
0
    return d->state->renderHints;
7025
0
}
7026
7027
/*!
7028
    \fn bool QPainter::testRenderHint(RenderHint hint) const
7029
    \since 4.3
7030
7031
    Returns \c true if \a hint is set; otherwise returns \c false.
7032
7033
    \sa renderHints(), setRenderHint()
7034
*/
7035
7036
/*!
7037
    Returns \c true if view transformation is enabled; otherwise returns
7038
    false.
7039
7040
    \sa setViewTransformEnabled(), worldTransform()
7041
*/
7042
7043
bool QPainter::viewTransformEnabled() const
7044
0
{
7045
0
    Q_D(const QPainter);
7046
0
    if (!d->engine) {
7047
0
        qWarning("QPainter::viewTransformEnabled: Painter not active");
7048
0
        return false;
7049
0
    }
7050
0
    return d->state->VxF;
7051
0
}
7052
7053
/*!
7054
    \fn void QPainter::setWindow(const QRect &rectangle)
7055
7056
    Sets the painter's window to the given \a rectangle, and enables
7057
    view transformations.
7058
7059
    The window rectangle is part of the view transformation. The
7060
    window specifies the logical coordinate system. Its sister, the
7061
    viewport(), specifies the device coordinate system.
7062
7063
    The default window rectangle is the same as the device's
7064
    rectangle.
7065
7066
    \sa window(), viewTransformEnabled(), {Coordinate
7067
    System#Window-Viewport Conversion}{Window-Viewport Conversion}
7068
*/
7069
7070
/*!
7071
    \fn void QPainter::setWindow(int x, int y, int width, int height)
7072
    \overload
7073
7074
    Sets the painter's window to the rectangle beginning at (\a x, \a
7075
    y) and the given \a width and \a height.
7076
*/
7077
7078
void QPainter::setWindow(const QRect &r)
7079
0
{
7080
#ifdef QT_DEBUG_DRAW
7081
    if constexpr (qt_show_painter_debug_output)
7082
        printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
7083
#endif
7084
7085
0
    Q_D(QPainter);
7086
7087
0
    if (!d->engine) {
7088
0
        qWarning("QPainter::setWindow: Painter not active");
7089
0
        return;
7090
0
    }
7091
7092
0
    d->state->wx = r.x();
7093
0
    d->state->wy = r.y();
7094
0
    d->state->ww = r.width();
7095
0
    d->state->wh = r.height();
7096
7097
0
    d->state->VxF = true;
7098
0
    d->updateMatrix();
7099
0
}
7100
7101
/*!
7102
    Returns the window rectangle.
7103
7104
    \sa setWindow(), setViewTransformEnabled()
7105
*/
7106
7107
QRect QPainter::window() const
7108
0
{
7109
0
    Q_D(const QPainter);
7110
0
    if (!d->engine) {
7111
0
        qWarning("QPainter::window: Painter not active");
7112
0
        return QRect();
7113
0
    }
7114
0
    return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
7115
0
}
7116
7117
/*!
7118
    \fn void QPainter::setViewport(const QRect &rectangle)
7119
7120
    Sets the painter's viewport rectangle to the given \a rectangle,
7121
    and enables view transformations.
7122
7123
    The viewport rectangle is part of the view transformation. The
7124
    viewport specifies the device coordinate system. Its sister, the
7125
    window(), specifies the logical coordinate system.
7126
7127
    The default viewport rectangle is the same as the device's
7128
    rectangle.
7129
7130
    \sa viewport(), viewTransformEnabled(), {Coordinate
7131
    System#Window-Viewport Conversion}{Window-Viewport Conversion}
7132
*/
7133
7134
/*!
7135
    \fn void QPainter::setViewport(int x, int y, int width, int height)
7136
    \overload
7137
7138
    Sets the painter's viewport rectangle to be the rectangle
7139
    beginning at (\a x, \a y) with the given \a width and \a height.
7140
*/
7141
7142
void QPainter::setViewport(const QRect &r)
7143
0
{
7144
#ifdef QT_DEBUG_DRAW
7145
    if constexpr (qt_show_painter_debug_output)
7146
        printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
7147
#endif
7148
7149
0
    Q_D(QPainter);
7150
7151
0
    if (!d->engine) {
7152
0
        qWarning("QPainter::setViewport: Painter not active");
7153
0
        return;
7154
0
    }
7155
7156
0
    d->state->vx = r.x();
7157
0
    d->state->vy = r.y();
7158
0
    d->state->vw = r.width();
7159
0
    d->state->vh = r.height();
7160
7161
0
    d->state->VxF = true;
7162
0
    d->updateMatrix();
7163
0
}
7164
7165
/*!
7166
    Returns the viewport rectangle.
7167
7168
    \sa setViewport(), setViewTransformEnabled()
7169
*/
7170
7171
QRect QPainter::viewport() const
7172
0
{
7173
0
    Q_D(const QPainter);
7174
0
    if (!d->engine) {
7175
0
        qWarning("QPainter::viewport: Painter not active");
7176
0
        return QRect();
7177
0
    }
7178
0
    return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
7179
0
}
7180
7181
/*!
7182
    Enables view transformations if \a enable is true, or disables
7183
    view transformations if \a enable is false.
7184
7185
    \sa viewTransformEnabled(), {Coordinate System#Window-Viewport
7186
    Conversion}{Window-Viewport Conversion}
7187
*/
7188
7189
void QPainter::setViewTransformEnabled(bool enable)
7190
0
{
7191
#ifdef QT_DEBUG_DRAW
7192
    if constexpr (qt_show_painter_debug_output)
7193
        printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
7194
#endif
7195
7196
0
    Q_D(QPainter);
7197
7198
0
    if (!d->engine) {
7199
0
        qWarning("QPainter::setViewTransformEnabled: Painter not active");
7200
0
        return;
7201
0
    }
7202
7203
0
    if (enable == d->state->VxF)
7204
0
        return;
7205
7206
0
    d->state->VxF = enable;
7207
0
    d->updateMatrix();
7208
0
}
7209
7210
void qt_format_text(const QFont &fnt,
7211
                    const QRectF &_r,
7212
                    int tf,
7213
                    int alignment,
7214
                    const QTextOption *option,
7215
                    const QString& str,
7216
                    QRectF *brect,
7217
                    int tabstops,
7218
                    int *ta,
7219
                    int tabarraylen,
7220
                    QPainter *painter)
7221
0
{
7222
0
    Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=nullptr) ); // we either have an option or flags
7223
7224
0
    if (_r.isEmpty() && !(tf & Qt::TextDontClip)) {
7225
0
        if (!brect)
7226
0
            return;
7227
0
        else
7228
0
            tf |= Qt::TextDontPrint;
7229
0
    }
7230
7231
0
    if (option) {
7232
0
        alignment |= option->alignment();
7233
0
        if (option->wrapMode() != QTextOption::NoWrap)
7234
0
            tf |= Qt::TextWordWrap;
7235
7236
0
        if (option->flags() & QTextOption::IncludeTrailingSpaces)
7237
0
            tf |= Qt::TextIncludeTrailingSpaces;
7238
7239
0
        if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7240
0
            tf |= Qt::TextExpandTabs;
7241
0
    }
7242
7243
    // we need to copy r here to protect against the case (&r == brect).
7244
0
    QRectF r(_r);
7245
7246
0
    bool dontclip  = (tf & Qt::TextDontClip);
7247
0
    bool wordwrap  = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7248
0
    bool singleline = (tf & Qt::TextSingleLine);
7249
0
    bool showmnemonic = (tf & Qt::TextShowMnemonic);
7250
0
    bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7251
7252
0
    Qt::LayoutDirection layout_direction;
7253
0
    if (tf & Qt::TextForceLeftToRight)
7254
0
        layout_direction = Qt::LeftToRight;
7255
0
    else if (tf & Qt::TextForceRightToLeft)
7256
0
        layout_direction = Qt::RightToLeft;
7257
0
    else if (option)
7258
0
        layout_direction = option->textDirection();
7259
0
    else if (painter)
7260
0
        layout_direction = painter->layoutDirection();
7261
0
    else
7262
0
        layout_direction = Qt::LeftToRight;
7263
7264
0
    alignment = QGuiApplicationPrivate::visualAlignment(layout_direction, QFlag(alignment));
7265
7266
0
    bool isRightToLeft = layout_direction == Qt::RightToLeft;
7267
0
    bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7268
0
                        (((alignment & Qt::AlignLeft) && !isRightToLeft) ||
7269
0
                          ((alignment & Qt::AlignRight) && isRightToLeft)));
7270
7271
0
    if (!painter)
7272
0
        tf |= Qt::TextDontPrint;
7273
7274
0
    uint maxUnderlines = 0;
7275
7276
0
    QFontMetricsF fm(fnt);
7277
0
    QString text = str;
7278
0
    int offset = 0;
7279
0
start_lengthVariant:
7280
0
    bool hasMoreLengthVariants = false;
7281
    // compatible behaviour to the old implementation. Replace
7282
    // tabs by spaces
7283
0
    int old_offset = offset;
7284
0
    for (; offset < text.size(); offset++) {
7285
0
        QChar chr = text.at(offset);
7286
0
        if (chr == u'\r' || (singleline && chr == u'\n')) {
7287
0
            text[offset] = u' ';
7288
0
        } else if (chr == u'\n') {
7289
0
            text[offset] = QChar::LineSeparator;
7290
0
        } else if (chr == u'&') {
7291
0
            ++maxUnderlines;
7292
0
        } else if (chr == u'\t') {
7293
0
            if (!expandtabs) {
7294
0
                text[offset] = u' ';
7295
0
            } else if (!tabarraylen && !tabstops) {
7296
0
                tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7297
0
            }
7298
0
        } else if (chr == u'\x9c') {
7299
            // string with multiple length variants
7300
0
            hasMoreLengthVariants = true;
7301
0
            break;
7302
0
        }
7303
0
    }
7304
7305
0
    QList<QTextLayout::FormatRange> underlineFormats;
7306
0
    int length = offset - old_offset;
7307
0
    if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7308
0
        QChar *cout = text.data() + old_offset;
7309
0
        QChar *cout0 = cout;
7310
0
        QChar *cin = cout;
7311
0
        int l = length;
7312
0
        while (l) {
7313
0
            if (*cin == u'&') {
7314
0
                ++cin;
7315
0
                --length;
7316
0
                --l;
7317
0
                if (!l)
7318
0
                    break;
7319
0
                if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7320
0
                    QTextLayout::FormatRange range;
7321
0
                    range.start = cout - cout0;
7322
0
                    range.length = 1;
7323
0
                    range.format.setFontUnderline(true);
7324
0
                    underlineFormats.append(range);
7325
0
                }
7326
#ifdef Q_OS_APPLE
7327
            } else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7328
                       cin[1] == u'&' && cin[2] != u'&' &&
7329
                       cin[3] == u')') {
7330
                int n = 0;
7331
                while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7332
                    ++n;
7333
                cout -= n;
7334
                cin += 4;
7335
                length -= n + 4;
7336
                l -= 4;
7337
                continue;
7338
#endif //Q_OS_APPLE
7339
0
            }
7340
0
            *cout = *cin;
7341
0
            ++cout;
7342
0
            ++cin;
7343
0
            --l;
7344
0
        }
7345
0
    }
7346
7347
0
    qreal height = 0;
7348
0
    qreal width = 0;
7349
7350
0
    QString finalText = text.mid(old_offset, length);
7351
0
    Q_DECL_UNINITIALIZED QStackTextEngine engine(finalText, fnt);
7352
0
    if (option) {
7353
0
        engine.option = *option;
7354
0
    }
7355
7356
0
    if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7357
0
        engine.option.setTabStopDistance(tabstops);
7358
7359
0
    if (engine.option.tabs().isEmpty() && ta) {
7360
0
        QList<qreal> tabs;
7361
0
        tabs.reserve(tabarraylen);
7362
0
        for (int i = 0; i < tabarraylen; i++)
7363
0
            tabs.append(qreal(ta[i]));
7364
0
        engine.option.setTabArray(tabs);
7365
0
    }
7366
7367
0
    engine.option.setTextDirection(layout_direction);
7368
0
    if (alignment & Qt::AlignJustify)
7369
0
        engine.option.setAlignment(Qt::AlignJustify);
7370
0
    else
7371
0
        engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
7372
7373
0
    if (!option && (tf & Qt::TextWrapAnywhere))
7374
0
        engine.option.setWrapMode(QTextOption::WrapAnywhere);
7375
7376
0
    if (tf & Qt::TextJustificationForced)
7377
0
        engine.forceJustification = true;
7378
0
    QTextLayout textLayout(&engine);
7379
0
    textLayout.setCacheEnabled(true);
7380
0
    textLayout.setFormats(underlineFormats);
7381
7382
0
    if (finalText.isEmpty()) {
7383
0
        height = fm.height();
7384
0
        width = 0;
7385
0
        tf |= Qt::TextDontPrint;
7386
0
    } else {
7387
0
        qreal lineWidth = 0x01000000;
7388
0
        if (wordwrap || (tf & Qt::TextJustificationForced))
7389
0
            lineWidth = qMax<qreal>(0, r.width());
7390
0
        if (!wordwrap)
7391
0
            tf |= Qt::TextIncludeTrailingSpaces;
7392
0
        textLayout.beginLayout();
7393
7394
0
        qreal leading = fm.leading();
7395
0
        height = -leading;
7396
7397
0
        while (1) {
7398
0
            QTextLine l = textLayout.createLine();
7399
0
            if (!l.isValid())
7400
0
                break;
7401
7402
0
            l.setLineWidth(lineWidth);
7403
0
            height += leading;
7404
7405
            // Make sure lines are positioned on whole pixels
7406
0
            height = qCeil(height);
7407
7408
0
            if (alignment & Qt::AlignBaseline && l.lineNumber() == 0)
7409
0
                height -= l.ascent();
7410
7411
0
            l.setPosition(QPointF(0., height));
7412
0
            height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7413
0
            width = qMax(width, l.naturalTextWidth());
7414
0
            if (!dontclip && !brect && height >= r.height())
7415
0
                break;
7416
0
        }
7417
0
        textLayout.endLayout();
7418
0
    }
7419
7420
0
    qreal yoff = 0;
7421
0
    qreal xoff = 0;
7422
0
    if (alignment & Qt::AlignBottom)
7423
0
        yoff = r.height() - height;
7424
0
    else if (alignment & Qt::AlignVCenter)
7425
0
        yoff = (r.height() - height)/2;
7426
7427
0
    if (alignment & Qt::AlignRight)
7428
0
        xoff = r.width() - width;
7429
0
    else if (alignment & Qt::AlignHCenter)
7430
0
        xoff = (r.width() - width)/2;
7431
7432
0
    QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7433
7434
0
    if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7435
0
        offset++;
7436
0
        goto start_lengthVariant;
7437
0
    }
7438
0
    if (brect)
7439
0
        *brect = bounds;
7440
7441
0
    if (!(tf & Qt::TextDontPrint)) {
7442
0
        bool restore = false;
7443
0
        if (!dontclip && !r.contains(bounds)) {
7444
0
            restore = true;
7445
0
            painter->save();
7446
0
            painter->setClipRect(r, Qt::IntersectClip);
7447
0
        }
7448
7449
0
        for (int i = 0; i < textLayout.lineCount(); i++) {
7450
0
            QTextLine line = textLayout.lineAt(i);
7451
0
            QTextEngine *eng = textLayout.engine();
7452
0
            eng->enableDelayDecorations();
7453
7454
0
            qreal advance = line.horizontalAdvance();
7455
0
            xoff = 0;
7456
0
            if (alignment & Qt::AlignRight) {
7457
0
                xoff = r.width() - advance -
7458
0
                    eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7459
0
            } else if (alignment & Qt::AlignHCenter) {
7460
0
                xoff = (r.width() - advance) / 2;
7461
0
            }
7462
7463
0
            line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff));
7464
0
            eng->drawDecorations(painter);
7465
0
        }
7466
7467
0
        if (restore) {
7468
0
            painter->restore();
7469
0
        }
7470
0
    }
7471
0
}
7472
7473
void qt_format_text(const QFont &fnt, const QRectF &_r,
7474
                    int tf, const QString& str, QRectF *brect,
7475
                    int tabstops, int *ta, int tabarraylen,
7476
                    QPainter *painter)
7477
0
{
7478
0
    qt_format_text(fnt,
7479
0
                   _r,
7480
0
                   tf,
7481
0
                   tf & ~Qt::AlignBaseline, // Qt::AlignBaseline conflicts with Qt::TextSingleLine
7482
0
                   nullptr,
7483
0
                   str,
7484
0
                   brect,
7485
0
                   tabstops,
7486
0
                   ta,
7487
0
                   tabarraylen,
7488
0
                   painter);
7489
0
}
7490
7491
void qt_format_text(const QFont &fnt,
7492
                    const QRectF &_r,
7493
                    int tf,
7494
                    const QTextOption *option,
7495
                    const QString& str,
7496
                    QRectF *brect,
7497
                    int tabstops,
7498
                    int *ta,
7499
                    int tabarraylen,
7500
                    QPainter *painter)
7501
0
{
7502
0
    qt_format_text(fnt,
7503
0
                   _r,
7504
0
                   tf,
7505
0
                   tf & ~Qt::AlignBaseline, // Qt::AlignBaseline conflicts with Qt::TextSingleLine
7506
0
                   option,
7507
0
                   str,
7508
0
                   brect,
7509
0
                   tabstops,
7510
0
                   ta,
7511
0
                   tabarraylen,
7512
0
                   painter);
7513
0
}
7514
7515
/*!
7516
    Sets the layout direction used by the painter when drawing text,
7517
    to the specified \a direction.
7518
7519
    The default is Qt::LayoutDirectionAuto, which will implicitly determine the
7520
    direction from the text drawn.
7521
7522
    \sa QTextOption::setTextDirection(), layoutDirection(), drawText(), {QPainter#Settings}{Settings}
7523
*/
7524
void QPainter::setLayoutDirection(Qt::LayoutDirection direction)
7525
0
{
7526
0
    Q_D(QPainter);
7527
0
    if (d->state)
7528
0
        d->state->layoutDirection = direction;
7529
0
}
7530
7531
/*!
7532
    Returns the layout direction used by the painter when drawing text.
7533
7534
    \sa QTextOption::textDirection(), setLayoutDirection(), drawText(), {QPainter#Settings}{Settings}
7535
*/
7536
Qt::LayoutDirection QPainter::layoutDirection() const
7537
0
{
7538
0
    Q_D(const QPainter);
7539
0
    return d->state ? d->state->layoutDirection : Qt::LayoutDirectionAuto;
7540
0
}
7541
7542
QPainterState::QPainterState(const QPainterState *s)
7543
0
    : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7544
0
      pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7545
0
      clipRegion(s->clipRegion), clipPath(s->clipPath),
7546
0
      clipOperation(s->clipOperation),
7547
0
      renderHints(s->renderHints), clipInfo(s->clipInfo),
7548
0
      worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7549
0
      wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7550
0
      vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7551
0
      opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7552
0
      clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7553
0
      layoutDirection(s->layoutDirection),
7554
0
      composition_mode(s->composition_mode),
7555
0
      emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7556
0
{
7557
0
    dirtyFlags = s->dirtyFlags;
7558
0
}
7559
7560
QPainterState::QPainterState()
7561
1.39M
    : brushOrigin(0, 0), WxF(false), VxF(false), clipEnabled(true),
7562
1.39M
      layoutDirection(QGuiApplication::layoutDirection())
7563
1.39M
{
7564
1.39M
}
7565
7566
QPainterState::~QPainterState()
7567
1.39M
{
7568
1.39M
}
7569
7570
0
void QPainterState::init(QPainter *p) {
7571
0
    bgBrush = Qt::white;
7572
0
    bgMode = Qt::TransparentMode;
7573
0
    WxF = false;
7574
0
    VxF = false;
7575
0
    clipEnabled = true;
7576
0
    wx = wy = ww = wh = 0;
7577
0
    vx = vy = vw = vh = 0;
7578
0
    painter = p;
7579
0
    pen = QPen();
7580
0
    brushOrigin = QPointF(0, 0);
7581
0
    brush = QBrush();
7582
0
    font = deviceFont = QFont();
7583
0
    clipRegion = QRegion();
7584
0
    clipPath = QPainterPath();
7585
0
    clipOperation = Qt::NoClip;
7586
0
    clipInfo.clear();
7587
0
    worldMatrix.reset();
7588
0
    matrix.reset();
7589
0
    layoutDirection = QGuiApplication::layoutDirection();
7590
0
    composition_mode = QPainter::CompositionMode_SourceOver;
7591
0
    emulationSpecifier = 0;
7592
0
    dirtyFlags = { };
7593
0
    changeFlags = 0;
7594
0
    renderHints = { };
7595
0
    opacity = 1;
7596
0
}
7597
7598
/*!
7599
    \fn void QPainter::drawImage(const QRectF &target, const QImage &image, const QRectF &source,
7600
                         Qt::ImageConversionFlags flags)
7601
7602
    Draws the rectangular portion \a source of the given \a image
7603
    into the \a target rectangle in the paint device.
7604
7605
    \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7606
    \note See \l{Drawing High Resolution Versions of Pixmaps and Images} on how this is affected
7607
    by QImage::devicePixelRatio().
7608
7609
    If the image needs to be modified to fit in a lower-resolution
7610
    result (e.g. converting from 32-bit to 8-bit), use the \a flags to
7611
    specify how you would prefer this to happen.
7612
7613
    \table 100%
7614
    \row
7615
    \li
7616
    \snippet code/src_gui_painting_qpainter.cpp 20
7617
    \endtable
7618
7619
    \sa drawPixmap(), QImage::devicePixelRatio()
7620
*/
7621
7622
/*!
7623
    \fn void QPainter::drawImage(const QRect &target, const QImage &image, const QRect &source,
7624
                                 Qt::ImageConversionFlags flags)
7625
    \overload
7626
7627
    Draws the rectangular portion \a source of the given \a image
7628
    into the \a target rectangle in the paint device.
7629
7630
    \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7631
*/
7632
7633
/*!
7634
    \fn void QPainter::drawImage(const QPointF &point, const QImage &image)
7635
7636
    \overload
7637
7638
    Draws the given \a image at the given \a point.
7639
*/
7640
7641
/*!
7642
    \fn void QPainter::drawImage(const QPoint &point, const QImage &image)
7643
7644
    \overload
7645
7646
    Draws the given \a image at the given \a point.
7647
*/
7648
7649
/*!
7650
    \fn void QPainter::drawImage(const QPointF &point, const QImage &image, const QRectF &source,
7651
                                 Qt::ImageConversionFlags flags = Qt::AutoColor)
7652
7653
    \overload
7654
7655
    Draws the rectangular portion \a source of the given \a image with
7656
    its origin at the given \a point.
7657
*/
7658
7659
/*!
7660
    \fn void QPainter::drawImage(const QPoint &point, const QImage &image, const QRect &source,
7661
                                 Qt::ImageConversionFlags flags = Qt::AutoColor)
7662
    \overload
7663
7664
    Draws the rectangular portion \a source of the given \a image with
7665
    its origin at the given \a point.
7666
*/
7667
7668
/*!
7669
    \fn void QPainter::drawImage(const QRectF &rectangle, const QImage &image)
7670
7671
    \overload
7672
7673
    Draws the given \a image into the given \a rectangle.
7674
7675
    \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7676
*/
7677
7678
/*!
7679
    \fn void QPainter::drawImage(const QRect &rectangle, const QImage &image)
7680
7681
    \overload
7682
7683
    Draws the given \a image into the given \a rectangle.
7684
7685
   \note The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
7686
*/
7687
7688
/*!
7689
    \fn void QPainter::drawImage(int x, int y, const QImage &image,
7690
                                 int sx, int sy, int sw, int sh,
7691
                                 Qt::ImageConversionFlags flags)
7692
    \overload
7693
7694
    Draws an image at (\a{x}, \a{y}) by copying a part of \a image into
7695
    the paint device.
7696
7697
    (\a{x}, \a{y}) specifies the top-left point in the paint device that is
7698
    to be drawn onto. (\a{sx}, \a{sy}) specifies the top-left point in \a
7699
    image that is to be drawn. The default is (0, 0).
7700
7701
    (\a{sw}, \a{sh}) specifies the size of the image that is to be drawn.
7702
    The default, (0, 0) (and negative) means all the way to the
7703
    bottom-right of the image.
7704
*/
7705
7706
/*!
7707
    \class QPaintEngineState
7708
    \since 4.1
7709
    \inmodule QtGui
7710
7711
    \brief The QPaintEngineState class provides information about the
7712
    active paint engine's current state.
7713
    \reentrant
7714
7715
    QPaintEngineState records which properties that have changed since
7716
    the last time the paint engine was updated, as well as their
7717
    current value.
7718
7719
    Which properties that have changed can at any time be retrieved
7720
    using the state() function. This function returns an instance of
7721
    the QPaintEngine::DirtyFlags type which stores an OR combination
7722
    of QPaintEngine::DirtyFlag values. The QPaintEngine::DirtyFlag
7723
    enum defines whether a property has changed since the last update
7724
    or not.
7725
7726
    If a property is marked with a dirty flag, its current value can
7727
    be retrieved using the corresponding get function:
7728
7729
    \target GetFunction
7730
7731
    \table
7732
    \header \li Property Flag \li Current Property Value
7733
    \row \li QPaintEngine::DirtyBackground \li backgroundBrush()
7734
    \row \li QPaintEngine::DirtyBackgroundMode \li backgroundMode()
7735
    \row \li QPaintEngine::DirtyBrush \li brush()
7736
    \row \li QPaintEngine::DirtyBrushOrigin \li brushOrigin()
7737
    \row \li QPaintEngine::DirtyClipRegion \e or QPaintEngine::DirtyClipPath
7738
         \li clipOperation()
7739
    \row \li QPaintEngine::DirtyClipPath \li clipPath()
7740
    \row \li QPaintEngine::DirtyClipRegion \li clipRegion()
7741
    \row \li QPaintEngine::DirtyCompositionMode \li compositionMode()
7742
    \row \li QPaintEngine::DirtyFont \li font()
7743
    \row \li QPaintEngine::DirtyTransform \li transform()
7744
    \row \li QPaintEngine::DirtyClipEnabled \li isClipEnabled()
7745
    \row \li QPaintEngine::DirtyPen \li pen()
7746
    \row \li QPaintEngine::DirtyHints \li renderHints()
7747
    \endtable
7748
7749
    The QPaintEngineState class also provide the painter() function
7750
    which returns a pointer to the painter that is currently updating
7751
    the paint engine.
7752
7753
    An instance of this class, representing the current state of the
7754
    active paint engine, is passed as argument to the
7755
    QPaintEngine::updateState() function. The only situation in which
7756
    you will have to use this class directly is when implementing your
7757
    own paint engine.
7758
7759
    \sa QPaintEngine
7760
*/
7761
7762
7763
/*!
7764
    \fn QPaintEngine::DirtyFlags QPaintEngineState::state() const
7765
7766
    Returns a combination of flags identifying the set of properties
7767
    that need to be updated when updating the paint engine's state
7768
    (i.e. during a call to the QPaintEngine::updateState() function).
7769
7770
    \sa QPaintEngine::updateState()
7771
*/
7772
7773
7774
/*!
7775
    Returns the pen in the current paint engine state.
7776
7777
    This variable should only be used when the state() returns a
7778
    combination which includes the QPaintEngine::DirtyPen flag.
7779
7780
    \sa state(), QPaintEngine::updateState()
7781
*/
7782
7783
QPen QPaintEngineState::pen() const
7784
0
{
7785
0
    return static_cast<const QPainterState *>(this)->pen;
7786
0
}
7787
7788
/*!
7789
    Returns the brush in the current paint engine state.
7790
7791
    This variable should only be used when the state() returns a
7792
    combination which includes the QPaintEngine::DirtyBrush flag.
7793
7794
    \sa state(), QPaintEngine::updateState()
7795
*/
7796
7797
QBrush QPaintEngineState::brush() const
7798
0
{
7799
0
    return static_cast<const QPainterState *>(this)->brush;
7800
0
}
7801
7802
/*!
7803
    Returns the brush origin in the current paint engine state.
7804
7805
    This variable should only be used when the state() returns a
7806
    combination which includes the QPaintEngine::DirtyBrushOrigin flag.
7807
7808
    \sa state(), QPaintEngine::updateState()
7809
*/
7810
7811
QPointF QPaintEngineState::brushOrigin() const
7812
0
{
7813
0
    return static_cast<const QPainterState *>(this)->brushOrigin;
7814
0
}
7815
7816
/*!
7817
    Returns the background brush in the current paint engine state.
7818
7819
    This variable should only be used when the state() returns a
7820
    combination which includes the QPaintEngine::DirtyBackground flag.
7821
7822
    \sa state(), QPaintEngine::updateState()
7823
*/
7824
7825
QBrush QPaintEngineState::backgroundBrush() const
7826
0
{
7827
0
    return static_cast<const QPainterState *>(this)->bgBrush;
7828
0
}
7829
7830
/*!
7831
    Returns the background mode in the current paint engine
7832
    state.
7833
7834
    This variable should only be used when the state() returns a
7835
    combination which includes the QPaintEngine::DirtyBackgroundMode flag.
7836
7837
    \sa state(), QPaintEngine::updateState()
7838
*/
7839
7840
Qt::BGMode QPaintEngineState::backgroundMode() const
7841
0
{
7842
0
    return static_cast<const QPainterState *>(this)->bgMode;
7843
0
}
7844
7845
/*!
7846
    Returns the font in the current paint engine
7847
    state.
7848
7849
    This variable should only be used when the state() returns a
7850
    combination which includes the QPaintEngine::DirtyFont flag.
7851
7852
    \sa state(), QPaintEngine::updateState()
7853
*/
7854
7855
QFont QPaintEngineState::font() const
7856
0
{
7857
0
    return static_cast<const QPainterState *>(this)->font;
7858
0
}
7859
7860
/*!
7861
    \since 4.3
7862
7863
    Returns the matrix in the current paint engine state.
7864
7865
    This variable should only be used when the state() returns a
7866
    combination which includes the QPaintEngine::DirtyTransform flag.
7867
7868
    \sa state(), QPaintEngine::updateState()
7869
*/
7870
7871
7872
QTransform QPaintEngineState::transform() const
7873
0
{
7874
0
    const QPainterState *st = static_cast<const QPainterState *>(this);
7875
7876
0
    return st->matrix;
7877
0
}
7878
7879
7880
/*!
7881
    Returns the clip operation in the current paint engine
7882
    state.
7883
7884
    This variable should only be used when the state() returns a
7885
    combination which includes either the QPaintEngine::DirtyClipPath
7886
    or the QPaintEngine::DirtyClipRegion flag.
7887
7888
    \sa state(), QPaintEngine::updateState()
7889
*/
7890
7891
Qt::ClipOperation QPaintEngineState::clipOperation() const
7892
0
{
7893
0
    return static_cast<const QPainterState *>(this)->clipOperation;
7894
0
}
7895
7896
/*!
7897
    \since 4.3
7898
7899
    Returns whether the coordinate of the fill have been specified
7900
    as bounded by the current rendering operation and have to be
7901
    resolved (about the currently rendered primitive).
7902
*/
7903
bool QPaintEngineState::brushNeedsResolving() const
7904
0
{
7905
0
    const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
7906
0
    return needsResolving(brush);
7907
0
}
7908
7909
7910
/*!
7911
    \since 4.3
7912
7913
    Returns whether the coordinate of the stroke have been specified
7914
    as bounded by the current rendering operation and have to be
7915
    resolved (about the currently rendered primitive).
7916
*/
7917
bool QPaintEngineState::penNeedsResolving() const
7918
0
{
7919
0
    const QPen &pen = static_cast<const QPainterState *>(this)->pen;
7920
0
    return needsResolving(pen.brush());
7921
0
}
7922
7923
/*!
7924
    Returns the clip region in the current paint engine state.
7925
7926
    This variable should only be used when the state() returns a
7927
    combination which includes the QPaintEngine::DirtyClipRegion flag.
7928
7929
    \sa state(), QPaintEngine::updateState()
7930
*/
7931
7932
QRegion QPaintEngineState::clipRegion() const
7933
0
{
7934
0
    return static_cast<const QPainterState *>(this)->clipRegion;
7935
0
}
7936
7937
/*!
7938
    Returns the clip path in the current paint engine state.
7939
7940
    This variable should only be used when the state() returns a
7941
    combination which includes the QPaintEngine::DirtyClipPath flag.
7942
7943
    \sa state(), QPaintEngine::updateState()
7944
*/
7945
7946
QPainterPath QPaintEngineState::clipPath() const
7947
0
{
7948
0
    return static_cast<const QPainterState *>(this)->clipPath;
7949
0
}
7950
7951
/*!
7952
    Returns whether clipping is enabled or not in the current paint
7953
    engine state.
7954
7955
    This variable should only be used when the state() returns a
7956
    combination which includes the QPaintEngine::DirtyClipEnabled
7957
    flag.
7958
7959
    \sa state(), QPaintEngine::updateState()
7960
*/
7961
7962
bool QPaintEngineState::isClipEnabled() const
7963
0
{
7964
0
    return static_cast<const QPainterState *>(this)->clipEnabled;
7965
0
}
7966
7967
/*!
7968
    Returns the render hints in the current paint engine state.
7969
7970
    This variable should only be used when the state() returns a
7971
    combination which includes the QPaintEngine::DirtyHints
7972
    flag.
7973
7974
    \sa state(), QPaintEngine::updateState()
7975
*/
7976
7977
QPainter::RenderHints QPaintEngineState::renderHints() const
7978
0
{
7979
0
    return static_cast<const QPainterState *>(this)->renderHints;
7980
0
}
7981
7982
/*!
7983
    Returns the composition mode in the current paint engine state.
7984
7985
    This variable should only be used when the state() returns a
7986
    combination which includes the QPaintEngine::DirtyCompositionMode
7987
    flag.
7988
7989
    \sa state(), QPaintEngine::updateState()
7990
*/
7991
7992
QPainter::CompositionMode QPaintEngineState::compositionMode() const
7993
0
{
7994
0
    return static_cast<const QPainterState *>(this)->composition_mode;
7995
0
}
7996
7997
7998
/*!
7999
    Returns a pointer to the painter currently updating the paint
8000
    engine.
8001
*/
8002
8003
QPainter *QPaintEngineState::painter() const
8004
0
{
8005
0
    return static_cast<const QPainterState *>(this)->painter;
8006
0
}
8007
8008
8009
/*!
8010
    \since 4.2
8011
8012
    Returns the opacity in the current paint engine state.
8013
*/
8014
8015
qreal QPaintEngineState::opacity() const
8016
0
{
8017
0
    return static_cast<const QPainterState *>(this)->opacity;
8018
0
}
8019
8020
/*!
8021
    \since 4.3
8022
8023
    Sets the world transformation matrix.
8024
    If \a combine is true, the specified \a transform is combined with
8025
    the current matrix; otherwise it replaces the current matrix.
8026
8027
    \sa transform(), setWorldTransform()
8028
*/
8029
8030
void QPainter::setTransform(const QTransform &transform, bool combine )
8031
0
{
8032
0
    setWorldTransform(transform, combine);
8033
0
}
8034
8035
/*!
8036
    Alias for worldTransform().
8037
    Returns the world transformation matrix.
8038
8039
    \sa worldTransform()
8040
*/
8041
8042
const QTransform & QPainter::transform() const
8043
0
{
8044
0
    return worldTransform();
8045
0
}
8046
8047
8048
/*!
8049
    Returns the matrix that transforms from logical coordinates to
8050
    device coordinates of the platform dependent paint device.
8051
8052
    This function is \e only needed when using platform painting
8053
    commands on the platform dependent handle (Qt::HANDLE), and the
8054
    platform does not do transformations nativly.
8055
8056
    The QPaintEngine::PaintEngineFeature enum can be queried to
8057
    determine whether the platform performs the transformations or
8058
    not.
8059
8060
    \sa worldTransform(), QPaintEngine::hasFeature(),
8061
*/
8062
8063
const QTransform & QPainter::deviceTransform() const
8064
0
{
8065
0
    Q_D(const QPainter);
8066
0
    if (!d->engine) {
8067
0
        qWarning("QPainter::deviceTransform: Painter not active");
8068
0
        return d->fakeState()->transform;
8069
0
    }
8070
0
    return d->state->matrix;
8071
0
}
8072
8073
8074
/*!
8075
    Resets any transformations that were made using translate(),
8076
    scale(), shear(), rotate(), setWorldTransform(), setViewport()
8077
    and setWindow().
8078
8079
    \sa {Coordinate Transformations}
8080
*/
8081
8082
void QPainter::resetTransform()
8083
0
{
8084
0
     Q_D(QPainter);
8085
#ifdef QT_DEBUG_DRAW
8086
    if constexpr (qt_show_painter_debug_output)
8087
        printf("QPainter::resetMatrix()\n");
8088
#endif
8089
0
    if (!d->engine) {
8090
0
        qWarning("QPainter::resetMatrix: Painter not active");
8091
0
        return;
8092
0
    }
8093
8094
0
    d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0;                        // default view origins
8095
0
    d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
8096
0
    d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
8097
0
    d->state->worldMatrix = QTransform();
8098
0
    setWorldMatrixEnabled(false);
8099
0
    setViewTransformEnabled(false);
8100
0
    if (d->extended)
8101
0
        d->extended->transformChanged();
8102
0
    else
8103
0
        d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
8104
0
}
8105
8106
/*!
8107
    Sets the world transformation matrix.
8108
    If \a combine is true, the specified \a matrix is combined with the current matrix;
8109
    otherwise it replaces the current matrix.
8110
8111
    \sa transform(), setTransform()
8112
*/
8113
8114
void QPainter::setWorldTransform(const QTransform &matrix, bool combine )
8115
0
{
8116
0
    Q_D(QPainter);
8117
8118
0
    if (!d->engine) {
8119
0
        qWarning("QPainter::setWorldTransform: Painter not active");
8120
0
        return;
8121
0
    }
8122
8123
0
    if (combine)
8124
0
        d->state->worldMatrix = matrix * d->state->worldMatrix;                        // combines
8125
0
    else
8126
0
        d->state->worldMatrix = matrix;                                // set new matrix
8127
8128
0
    d->state->WxF = true;
8129
0
    d->updateMatrix();
8130
0
}
8131
8132
/*!
8133
    Returns the world transformation matrix.
8134
*/
8135
8136
const QTransform & QPainter::worldTransform() const
8137
0
{
8138
0
    Q_D(const QPainter);
8139
0
    if (!d->engine) {
8140
0
        qWarning("QPainter::worldTransform: Painter not active");
8141
0
        return d->fakeState()->transform;
8142
0
    }
8143
0
    return d->state->worldMatrix;
8144
0
}
8145
8146
/*!
8147
    Returns the transformation matrix combining the current
8148
    window/viewport and world transformation.
8149
8150
    \sa setWorldTransform(), setWindow(), setViewport()
8151
*/
8152
8153
QTransform QPainter::combinedTransform() const
8154
0
{
8155
0
    Q_D(const QPainter);
8156
0
    if (!d->engine) {
8157
0
        qWarning("QPainter::combinedTransform: Painter not active");
8158
0
        return QTransform();
8159
0
    }
8160
0
    return d->state->worldMatrix * d->viewTransform() * d->hidpiScaleTransform();
8161
0
}
8162
8163
/*!
8164
    \since 4.7
8165
8166
    This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap,
8167
    at multiple positions with different scale, rotation and opacity. \a
8168
    fragments is an array of \a fragmentCount elements specifying the
8169
    parameters used to draw each pixmap fragment. The \a hints
8170
    parameter can be used to pass in drawing hints.
8171
8172
    This function is potentially faster than multiple calls to drawPixmap(),
8173
    since the backend can optimize state changes.
8174
8175
    \sa QPainter::PixmapFragment, QPainter::PixmapFragmentHint
8176
*/
8177
8178
void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
8179
                                   const QPixmap &pixmap, PixmapFragmentHints hints)
8180
0
{
8181
0
    Q_D(QPainter);
8182
8183
0
    if (!d->engine || pixmap.isNull())
8184
0
        return;
8185
8186
0
#ifndef QT_NO_DEBUG
8187
0
    for (int i = 0; i < fragmentCount; ++i) {
8188
0
        QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8189
0
                          fragments[i].width, fragments[i].height);
8190
0
        if (!(QRectF(pixmap.rect()).contains(sourceRect)))
8191
0
            qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
8192
0
    }
8193
0
#endif
8194
8195
0
    if (d->engine->isExtended()) {
8196
0
        d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8197
0
    } else {
8198
0
        qreal oldOpacity = opacity();
8199
0
        QTransform oldTransform = transform();
8200
8201
0
        for (int i = 0; i < fragmentCount; ++i) {
8202
0
            QTransform transform = oldTransform;
8203
0
            qreal xOffset = 0;
8204
0
            qreal yOffset = 0;
8205
0
            if (fragments[i].rotation == 0) {
8206
0
                xOffset = fragments[i].x;
8207
0
                yOffset = fragments[i].y;
8208
0
            } else {
8209
0
                transform.translate(fragments[i].x, fragments[i].y);
8210
0
                transform.rotate(fragments[i].rotation);
8211
0
            }
8212
0
            setOpacity(oldOpacity * fragments[i].opacity);
8213
0
            setTransform(transform);
8214
8215
0
            qreal w = fragments[i].scaleX * fragments[i].width;
8216
0
            qreal h = fragments[i].scaleY * fragments[i].height;
8217
0
            QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8218
0
                              fragments[i].width, fragments[i].height);
8219
0
            drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8220
0
        }
8221
8222
0
        setOpacity(oldOpacity);
8223
0
        setTransform(oldTransform);
8224
0
    }
8225
0
}
8226
8227
/*!
8228
    \since 4.7
8229
    \class QPainter::PixmapFragment
8230
    \inmodule QtGui
8231
8232
    \brief This class is used in conjunction with the
8233
    QPainter::drawPixmapFragments() function to specify how a pixmap, or
8234
    sub-rect of a pixmap, is drawn.
8235
8236
    The \a sourceLeft, \a sourceTop, \a width and \a height variables are used
8237
    as a source rectangle within the pixmap passed into the
8238
    QPainter::drawPixmapFragments() function. The variables \a x, \a y, \a
8239
    width and \a height are used to calculate the target rectangle that is
8240
    drawn. \a x and \a y denotes the center of the target rectangle. The \a
8241
    width and \a height in the target rectangle is scaled by the \a scaleX and
8242
    \a scaleY values. The resulting target rectangle is then rotated \a
8243
    rotation degrees around the \a x, \a y center point.
8244
8245
    \sa QPainter::drawPixmapFragments()
8246
*/
8247
8248
/*!
8249
    \since 4.7
8250
8251
    This is a convenience function that returns a QPainter::PixmapFragment that is
8252
    initialized with the \a pos, \a sourceRect, \a scaleX, \a scaleY, \a
8253
    rotation, \a opacity parameters.
8254
*/
8255
8256
QPainter::PixmapFragment QPainter::PixmapFragment::create(const QPointF &pos, const QRectF &sourceRect,
8257
                                              qreal scaleX, qreal scaleY, qreal rotation,
8258
                                              qreal opacity)
8259
0
{
8260
0
    PixmapFragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(),
8261
0
                               sourceRect.height(), scaleX, scaleY, rotation, opacity};
8262
0
    return fragment;
8263
0
}
8264
8265
/*!
8266
    \variable QPainter::PixmapFragment::x
8267
    \brief the x coordinate of center point in the target rectangle.
8268
*/
8269
8270
/*!
8271
    \variable QPainter::PixmapFragment::y
8272
    \brief the y coordinate of the center point in the target rectangle.
8273
*/
8274
8275
/*!
8276
    \variable QPainter::PixmapFragment::sourceLeft
8277
    \brief the left coordinate of the source rectangle.
8278
*/
8279
8280
/*!
8281
    \variable QPainter::PixmapFragment::sourceTop
8282
    \brief the top coordinate of the source rectangle.
8283
*/
8284
8285
/*!
8286
    \variable QPainter::PixmapFragment::width
8287
8288
    \brief the width of the source rectangle and is used to calculate the width
8289
    of the target rectangle.
8290
*/
8291
8292
/*!
8293
    \variable QPainter::PixmapFragment::height
8294
8295
    \brief the height of the source rectangle and is used to calculate the
8296
    height of the target rectangle.
8297
*/
8298
8299
/*!
8300
    \variable QPainter::PixmapFragment::scaleX
8301
    \brief the horizontal scale of the target rectangle.
8302
*/
8303
8304
/*!
8305
    \variable QPainter::PixmapFragment::scaleY
8306
    \brief the vertical scale of the target rectangle.
8307
*/
8308
8309
/*!
8310
    \variable QPainter::PixmapFragment::rotation
8311
8312
    \brief the rotation of the target rectangle in degrees. The target
8313
    rectangle is rotated after it has been scaled.
8314
*/
8315
8316
/*!
8317
    \variable QPainter::PixmapFragment::opacity
8318
8319
    \brief the opacity of the target rectangle, where 0.0 is fully transparent
8320
    and 1.0 is fully opaque.
8321
*/
8322
8323
/*!
8324
    \since 4.7
8325
8326
    \enum QPainter::PixmapFragmentHint
8327
8328
    \value OpaqueHint Indicates that the pixmap fragments to be drawn are
8329
    opaque. Opaque fragments are potentially faster to draw.
8330
8331
    \sa QPainter::drawPixmapFragments(), QPainter::PixmapFragment
8332
*/
8333
8334
void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
8335
0
{
8336
0
    p->draw_helper(path, operation);
8337
0
}
8338
8339
QT_END_NAMESPACE
8340
8341
#include "moc_qpainter.cpp"