Coverage Report

Created: 2025-07-12 07:23

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