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

source code of qtbase/src/gui/painting/qpainter.cpp