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