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