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.