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

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