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