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