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