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(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(QPlatformIntegration::ThreadedPixmaps))
164 // framebuffer objects and such cannot be targets unless threaded GL is supported
165 && (devType != QInternal::OpenGL || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL))
166 // widgets cannot be targets except for QGLWidget
167 && (devType != QInternal::Widget || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL)
168 || (engineType != QPaintEngine::OpenGL && engineType != QPaintEngine::OpenGL2))) {
169 qWarning("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
178void QPainterPrivate::checkEmulation()
179{
180 Q_ASSERT(extended);
181 bool doEmulation = false;
182 if (state->bgMode == Qt::OpaqueMode)
183 doEmulation = true;
184
185 const QGradient *bg = state->brush.gradient();
186 if (bg && bg->coordinateMode() > QGradient::LogicalMode)
187 doEmulation = true;
188
189 const QGradient *pg = qpen_brush(state->pen).gradient();
190 if (pg && pg->coordinateMode() > QGradient::LogicalMode)
191 doEmulation = true;
192
193 if (state->brush.style() == Qt::TexturePattern) {
194 if (qHasPixmapTexture(state->brush))
195 doEmulation |= !qFuzzyCompare(state->brush.texture().devicePixelRatioF(), 1.0);
196 else
197 doEmulation |= !qFuzzyCompare(state->brush.textureImage().devicePixelRatioF(), 1.0);
198 }
199
200 if (doEmulation && extended->flags() & QPaintEngineEx::DoNotEmulate)
201 return;
202
203 if (doEmulation) {
204 if (extended != emulationEngine) {
205 if (!emulationEngine)
206 emulationEngine = new QEmulationPaintEngine(extended);
207 extended = emulationEngine;
208 extended->setState(state);
209 }
210 } else if (emulationEngine == extended) {
211 extended = emulationEngine->real_engine;
212 }
213}
214
215
216QPainterPrivate::~QPainterPrivate()
217{
218 delete emulationEngine;
219 qDeleteAll(states);
220 delete dummyState;
221}
222
223
224QTransform QPainterPrivate::viewTransform() const
225{
226 if (state->VxF) {
227 qreal scaleW = qreal(state->vw)/qreal(state->ww);
228 qreal scaleH = qreal(state->vh)/qreal(state->wh);
229 return QTransform(scaleW, 0, 0, scaleH,
230 state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
231 }
232 return QTransform();
233}
234
235qreal QPainterPrivate::effectiveDevicePixelRatio() const
236{
237 // Special cases for devices that does not support PdmDevicePixelRatio go here:
238 if (device->devType() == QInternal::Printer)
239 return qreal(1);
240
241 return qMax(qreal(1), device->devicePixelRatioF());
242}
243
244QTransform QPainterPrivate::hidpiScaleTransform() const
245{
246 const qreal devicePixelRatio = effectiveDevicePixelRatio();
247 return QTransform::fromScale(devicePixelRatio, devicePixelRatio);
248}
249
250/*
251 \internal
252 Returns \c true if using a shared painter; otherwise false.
253*/
254bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
255{
256 Q_ASSERT(q);
257 Q_ASSERT(pdev);
258
259 QPainter *sp = pdev->sharedPainter();
260 if (!sp)
261 return false;
262
263 // Save the current state of the shared painter and assign
264 // the current d_ptr to the shared painter's d_ptr.
265 sp->save();
266 if (!sp->d_ptr->d_ptrs) {
267 // Allocate space for 4 d-pointers (enough for up to 4 sub-sequent
268 // redirections within the same paintEvent(), which should be enough
269 // in 99% of all cases). E.g: A renders B which renders C which renders D.
270 sp->d_ptr->d_ptrs_size = 4;
271 sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *));
272 Q_CHECK_PTR(sp->d_ptr->d_ptrs);
273 } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) {
274 // However, to support corner cases we grow the array dynamically if needed.
275 sp->d_ptr->d_ptrs_size <<= 1;
276 const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *);
277 sp->d_ptr->d_ptrs = q_check_ptr((QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize));
278 }
279 sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr.data();
280 q->d_ptr.take();
281 q->d_ptr.reset(sp->d_ptr.data());
282
283 Q_ASSERT(q->d_ptr->state);
284
285 // Now initialize the painter with correct widget properties.
286 q->d_ptr->initFrom(pdev);
287 QPoint offset;
288 pdev->redirected(&offset);
289 offset += q->d_ptr->engine->coordinateOffset();
290
291 // Update system rect.
292 q->d_ptr->state->ww = q->d_ptr->state->vw = pdev->width();
293 q->d_ptr->state->wh = q->d_ptr->state->vh = pdev->height();
294
295 // Update matrix.
296 if (q->d_ptr->state->WxF) {
297 q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
298 q->d_ptr->state->redirectionMatrix *= q->d_ptr->hidpiScaleTransform().inverted();
299 q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
300 q->d_ptr->state->worldMatrix = QTransform();
301 q->d_ptr->state->WxF = false;
302 } else {
303 q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
304 }
305 q->d_ptr->updateMatrix();
306
307 QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
308 if (enginePrivate->currentClipDevice == pdev) {
309 enginePrivate->systemStateChanged();
310 return true;
311 }
312
313 // Update system transform and clip.
314 enginePrivate->currentClipDevice = pdev;
315 enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
316 return true;
317}
318
319void QPainterPrivate::detachPainterPrivate(QPainter *q)
320{
321 Q_ASSERT(refcount > 1);
322 Q_ASSERT(q);
323
324 QPainterPrivate *original = d_ptrs[--refcount - 1];
325 if (inDestructor) {
326 inDestructor = false;
327 if (original)
328 original->inDestructor = true;
329 } else if (!original) {
330 original = new QPainterPrivate(q);
331 }
332
333 d_ptrs[refcount - 1] = nullptr;
334 q->restore();
335 q->d_ptr.take();
336 q->d_ptr.reset(original);
337
338 if (emulationEngine) {
339 extended = emulationEngine->real_engine;
340 delete emulationEngine;
341 emulationEngine = nullptr;
342 }
343}
344
345
346void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op)
347{
348#ifdef QT_DEBUG_DRAW
349 if (qt_show_painter_debug_output) {
350 printf("QPainter::drawHelper\n");
351 }
352#endif
353
354 if (originalPath.isEmpty())
355 return;
356
357 QPaintEngine::PaintEngineFeatures gradientStretch =
358 QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
359 | QPaintEngine::ObjectBoundingModeGradients);
360
361 const bool mustEmulateObjectBoundingModeGradients = extended
362 || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
363 && !engine->hasFeature(QPaintEngine::PatternTransform));
364
365 if (!(state->emulationSpecifier & ~gradientStretch)
366 && !mustEmulateObjectBoundingModeGradients) {
367 drawStretchedGradient(originalPath, op);
368 return;
369 } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
370 drawOpaqueBackground(originalPath, op);
371 return;
372 }
373
374 Q_Q(QPainter);
375
376 qreal strokeOffsetX = 0, strokeOffsetY = 0;
377
378 QPainterPath path = originalPath * state->matrix;
379 QRectF pathBounds = path.boundingRect();
380 QRectF strokeBounds;
381 bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
382 if (doStroke) {
383 qreal penWidth = state->pen.widthF();
384 if (penWidth == 0) {
385 strokeOffsetX = 1;
386 strokeOffsetY = 1;
387 } else {
388 // In case of complex xform
389 if (state->matrix.type() > QTransform::TxScale) {
390 QPainterPathStroker stroker;
391 stroker.setWidth(penWidth);
392 stroker.setJoinStyle(state->pen.joinStyle());
393 stroker.setCapStyle(state->pen.capStyle());
394 QPainterPath stroke = stroker.createStroke(originalPath);
395 strokeBounds = (stroke * state->matrix).boundingRect();
396 } else {
397 strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
398 strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
399 }
400 }
401 }
402
403 QRect absPathRect;
404 if (!strokeBounds.isEmpty()) {
405 absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
406 } else {
407 absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
408 .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
409 }
410
411 if (q->hasClipping()) {
412 bool hasPerspectiveTransform = false;
413 for (const QPainterClipInfo &info : qAsConst(state->clipInfo)) {
414 if (info.matrix.type() == QTransform::TxProject) {
415 hasPerspectiveTransform = true;
416 break;
417 }
418 }
419 // avoid mapping QRegions with perspective transforms
420 if (!hasPerspectiveTransform) {
421 // The trick with txinv and invMatrix is done in order to
422 // avoid transforming the clip to logical coordinates, and
423 // then back to device coordinates. This is a problem with
424 // QRegion/QRect based clips, since they use integer
425 // coordinates and converting to/from logical coordinates will
426 // lose precision.
427 bool old_txinv = txinv;
428 QTransform old_invMatrix = invMatrix;
429 txinv = true;
430 invMatrix = QTransform();
431 QPainterPath clipPath = q->clipPath();
432 QRectF r = clipPath.boundingRect().intersected(absPathRect);
433 absPathRect = r.toAlignedRect();
434 txinv = old_txinv;
435 invMatrix = old_invMatrix;
436 }
437 }
438
439// qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
440// devMinX, devMinY, device->width(), device->height());
441// qDebug() << " - matrix" << state->matrix;
442// qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
443// qDebug() << " - path.bounds" << path.boundingRect();
444
445 if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
446 return;
447
448 QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
449 image.fill(0);
450
451 QPainter p(&image);
452
453 p.d_ptr->helper_device = helper_device;
454
455 p.setOpacity(state->opacity);
456 p.translate(-absPathRect.x(), -absPathRect.y());
457 p.setTransform(state->matrix, true);
458 p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
459 p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
460 p.setBackground(state->bgBrush);
461 p.setBackgroundMode(state->bgMode);
462 p.setBrushOrigin(state->brushOrigin);
463
464 p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
465 p.setRenderHint(QPainter::SmoothPixmapTransform,
466 state->renderHints & QPainter::SmoothPixmapTransform);
467
468 p.drawPath(originalPath);
469
470#ifndef QT_NO_DEBUG
471 static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty("QT_PAINT_FALLBACK_OVERLAY");
472 if (do_fallback_overlay) {
473 QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
474 QPainter pt(&block);
475 pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
476 pt.drawLine(0, 0, 8, 8);
477 pt.end();
478 p.resetTransform();
479 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
480 p.setOpacity(0.5);
481 p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
482 }
483#endif
484
485 p.end();
486
487 q->save();
488 state->matrix = QTransform();
489 if (extended) {
490 extended->transformChanged();
491 } else {
492 state->dirtyFlags |= QPaintEngine::DirtyTransform;
493 updateState(state);
494 }
495 engine->drawImage(absPathRect,
496 image,
497 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
498 Qt::OrderedDither | Qt::OrderedAlphaDither);
499 q->restore();
500}
501
502void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op)
503{
504 Q_Q(QPainter);
505
506 q->setBackgroundMode(Qt::TransparentMode);
507
508 if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
509 q->fillPath(path, state->bgBrush.color());
510 q->fillPath(path, state->brush);
511 }
512
513 if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
514 q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
515 q->strokePath(path, state->pen);
516 }
517
518 q->setBackgroundMode(Qt::OpaqueMode);
519}
520
521static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
522{
523 Q_ASSERT(brush.style() >= Qt::LinearGradientPattern
524 && brush.style() <= Qt::ConicalGradientPattern);
525
526 QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
527 boundingRect.x(), boundingRect.y());
528
529 QGradient g = *brush.gradient();
530 g.setCoordinateMode(QGradient::LogicalMode);
531
532 QBrush b(g);
533 if (brush.gradient()->coordinateMode() == QGradient::ObjectMode)
534 b.setTransform(b.transform() * gradientToUser);
535 else
536 b.setTransform(gradientToUser * b.transform());
537 return b;
538}
539
540void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperation op)
541{
542 Q_Q(QPainter);
543
544 const qreal sw = helper_device->width();
545 const qreal sh = helper_device->height();
546
547 bool changedPen = false;
548 bool changedBrush = false;
549 bool needsFill = false;
550
551 const QPen pen = state->pen;
552 const QBrush brush = state->brush;
553
554 const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
555 const QGradient::CoordinateMode brushMode = coordinateMode(brush);
556
557 QRectF boundingRect;
558
559 // Draw the xformed fill if the brush is a stretch gradient.
560 if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
561 if (brushMode == QGradient::StretchToDeviceMode) {
562 q->setPen(Qt::NoPen);
563 changedPen = pen.style() != Qt::NoPen;
564 q->scale(sw, sh);
565 updateState(state);
566
567 const qreal isw = 1.0 / sw;
568 const qreal ish = 1.0 / sh;
569 QTransform inv(isw, 0, 0, ish, 0, 0);
570 engine->drawPath(path * inv);
571 q->scale(isw, ish);
572 } else {
573 needsFill = true;
574
575 if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
576 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
577 boundingRect = path.boundingRect();
578 q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
579 changedBrush = true;
580 }
581 }
582 }
583
584 if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
585 // Draw the xformed outline if the pen is a stretch gradient.
586 if (penMode == QGradient::StretchToDeviceMode) {
587 q->setPen(Qt::NoPen);
588 changedPen = true;
589
590 if (needsFill) {
591 updateState(state);
592 engine->drawPath(path);
593 }
594
595 q->scale(sw, sh);
596 q->setBrush(pen.brush());
597 changedBrush = true;
598 updateState(state);
599
600 QPainterPathStroker stroker;
601 stroker.setDashPattern(pen.style());
602 stroker.setWidth(pen.widthF());
603 stroker.setJoinStyle(pen.joinStyle());
604 stroker.setCapStyle(pen.capStyle());
605 stroker.setMiterLimit(pen.miterLimit());
606 QPainterPath stroke = stroker.createStroke(path);
607
608 const qreal isw = 1.0 / sw;
609 const qreal ish = 1.0 / sh;
610 QTransform inv(isw, 0, 0, ish, 0, 0);
611 engine->drawPath(stroke * inv);
612 q->scale(isw, ish);
613 } else {
614 if (!needsFill && brush.style() != Qt::NoBrush) {
615 q->setBrush(Qt::NoBrush);
616 changedBrush = true;
617 }
618
619 if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
620 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
621
622 // avoid computing the bounding rect twice
623 if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
624 boundingRect = path.boundingRect();
625
626 QPen p = pen;
627 p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
628 q->setPen(p);
629 changedPen = true;
630 } else if (changedPen) {
631 q->setPen(pen);
632 changedPen = false;
633 }
634
635 updateState(state);
636 engine->drawPath(path);
637 }
638 } else if (needsFill) {
639 if (pen.style() != Qt::NoPen) {
640 q->setPen(Qt::NoPen);
641 changedPen = true;
642 }
643
644 updateState(state);
645 engine->drawPath(path);
646 }
647
648 if (changedPen)
649 q->setPen(pen);
650 if (changedBrush)
651 q->setBrush(brush);
652}
653
654
655void QPainterPrivate::updateMatrix()
656{
657 state->matrix = state->WxF ? state->worldMatrix : QTransform();
658 if (state->VxF)
659 state->matrix *= viewTransform();
660
661 txinv = false; // no inverted matrix
662 state->matrix *= state->redirectionMatrix;
663 if (extended)
664 extended->transformChanged();
665 else
666 state->dirtyFlags |= QPaintEngine::DirtyTransform;
667
668 state->matrix *= hidpiScaleTransform();
669
670// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
671// qDebug() << " --- using matrix" << state->matrix << redirection_offset;
672}
673
674/*! \internal */
675void QPainterPrivate::updateInvMatrix()
676{
677 Q_ASSERT(txinv == false);
678 txinv = true; // creating inverted matrix
679 invMatrix = state->matrix.inverted();
680}
681
682extern bool qt_isExtendedRadialGradient(const QBrush &brush);
683
684void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
685{
686 bool alpha = false;
687 bool linearGradient = false;
688 bool radialGradient = false;
689 bool extendedRadialGradient = false;
690 bool conicalGradient = false;
691 bool patternBrush = false;
692 bool xform = false;
693 bool complexXform = false;
694
695 bool skip = true;
696
697 // Pen and brush properties (we have to check both if one changes because the
698 // one that's unchanged can still be in a state which requires emulation)
699 if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
700 // Check Brush stroke emulation
701 if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
702 s->emulationSpecifier |= QPaintEngine::BrushStroke;
703 else
704 s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
705
706 skip = false;
707
708 QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
709 Qt::BrushStyle brushStyle = qbrush_style(s->brush);
710 Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
711 alpha = (penBrushStyle != Qt::NoBrush
712 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
713 && !penBrush.isOpaque())
714 || (brushStyle != Qt::NoBrush
715 && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
716 && !s->brush.isOpaque());
717 linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
718 (brushStyle == Qt::LinearGradientPattern));
719 radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
720 (brushStyle == Qt::RadialGradientPattern));
721 extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
722 conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
723 (brushStyle == Qt::ConicalGradientPattern));
724 patternBrush = (((penBrushStyle > Qt::SolidPattern
725 && penBrushStyle < Qt::LinearGradientPattern)
726 || penBrushStyle == Qt::TexturePattern) ||
727 ((brushStyle > Qt::SolidPattern
728 && brushStyle < Qt::LinearGradientPattern)
729 || brushStyle == Qt::TexturePattern));
730
731 bool penTextureAlpha = false;
732 if (penBrush.style() == Qt::TexturePattern)
733 penTextureAlpha = qHasPixmapTexture(penBrush)
734 ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
735 : penBrush.textureImage().hasAlphaChannel();
736 bool brushTextureAlpha = false;
737 if (s->brush.style() == Qt::TexturePattern) {
738 brushTextureAlpha = qHasPixmapTexture(s->brush)
739 ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
740 : s->brush.textureImage().hasAlphaChannel();
741 }
742 if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
743 || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
744 && !engine->hasFeature(QPaintEngine::MaskedBrush))
745 s->emulationSpecifier |= QPaintEngine::MaskedBrush;
746 else
747 s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
748 }
749
750 if (s->state() & (QPaintEngine::DirtyHints
751 | QPaintEngine::DirtyOpacity
752 | QPaintEngine::DirtyBackgroundMode)) {
753 skip = false;
754 }
755
756 if (skip)
757 return;
758
759#if 0
760 qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
761 " - alpha: %d\n"
762 " - linearGradient: %d\n"
763 " - radialGradient: %d\n"
764 " - conicalGradient: %d\n"
765 " - patternBrush: %d\n"
766 " - hints: %x\n"
767 " - xform: %d\n",
768 s,
769 alpha,
770 linearGradient,
771 radialGradient,
772 conicalGradient,
773 patternBrush,
774 uint(s->renderHints),
775 xform);
776#endif
777
778 // XForm properties
779 if (s->state() & QPaintEngine::DirtyTransform) {
780 xform = !s->matrix.isIdentity();
781 complexXform = !s->matrix.isAffine();
782 } else if (s->matrix.type() >= QTransform::TxTranslate) {
783 xform = true;
784 complexXform = !s->matrix.isAffine();
785 }
786
787 const bool brushXform = (s->brush.transform().type() != QTransform::TxNone);
788 const bool penXform = (s->pen.brush().transform().type() != QTransform::TxNone);
789
790 const bool patternXform = patternBrush && (xform || brushXform || penXform);
791
792 // Check alphablending
793 if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
794 s->emulationSpecifier |= QPaintEngine::AlphaBlend;
795 else
796 s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
797
798 // Linear gradient emulation
799 if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
800 s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
801 else
802 s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
803
804 // Radial gradient emulation
805 if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
806 s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
807 else
808 s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
809
810 // Conical gradient emulation
811 if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
812 s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
813 else
814 s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
815
816 // Pattern brushes
817 if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
818 s->emulationSpecifier |= QPaintEngine::PatternBrush;
819 else
820 s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
821
822 // Pattern XForms
823 if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
824 s->emulationSpecifier |= QPaintEngine::PatternTransform;
825 else
826 s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
827
828 // Primitive XForms
829 if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
830 s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
831 else
832 s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
833
834 // Perspective XForms
835 if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
836 s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
837 else
838 s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
839
840 // Constant opacity
841 if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
842 s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
843 else
844 s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
845
846 bool gradientStretch = false;
847 bool objectBoundingMode = false;
848 if (linearGradient || conicalGradient || radialGradient) {
849 QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
850 QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
851
852 gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
853 gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
854
855 objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
856 objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
857 }
858 if (gradientStretch)
859 s->emulationSpecifier |= QGradient_StretchToDevice;
860 else
861 s->emulationSpecifier &= ~QGradient_StretchToDevice;
862
863 if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
864 s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
865 else
866 s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
867
868 // Opaque backgrounds...
869 if (s->bgMode == Qt::OpaqueMode &&
870 (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
871 s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
872 else
873 s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
874
875#if 0
876 //won't be correct either way because the device can already have
877 // something rendered to it in which case subsequent emulation
878 // on a fully transparent qimage and then blitting the results
879 // won't produce correct results
880 // Blend modes
881 if (state->composition_mode > QPainter::CompositionMode_Xor &&
882 !engine->hasFeature(QPaintEngine::BlendModes))
883 s->emulationSpecifier |= QPaintEngine::BlendModes;
884 else
885 s->emulationSpecifier &= ~QPaintEngine::BlendModes;
886#endif
887}
888
889void QPainterPrivate::updateStateImpl(QPainterState *newState)
890{
891 // ### we might have to call QPainter::begin() here...
892 if (!engine->state) {
893 engine->state = newState;
894 engine->setDirty(QPaintEngine::AllDirty);
895 }
896
897 if (engine->state->painter() != newState->painter)
898 // ### this could break with clip regions vs paths.
899 engine->setDirty(QPaintEngine::AllDirty);
900
901 // Upon restore, revert all changes since last save
902 else if (engine->state != newState)
903 newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
904
905 // We need to store all changes made so that restore can deal with them
906 else
907 newState->changeFlags |= newState->dirtyFlags;
908
909 updateEmulationSpecifier(newState);
910
911 // Unset potential dirty background mode
912 newState->dirtyFlags &= ~(QPaintEngine::DirtyBackgroundMode
913 | QPaintEngine::DirtyBackground);
914
915 engine->state = newState;
916 engine->updateState(*newState);
917 engine->clearDirty(QPaintEngine::AllDirty);
918
919}
920
921void QPainterPrivate::updateState(QPainterState *newState)
922{
923
924 if (!newState) {
925 engine->state = newState;
926 } else if (newState->state() || engine->state!=newState) {
927 updateStateImpl(newState);
928 }
929}
930
931
932/*!
933 \class QPainter
934 \brief The QPainter class performs low-level painting on widgets and
935 other paint devices.
936
937 \inmodule QtGui
938 \ingroup painting
939
940 \reentrant
941
942 QPainter provides highly optimized functions to do most of the
943 drawing GUI programs require. It can draw everything from simple
944 lines to complex shapes like pies and chords. It can also draw
945 aligned text and pixmaps. Normally, it draws in a "natural"
946 coordinate system, but it can also do view and world
947 transformation. QPainter can operate on any object that inherits
948 the QPaintDevice class.
949
950 The common use of QPainter is inside a widget's paint event:
951 Construct and customize (e.g. set the pen or the brush) the
952 painter. Then draw. Remember to destroy the QPainter object after
953 drawing. For example:
954
955 \snippet code/src_gui_painting_qpainter.cpp 0
956
957 The core functionality of QPainter is drawing, but the class also
958 provide several functions that allows you to customize QPainter's
959 settings and its rendering quality, and others that enable
960 clipping. In addition you can control how different shapes are
961 merged together by specifying the painter's composition mode.
962
963 The isActive() function indicates whether the painter is active. A
964 painter is activated by the begin() function and the constructor
965 that takes a QPaintDevice argument. The end() function, and the
966 destructor, deactivates it.
967
968 Together with the QPaintDevice and QPaintEngine classes, QPainter
969 form the basis for Qt's paint system. QPainter is the class used
970 to perform drawing operations. QPaintDevice represents a device
971 that can be painted on using a QPainter. QPaintEngine provides the
972 interface that the painter uses to draw onto different types of
973 devices. If the painter is active, device() returns the paint
974 device on which the painter paints, and paintEngine() returns the
975 paint engine that the painter is currently operating on. For more
976 information, see the \l {Paint System}.
977
978 Sometimes it is desirable to make someone else paint on an unusual
979 QPaintDevice. QPainter supports a static function to do this,
980 setRedirected().
981
982 \warning When the paintdevice is a widget, QPainter can only be
983 used inside a paintEvent() function or in a function called by
984 paintEvent().
985
986 \tableofcontents
987
988 \section1 Settings
989
990 There are several settings that you can customize to make QPainter
991 draw according to your preferences:
992
993 \list
994
995 \li font() is the font used for drawing text. If the painter
996 isActive(), you can retrieve information about the currently set
997 font, and its metrics, using the fontInfo() and fontMetrics()
998 functions respectively.
999
1000 \li brush() defines the color or pattern that is used for filling
1001 shapes.
1002
1003 \li pen() defines the color or stipple that is used for drawing
1004 lines or boundaries.
1005
1006 \li backgroundMode() defines whether there is a background() or
1007 not, i.e it is either Qt::OpaqueMode or Qt::TransparentMode.
1008
1009 \li background() only applies when backgroundMode() is \l
1010 Qt::OpaqueMode and pen() is a stipple. In that case, it
1011 describes the color of the background pixels in the stipple.
1012
1013 \li brushOrigin() defines the origin of the tiled brushes, normally
1014 the origin of widget's background.
1015
1016 \li viewport(), window(), worldTransform() make up the painter's coordinate
1017 transformation system. For more information, see the \l
1018 {Coordinate Transformations} section and the \l {Coordinate
1019 System} documentation.
1020
1021 \li hasClipping() tells whether the painter clips at all. (The paint
1022 device clips, too.) If the painter clips, it clips to clipRegion().
1023
1024 \li layoutDirection() defines the layout direction used by the
1025 painter when drawing text.
1026
1027 \li worldMatrixEnabled() tells whether world transformation is enabled.
1028
1029 \li viewTransformEnabled() tells whether view transformation is
1030 enabled.
1031
1032 \endlist
1033
1034 Note that some of these settings mirror settings in some paint
1035 devices, e.g. QWidget::font(). The QPainter::begin() function (or
1036 equivalently the QPainter constructor) copies these attributes
1037 from the paint device.
1038
1039 You can at any time save the QPainter's state by calling the
1040 save() function which saves all the available settings on an
1041 internal stack. The restore() function pops them back.
1042
1043 \section1 Drawing
1044
1045 QPainter provides functions to draw most primitives: drawPoint(),
1046 drawPoints(), drawLine(), drawRect(), drawRoundedRect(),
1047 drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(),
1048 drawPolygon(), drawConvexPolygon() and drawCubicBezier(). The two
1049 convenience functions, drawRects() and drawLines(), draw the given
1050 number of rectangles or lines in the given array of \l
1051 {QRect}{QRects} or \l {QLine}{QLines} using the current pen and
1052 brush.
1053
1054 The QPainter class also provides the fillRect() function which
1055 fills the given QRect, with the given QBrush, and the eraseRect()
1056 function that erases the area inside the given rectangle.
1057
1058 All of these functions have both integer and floating point
1059 versions.
1060
1061 \table 100%
1062 \row
1063 \li \inlineimage qpainter-basicdrawing.png
1064 \li
1065 \b {Basic Drawing Example}
1066
1067 The \l {painting/basicdrawing}{Basic Drawing} example shows how to
1068 display basic graphics primitives in a variety of styles using the
1069 QPainter class.
1070
1071 \endtable
1072
1073 If you need to draw a complex shape, especially if you need to do
1074 so repeatedly, consider creating a QPainterPath and drawing it
1075 using drawPath().
1076
1077 \table 100%
1078 \row
1079 \li
1080 \b {Painter Paths example}
1081
1082 The QPainterPath class provides a container for painting
1083 operations, enabling graphical shapes to be constructed and
1084 reused.
1085
1086 The \l {painting/painterpaths}{Painter Paths} example shows how
1087 painter paths can be used to build complex shapes for rendering.
1088
1089 \li \inlineimage qpainter-painterpaths.png
1090 \endtable
1091
1092 QPainter also provides the fillPath() function which fills the
1093 given QPainterPath with the given QBrush, and the strokePath()
1094 function that draws the outline of the given path (i.e. strokes
1095 the path).
1096
1097 See also the \l {painting/deform}{Vector Deformation} example which
1098 shows how to use advanced vector techniques to draw text using a
1099 QPainterPath, the \l {painting/gradients}{Gradients} example which shows
1100 the different types of gradients that are available in Qt, and the \l
1101 {painting/pathstroke}{Path Stroking} example which shows Qt's built-in
1102 dash patterns and shows how custom patterns can be used to extend
1103 the range of available patterns.
1104
1105 \table
1106 \header
1107 \li \l {painting/deform}{Vector Deformation}
1108 \li \l {painting/gradients}{Gradients}
1109 \li \l {painting/pathstroke}{Path Stroking}
1110 \row
1111 \li \inlineimage qpainter-vectordeformation.png
1112 \li \inlineimage qpainter-gradients.png
1113 \li \inlineimage qpainter-pathstroking.png
1114 \endtable
1115
1116 Text drawing is done using drawText(). When you need
1117 fine-grained positioning, boundingRect() tells you where a given
1118 drawText() command will draw.
1119
1120 \section1 Drawing Pixmaps and Images
1121
1122 There are functions to draw pixmaps/images, namely drawPixmap(),
1123 drawImage() and drawTiledPixmap(). Both drawPixmap() and drawImage()
1124 produce the same result, except that drawPixmap() is faster
1125 on-screen while drawImage() may be faster on a QPrinter or other
1126 devices.
1127
1128 There is a drawPicture() function that draws the contents of an
1129 entire QPicture. The drawPicture() function is the only function
1130 that disregards all the painter's settings as QPicture has its own
1131 settings.
1132
1133 \section2 Drawing High Resolution Versions of Pixmaps and Images
1134
1135 High resolution versions of pixmaps have a \e{device pixel ratio} value larger
1136 than 1 (see QImageReader, QPixmap::devicePixelRatio()). Should it match the value
1137 of the underlying QPaintDevice, it is drawn directly onto the device with no
1138 additional transformation applied.
1139
1140 This is for example the case when drawing a QPixmap of 64x64 pixels size with
1141 a device pixel ratio of 2 onto a high DPI screen which also has
1142 a device pixel ratio of 2. Note that the pixmap is then effectively 32x32
1143 pixels in \e{user space}. Code paths in Qt that calculate layout geometry
1144 based on the pixmap size will use this size. The net effect of this is that
1145 the pixmap is displayed as high DPI pixmap rather than a large pixmap.
1146
1147 \section1 Rendering Quality
1148
1149 To get the optimal rendering result using QPainter, you should use
1150 the platform independent QImage as paint device; i.e. using QImage
1151 will ensure that the result has an identical pixel representation
1152 on any platform.
1153
1154 The QPainter class also provides a means of controlling the
1155 rendering quality through its RenderHint enum and the support for
1156 floating point precision: All the functions for drawing primitives
1157 has a floating point version. These are often used in combination
1158 with the \l {RenderHint}{QPainter::Antialiasing} render hint.
1159
1160 \table 100%
1161 \row
1162 \li \inlineimage qpainter-concentriccircles.png
1163 \li
1164 \b {Concentric Circles Example}
1165
1166 The \l {painting/concentriccircles}{Concentric Circles} example
1167 shows the improved rendering quality that can be obtained using
1168 floating point precision and anti-aliasing when drawing custom
1169 widgets.
1170
1171 The application's main window displays several widgets which are
1172 drawn using the various combinations of precision and
1173 anti-aliasing.
1174
1175 \endtable
1176
1177 The RenderHint enum specifies flags to QPainter that may or may
1178 not be respected by any given engine. \l
1179 {RenderHint}{QPainter::Antialiasing} indicates that the engine
1180 should antialias edges of primitives if possible, \l
1181 {RenderHint}{QPainter::TextAntialiasing} indicates that the engine
1182 should antialias text if possible, and the \l
1183 {RenderHint}{QPainter::SmoothPixmapTransform} indicates that the
1184 engine should use a smooth pixmap transformation algorithm.
1185
1186 The renderHints() function returns a flag that specifies the
1187 rendering hints that are set for this painter. Use the
1188 setRenderHint() function to set or clear the currently set
1189 RenderHints.
1190
1191 \section1 Coordinate Transformations
1192
1193 Normally, the QPainter operates on the device's own coordinate
1194 system (usually pixels), but QPainter has good support for
1195 coordinate transformations.
1196
1197 \table
1198 \header
1199 \li nop \li rotate() \li scale() \li translate()
1200 \row
1201 \li \inlineimage qpainter-clock.png
1202 \li \inlineimage qpainter-rotation.png
1203 \li \inlineimage qpainter-scale.png
1204 \li \inlineimage qpainter-translation.png
1205 \endtable
1206
1207 The most commonly used transformations are scaling, rotation,
1208 translation and shearing. Use the scale() function to scale the
1209 coordinate system by a given offset, the rotate() function to
1210 rotate it clockwise and translate() to translate it (i.e. adding a
1211 given offset to the points). You can also twist the coordinate
1212 system around the origin using the shear() function. See the \l
1213 {painting/affine}{Affine Transformations} example for a visualization of
1214 a sheared coordinate system.
1215
1216 See also the \l {painting/transformations}{Transformations}
1217 example which shows how transformations influence the way that
1218 QPainter renders graphics primitives. In particular it shows how
1219 the order of transformations affects the result.
1220
1221 \table 100%
1222 \row
1223 \li
1224 \b {Affine Transformations Example}
1225
1226 The \l {painting/affine}{Affine Transformations} example shows Qt's
1227 ability to perform affine transformations on painting
1228 operations. The demo also allows the user to experiment with the
1229 transformation operations and see the results immediately.
1230
1231 \li \inlineimage qpainter-affinetransformations.png
1232 \endtable
1233
1234 All the tranformation operations operate on the transformation
1235 worldTransform(). A matrix transforms a point in the plane to another
1236 point. For more information about the transformation matrix, see
1237 the \l {Coordinate System} and QTransform documentation.
1238
1239 The setWorldTransform() function can replace or add to the currently
1240 set worldTransform(). The resetTransform() function resets any
1241 transformations that were made using translate(), scale(),
1242 shear(), rotate(), setWorldTransform(), setViewport() and setWindow()
1243 functions. The deviceTransform() returns the matrix that transforms
1244 from logical coordinates to device coordinates of the platform
1245 dependent paint device. The latter function is only needed when
1246 using platform painting commands on the platform dependent handle,
1247 and the platform does not do transformations nativly.
1248
1249 When drawing with QPainter, we specify points using logical
1250 coordinates which then are converted into the physical coordinates
1251 of the paint device. The mapping of the logical coordinates to the
1252 physical coordinates are handled by QPainter's combinedTransform(), a
1253 combination of viewport() and window() and worldTransform(). The
1254 viewport() represents the physical coordinates specifying an
1255 arbitrary rectangle, the window() describes the same rectangle in
1256 logical coordinates, and the worldTransform() is identical with the
1257 transformation matrix.
1258
1259 See also \l {Coordinate System}
1260
1261 \section1 Clipping
1262
1263 QPainter can clip any drawing operation to a rectangle, a region,
1264 or a vector path. The current clip is available using the
1265 functions clipRegion() and clipPath(). Whether paths or regions are
1266 preferred (faster) depends on the underlying paintEngine(). For
1267 example, the QImage paint engine prefers paths while the X11 paint
1268 engine prefers regions. Setting a clip is done in the painters
1269 logical coordinates.
1270
1271 After QPainter's clipping, the paint device may also clip. For
1272 example, most widgets clip away the pixels used by child widgets,
1273 and most printers clip away an area near the edges of the paper.
1274 This additional clipping is not reflected by the return value of
1275 clipRegion() or hasClipping().
1276
1277 \section1 Composition Modes
1278 \target Composition Modes
1279
1280 QPainter provides the CompositionMode enum which defines the
1281 Porter-Duff rules for digital image compositing; it describes a
1282 model for combining the pixels in one image, the source, with the
1283 pixels in another image, the destination.
1284
1285 The two most common forms of composition are \l
1286 {QPainter::CompositionMode}{Source} and \l
1287 {QPainter::CompositionMode}{SourceOver}. \l
1288 {QPainter::CompositionMode}{Source} is used to draw opaque objects
1289 onto a paint device. In this mode, each pixel in the source
1290 replaces the corresponding pixel in the destination. In \l
1291 {QPainter::CompositionMode}{SourceOver} composition mode, the
1292 source object is transparent and is drawn on top of the
1293 destination.
1294
1295 Note that composition transformation operates pixelwise. For that
1296 reason, there is a difference between using the graphic primitive
1297 itself and its bounding rectangle: The bounding rect contains
1298 pixels with alpha == 0 (i.e the pixels surrounding the
1299 primitive). These pixels will overwrite the other image's pixels,
1300 effectively clearing those, while the primitive only overwrites
1301 its own area.
1302
1303 \table 100%
1304 \row
1305 \li \inlineimage qpainter-compositiondemo.png
1306
1307 \li
1308 \b {Composition Modes Example}
1309
1310 The \l {painting/composition}{Composition Modes} example, available in
1311 Qt's examples directory, allows you to experiment with the various
1312 composition modes and see the results immediately.
1313
1314 \endtable
1315
1316 \section1 Limitations
1317 \target Limitations
1318
1319 If you are using coordinates with Qt's raster-based paint engine, it is
1320 important to note that, while coordinates greater than +/- 2\sup 15 can
1321 be used, any painting performed with coordinates outside this range is not
1322 guaranteed to be shown; the drawing may be clipped. This is due to the
1323 use of \c{short int} in the implementation.
1324
1325 The outlines generated by Qt's stroker are only an approximation when dealing
1326 with curved shapes. It is in most cases impossible to represent the outline of
1327 a bezier curve segment using another bezier curve segment, and so Qt approximates
1328 the curve outlines by using several smaller curves. For performance reasons there
1329 is a limit to how many curves Qt uses for these outlines, and thus when using
1330 large pen widths or scales the outline error increases. To generate outlines with
1331 smaller errors it is possible to use the QPainterPathStroker class, which has the
1332 setCurveThreshold member function which let's the user specify the error tolerance.
1333 Another workaround is to convert the paths to polygons first and then draw the
1334 polygons instead.
1335
1336 \section1 Performance
1337
1338 QPainter is a rich framework that allows developers to do a great
1339 variety of graphical operations, such as gradients, composition
1340 modes and vector graphics. And QPainter can do this across a
1341 variety of different hardware and software stacks. Naturally the
1342 underlying combination of hardware and software has some
1343 implications for performance, and ensuring that every single
1344 operation is fast in combination with all the various combinations
1345 of composition modes, brushes, clipping, transformation, etc, is
1346 close to an impossible task because of the number of
1347 permutations. As a compromise we have selected a subset of the
1348 QPainter API and backends, where performance is guaranteed to be as
1349 good as we can sensibly get it for the given combination of
1350 hardware and software.
1351
1352 The backends we focus on as high-performance engines are:
1353
1354 \list
1355
1356 \li Raster - This backend implements all rendering in pure software
1357 and is always used to render into QImages. For optimal performance
1358 only use the format types QImage::Format_ARGB32_Premultiplied,
1359 QImage::Format_RGB32 or QImage::Format_RGB16. Any other format,
1360 including QImage::Format_ARGB32, has significantly worse
1361 performance. This engine is used by default for QWidget and QPixmap.
1362
1363 \li OpenGL 2.0 (ES) - This backend is the primary backend for
1364 hardware accelerated graphics. It can be run on desktop machines
1365 and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0
1366 specification. This includes most graphics chips produced in the
1367 last couple of years. The engine can be enabled by using QPainter
1368 onto a QOpenGLWidget.
1369
1370 \endlist
1371
1372 These operations are:
1373
1374 \list
1375
1376 \li Simple transformations, meaning translation and scaling, pluss
1377 0, 90, 180, 270 degree rotations.
1378
1379 \li \c drawPixmap() in combination with simple transformations and
1380 opacity with non-smooth transformation mode
1381 (\c QPainter::SmoothPixmapTransform not enabled as a render hint).
1382
1383 \li Rectangle fills with solid color, two-color linear gradients
1384 and simple transforms.
1385
1386 \li Rectangular clipping with simple transformations and intersect
1387 clip.
1388
1389 \li Composition Modes \c QPainter::CompositionMode_Source and
1390 QPainter::CompositionMode_SourceOver.
1391
1392 \li Rounded rectangle filling using solid color and two-color
1393 linear gradients fills.
1394
1395 \li 3x3 patched pixmaps, via qDrawBorderPixmap.
1396
1397 \endlist
1398
1399 This list gives an indication of which features to safely use in
1400 an application where performance is critical. For certain setups,
1401 other operations may be fast too, but before making extensive use
1402 of them, it is recommended to benchmark and verify them on the
1403 system where the software will run in the end. There are also
1404 cases where expensive operations are ok to use, for instance when
1405 the result is cached in a QPixmap.
1406
1407 \sa QPaintDevice, QPaintEngine, {Qt SVG}, {Basic Drawing Example}, {<qdrawutil.h>}{Drawing Utility Functions}
1408*/
1409
1410/*!
1411 \enum QPainter::RenderHint
1412
1413 Renderhints are used to specify flags to QPainter that may or
1414 may not be respected by any given engine.
1415
1416 \value Antialiasing Indicates that the engine should antialias
1417 edges of primitives if possible.
1418
1419 \value TextAntialiasing Indicates that the engine should antialias
1420 text if possible. To forcibly disable antialiasing for text, do not
1421 use this hint. Instead, set QFont::NoAntialias on your font's style
1422 strategy.
1423
1424 \value SmoothPixmapTransform Indicates that the engine should use
1425 a smooth pixmap transformation algorithm (such as bilinear) rather
1426 than nearest neighbor.
1427
1428 \value HighQualityAntialiasing This value is obsolete and will be ignored,
1429 use the Antialiasing render hint instead.
1430
1431 \value NonCosmeticDefaultPen This value is obsolete, the default for QPen
1432 is now non-cosmetic.
1433
1434 \value Qt4CompatiblePainting Compatibility hint telling the engine to use the
1435 same X11 based fill rules as in Qt 4, where aliased rendering is offset
1436 by slightly less than half a pixel. Also will treat default constructed pens
1437 as cosmetic. Potentially useful when porting a Qt 4 application to Qt 5.
1438
1439 \value LosslessImageRendering Use a lossless image rendering, whenever possible.
1440 Currently, this hint is only used when QPainter is employed to output a PDF
1441 file through QPrinter or QPdfWriter, where drawImage()/drawPixmap() calls
1442 will encode images using a lossless compression algorithm instead of lossy
1443 JPEG compression.
1444 This value was added in Qt 5.13.
1445
1446 \sa renderHints(), setRenderHint(), {QPainter#Rendering
1447 Quality}{Rendering Quality}, {Concentric Circles Example}
1448
1449*/
1450
1451/*!
1452 Constructs a painter.
1453
1454 \sa begin(), end()
1455*/
1456
1457QPainter::QPainter()
1458 : d_ptr(new QPainterPrivate(this))
1459{
1460}
1461
1462/*!
1463 \fn QPainter::QPainter(QPaintDevice *device)
1464
1465 Constructs a painter that begins painting the paint \a device
1466 immediately.
1467
1468 This constructor is convenient for short-lived painters, e.g. in a
1469 QWidget::paintEvent() and should be used only once. The
1470 constructor calls begin() for you and the QPainter destructor
1471 automatically calls end().
1472
1473 Here's an example using begin() and end():
1474 \snippet code/src_gui_painting_qpainter.cpp 1
1475
1476 The same example using this constructor:
1477 \snippet code/src_gui_painting_qpainter.cpp 2
1478
1479 Since the constructor cannot provide feedback when the initialization
1480 of the painter failed you should rather use begin() and end() to paint
1481 on external devices, e.g. printers.
1482
1483 \sa begin(), end()
1484*/
1485
1486QPainter::QPainter(QPaintDevice *pd)
1487 : d_ptr(nullptr)
1488{
1489 Q_ASSERT(pd != nullptr);
1490 if (!QPainterPrivate::attachPainterPrivate(this, pd)) {
1491 d_ptr.reset(new QPainterPrivate(this));
1492 begin(pd);
1493 }
1494 Q_ASSERT(d_ptr);
1495}
1496
1497/*!
1498 Destroys the painter.
1499*/
1500QPainter::~QPainter()
1501{
1502 d_ptr->inDestructor = true;
1503 QT_TRY {
1504 if (isActive())
1505 end();
1506 else if (d_ptr->refcount > 1)
1507 d_ptr->detachPainterPrivate(this);
1508 } QT_CATCH(...) {
1509 // don't throw anything in the destructor.
1510 }
1511 if (d_ptr) {
1512 // Make sure we haven't messed things up.
1513 Q_ASSERT(d_ptr->inDestructor);
1514 d_ptr->inDestructor = false;
1515 Q_ASSERT(d_ptr->refcount == 1);
1516 if (d_ptr->d_ptrs)
1517 free(d_ptr->d_ptrs);
1518 }
1519}
1520
1521/*!
1522 Returns the paint device on which this painter is currently
1523 painting, or \nullptr if the painter is not active.
1524
1525 \sa isActive()
1526*/
1527
1528QPaintDevice *QPainter::device() const
1529{
1530 Q_D(const QPainter);
1531 if (isActive() && d->engine->d_func()->currentClipDevice)
1532 return d->engine->d_func()->currentClipDevice;
1533 return d->original_device;
1534}
1535
1536/*!
1537 Returns \c true if begin() has been called and end() has not yet been
1538 called; otherwise returns \c false.
1539
1540 \sa begin(), QPaintDevice::paintingActive()
1541*/
1542
1543bool QPainter::isActive() const
1544{
1545 Q_D(const QPainter);
1546 return d->engine;
1547}
1548
1549#if QT_DEPRECATED_SINCE(5, 13)
1550/*!
1551 Initializes the painters pen, background and font to the same as
1552 the given \a device.
1553
1554 \obsolete
1555
1556 \sa begin(), {QPainter#Settings}{Settings}
1557*/
1558void QPainter::initFrom(const QPaintDevice *device)
1559{
1560 Q_ASSERT_X(device, "QPainter::initFrom(const QPaintDevice *device)", "QPaintDevice cannot be 0");
1561 Q_D(QPainter);
1562 d->initFrom(device);
1563}
1564#endif
1565
1566void QPainterPrivate::initFrom(const QPaintDevice *device)
1567{
1568 if (!engine) {
1569 qWarning("QPainter::initFrom: Painter not active, aborted");
1570 return;
1571 }
1572
1573 Q_Q(QPainter);
1574 device->initPainter(q);
1575
1576 if (extended) {
1577 extended->penChanged();
1578 } else if (engine) {
1579 engine->setDirty(QPaintEngine::DirtyPen);
1580 engine->setDirty(QPaintEngine::DirtyBrush);
1581 engine->setDirty(QPaintEngine::DirtyFont);
1582 }
1583}
1584
1585/*!
1586 Saves the current painter state (pushes the state onto a stack). A
1587 save() must be followed by a corresponding restore(); the end()
1588 function unwinds the stack.
1589
1590 \sa restore()
1591*/
1592
1593void QPainter::save()
1594{
1595#ifdef QT_DEBUG_DRAW
1596 if (qt_show_painter_debug_output)
1597 printf("QPainter::save()\n");
1598#endif
1599 Q_D(QPainter);
1600 if (!d->engine) {
1601 qWarning("QPainter::save: Painter not active");
1602 return;
1603 }
1604
1605 if (d->extended) {
1606 d->state = d->extended->createState(d->states.back());
1607 d->extended->setState(d->state);
1608 } else {
1609 d->updateState(d->state);
1610 d->state = new QPainterState(d->states.back());
1611 d->engine->state = d->state;
1612 }
1613 d->states.push_back(d->state);
1614}
1615
1616/*!
1617 Restores the current painter state (pops a saved state off the
1618 stack).
1619
1620 \sa save()
1621*/
1622
1623void QPainter::restore()
1624{
1625#ifdef QT_DEBUG_DRAW
1626 if (qt_show_painter_debug_output)
1627 printf("QPainter::restore()\n");
1628#endif
1629 Q_D(QPainter);
1630 if (d->states.size()<=1) {
1631 qWarning("QPainter::restore: Unbalanced save/restore");
1632 return;
1633 } else if (!d->engine) {
1634 qWarning("QPainter::restore: Painter not active");
1635 return;
1636 }
1637
1638 QPainterState *tmp = d->state;
1639 d->states.pop_back();
1640 d->state = d->states.back();
1641 d->txinv = false;
1642
1643 if (d->extended) {
1644 d->checkEmulation();
1645 d->extended->setState(d->state);
1646 delete tmp;
1647 return;
1648 }
1649
1650 // trigger clip update if the clip path/region has changed since
1651 // last save
1652 if (!d->state->clipInfo.isEmpty()
1653 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1654 // reuse the tmp state to avoid any extra allocs...
1655 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1656 tmp->clipOperation = Qt::NoClip;
1657 tmp->clipPath = QPainterPath();
1658 d->engine->updateState(*tmp);
1659 // replay the list of clip states,
1660 for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
1661 tmp->matrix = info.matrix;
1662 tmp->matrix *= d->state->redirectionMatrix;
1663 tmp->clipOperation = info.operation;
1664 if (info.clipType == QPainterClipInfo::RectClip) {
1665 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1666 tmp->clipRegion = info.rect;
1667 } else if (info.clipType == QPainterClipInfo::RegionClip) {
1668 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1669 tmp->clipRegion = info.region;
1670 } else { // clipType == QPainterClipInfo::PathClip
1671 tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
1672 tmp->clipPath = info.path;
1673 }
1674 d->engine->updateState(*tmp);
1675 }
1676
1677
1678 //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
1679 d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1680 tmp->changeFlags &= ~uint(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1681 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1682 }
1683
1684 d->updateState(d->state);
1685 delete tmp;
1686}
1687
1688
1689/*!
1690
1691 \fn bool QPainter::begin(QPaintDevice *device)
1692
1693 Begins painting the paint \a device and returns \c true if
1694 successful; otherwise returns \c false.
1695
1696 Notice that all painter settings (setPen(), setBrush() etc.) are reset
1697 to default values when begin() is called.
1698
1699 The errors that can occur are serious problems, such as these:
1700
1701 \snippet code/src_gui_painting_qpainter.cpp 3
1702
1703 Note that most of the time, you can use one of the constructors
1704 instead of begin(), and that end() is automatically done at
1705 destruction.
1706
1707 \warning A paint device can only be painted by one painter at a
1708 time.
1709
1710 \warning Painting on a QImage with the format
1711 QImage::Format_Indexed8 is not supported.
1712
1713 \sa end(), QPainter()
1714*/
1715
1716static inline void qt_cleanup_painter_state(QPainterPrivate *d)
1717{
1718 qDeleteAll(d->states);
1719 d->states.clear();
1720 d->state = nullptr;
1721 d->engine = nullptr;
1722 d->device = nullptr;
1723}
1724
1725bool QPainter::begin(QPaintDevice *pd)
1726{
1727 Q_ASSERT(pd);
1728
1729 if (pd->painters > 0) {
1730 qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
1731 return false;
1732 }
1733
1734 if (d_ptr->engine) {
1735 qWarning("QPainter::begin: Painter already active");
1736 return false;
1737 }
1738
1739 if (QPainterPrivate::attachPainterPrivate(this, pd))
1740 return true;
1741
1742 Q_D(QPainter);
1743
1744 d->helper_device = pd;
1745 d->original_device = pd;
1746
1747 QPoint redirectionOffset;
1748 QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1749 if (rpd)
1750 pd = rpd;
1751
1752#ifdef QT_DEBUG_DRAW
1753 if (qt_show_painter_debug_output)
1754 printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1755#endif
1756
1757 if (pd->devType() == QInternal::Pixmap)
1758 static_cast<QPixmap *>(pd)->detach();
1759 else if (pd->devType() == QInternal::Image)
1760 static_cast<QImage *>(pd)->detach();
1761
1762 d->engine = pd->paintEngine();
1763
1764 if (!d->engine) {
1765 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1766 return false;
1767 }
1768
1769 d->device = pd;
1770
1771 d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine) : nullptr;
1772 if (d->emulationEngine)
1773 d->emulationEngine->real_engine = d->extended;
1774
1775 // Setup new state...
1776 Q_ASSERT(!d->state);
1777 d->state = d->extended ? d->extended->createState(nullptr) : new QPainterState;
1778 d->state->painter = this;
1779 d->states.push_back(d->state);
1780
1781 d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1782 d->state->brushOrigin = QPointF();
1783
1784 // Slip a painter state into the engine before we do any other operations
1785 if (d->extended)
1786 d->extended->setState(d->state);
1787 else
1788 d->engine->state = d->state;
1789
1790 switch (pd->devType()) {
1791 case QInternal::Pixmap:
1792 {
1793 QPixmap *pm = static_cast<QPixmap *>(pd);
1794 Q_ASSERT(pm);
1795 if (pm->isNull()) {
1796 qWarning("QPainter::begin: Cannot paint on a null pixmap");
1797 qt_cleanup_painter_state(d);
1798 return false;
1799 }
1800
1801 if (pm->depth() == 1) {
1802 d->state->pen = QPen(Qt::color1);
1803 d->state->brush = QBrush(Qt::color0);
1804 }
1805 break;
1806 }
1807 case QInternal::Image:
1808 {
1809 QImage *img = static_cast<QImage *>(pd);
1810 Q_ASSERT(img);
1811 if (img->isNull()) {
1812 qWarning("QPainter::begin: Cannot paint on a null image");
1813 qt_cleanup_painter_state(d);
1814 return false;
1815 } else if (img->format() == QImage::Format_Indexed8) {
1816 // Painting on indexed8 images is not supported.
1817 qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format");
1818 qt_cleanup_painter_state(d);
1819 return false;
1820 }
1821 if (img->depth() == 1) {
1822 d->state->pen = QPen(Qt::color1);
1823 d->state->brush = QBrush(Qt::color0);
1824 }
1825 break;
1826 }
1827 default:
1828 break;
1829 }
1830 if (d->state->ww == 0) // For compat with 3.x painter defaults
1831 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1832
1833 d->engine->setPaintDevice(pd);
1834
1835 bool begun = d->engine->begin(pd);
1836 if (!begun) {
1837 qWarning("QPainter::begin(): Returned false");
1838 if (d->engine->isActive()) {
1839 end();
1840 } else {
1841 qt_cleanup_painter_state(d);
1842 }
1843 return false;
1844 } else {
1845 d->engine->setActive(begun);
1846 }
1847
1848 // Copy painter properties from original paint device,
1849 // required for QPixmap::grabWidget()
1850 if (d->original_device->devType() == QInternal::Widget) {
1851 d->initFrom(d->original_device);
1852 } else {
1853 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1854 // make sure we have a font compatible with the paintdevice
1855 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1856 }
1857
1858 QRect systemRect = d->engine->systemRect();
1859 if (!systemRect.isEmpty()) {
1860 d->state->ww = d->state->vw = systemRect.width();
1861 d->state->wh = d->state->vh = systemRect.height();
1862 } else {
1863 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1864 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1865 }
1866
1867 const QPoint coordinateOffset = d->engine->coordinateOffset();
1868 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1869
1870 Q_ASSERT(d->engine->isActive());
1871
1872 if (!d->state->redirectionMatrix.isIdentity() || d->effectiveDevicePixelRatio() > 1)
1873 d->updateMatrix();
1874
1875 Q_ASSERT(d->engine->isActive());
1876 d->state->renderHints = QPainter::TextAntialiasing;
1877 ++d->device->painters;
1878
1879 d->state->emulationSpecifier = 0;
1880
1881 return true;
1882}
1883
1884/*!
1885 Ends painting. Any resources used while painting are released. You
1886 don't normally need to call this since it is called by the
1887 destructor.
1888
1889 Returns \c true if the painter is no longer active; otherwise returns \c false.
1890
1891 \sa begin(), isActive()
1892*/
1893
1894bool QPainter::end()
1895{
1896#ifdef QT_DEBUG_DRAW
1897 if (qt_show_painter_debug_output)
1898 printf("QPainter::end()\n");
1899#endif
1900 Q_D(QPainter);
1901
1902 if (!d->engine) {
1903 qWarning("QPainter::end: Painter not active, aborted");
1904 qt_cleanup_painter_state(d);
1905 return false;
1906 }
1907
1908 if (d->refcount > 1) {
1909 d->detachPainterPrivate(this);
1910 return true;
1911 }
1912
1913 bool ended = true;
1914
1915 if (d->engine->isActive()) {
1916 ended = d->engine->end();
1917 d->updateState(nullptr);
1918
1919 --d->device->painters;
1920 if (d->device->painters == 0) {
1921 d->engine->setPaintDevice(nullptr);
1922 d->engine->setActive(false);
1923 }
1924 }
1925
1926 if (d->states.size() > 1) {
1927 qWarning("QPainter::end: Painter ended with %d saved states",
1928 d->states.size());
1929 }
1930
1931 if (d->engine->autoDestruct()) {
1932 delete d->engine;
1933 }
1934
1935 if (d->emulationEngine) {
1936 delete d->emulationEngine;
1937 d->emulationEngine = nullptr;
1938 }
1939
1940 if (d->extended) {
1941 d->extended = nullptr;
1942 }
1943
1944 qt_cleanup_painter_state(d);
1945
1946 return ended;
1947}
1948
1949
1950/*!
1951 Returns the paint engine that the painter is currently operating
1952 on if the painter is active; otherwise 0.
1953
1954 \sa isActive()
1955*/
1956QPaintEngine *QPainter::paintEngine() const
1957{
1958 Q_D(const QPainter);
1959 return d->engine;
1960}
1961
1962/*!
1963 \since 4.6
1964
1965 Flushes the painting pipeline and prepares for the user issuing commands
1966 directly to the underlying graphics context. Must be followed by a call to
1967 endNativePainting().
1968
1969 Note that only the states the underlying paint engine changes will be reset
1970 to their respective default states. The states we reset may change from
1971 release to release. The following states are currently reset in the OpenGL
1972 2 engine:
1973
1974 \list
1975 \li blending is disabled
1976 \li the depth, stencil and scissor tests are disabled
1977 \li the active texture unit is reset to 0
1978 \li the depth mask, depth function and the clear depth are reset to their
1979 default values
1980 \li the stencil mask, stencil operation and stencil function are reset to
1981 their default values
1982 \li the current color is reset to solid white
1983 \endlist
1984
1985 If, for example, the OpenGL polygon mode is changed by the user inside a
1986 beginNativePaint()/endNativePainting() block, it will not be reset to the
1987 default state by endNativePainting(). Here is an example that shows
1988 intermixing of painter commands and raw OpenGL commands:
1989
1990 \snippet code/src_gui_painting_qpainter.cpp 21
1991
1992 \sa endNativePainting()
1993*/
1994void QPainter::beginNativePainting()
1995{
1996 Q_D(QPainter);
1997 if (!d->engine) {
1998 qWarning("QPainter::beginNativePainting: Painter not active");
1999 return;
2000 }
2001
2002 if (d->extended)
2003 d->extended->beginNativePainting();
2004}
2005
2006/*!
2007 \since 4.6
2008
2009 Restores the painter after manually issuing native painting commands. Lets
2010 the painter restore any native state that it relies on before calling any
2011 other painter commands.
2012
2013 \sa beginNativePainting()
2014*/
2015void QPainter::endNativePainting()
2016{
2017 Q_D(const QPainter);
2018 if (!d->engine) {
2019 qWarning("QPainter::beginNativePainting: Painter not active");
2020 return;
2021 }
2022
2023 if (d->extended)
2024 d->extended->endNativePainting();
2025 else
2026 d->engine->syncState();
2027}
2028
2029/*!
2030 Returns the font metrics for the painter if the painter is
2031 active. Otherwise, the return value is undefined.
2032
2033 \sa font(), isActive(), {QPainter#Settings}{Settings}
2034*/
2035
2036QFontMetrics QPainter::fontMetrics() const
2037{
2038 Q_D(const QPainter);
2039 if (!d->engine) {
2040 qWarning("QPainter::fontMetrics: Painter not active");
2041 return QFontMetrics(QFont());
2042 }
2043 return QFontMetrics(d->state->font);
2044}
2045
2046
2047/*!
2048 Returns the font info for the painter if the painter is
2049 active. Otherwise, the return value is undefined.
2050
2051 \sa font(), isActive(), {QPainter#Settings}{Settings}
2052*/
2053
2054QFontInfo QPainter::fontInfo() const
2055{
2056 Q_D(const QPainter);
2057 if (!d->engine) {
2058 qWarning("QPainter::fontInfo: Painter not active");
2059 return QFontInfo(QFont());
2060 }
2061 return QFontInfo(d->state->font);
2062}
2063
2064/*!
2065 \since 4.2
2066
2067 Returns the opacity of the painter. The default value is
2068 1.
2069*/
2070
2071qreal QPainter::opacity() const
2072{
2073 Q_D(const QPainter);
2074 if (!d->engine) {
2075 qWarning("QPainter::opacity: Painter not active");
2076 return 1.0;
2077 }
2078 return d->state->opacity;
2079}
2080
2081/*!
2082 \since 4.2
2083
2084 Sets the opacity of the painter to \a opacity. The value should
2085 be in the range 0.0 to 1.0, where 0.0 is fully transparent and
2086 1.0 is fully opaque.
2087
2088 Opacity set on the painter will apply to all drawing operations
2089 individually.
2090*/
2091
2092void QPainter::setOpacity(qreal opacity)
2093{
2094 Q_D(QPainter);
2095
2096 if (!d->engine) {
2097 qWarning("QPainter::setOpacity: Painter not active");
2098 return;
2099 }
2100
2101 opacity = qMin(qreal(1), qMax(qreal(0), opacity));
2102
2103 if (opacity == d->state->opacity)
2104 return;
2105
2106 d->state->opacity = opacity;
2107
2108 if (d->extended)
2109 d->extended->opacityChanged();
2110 else
2111 d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
2112}
2113
2114
2115/*!
2116 Returns the currently set brush origin.
2117
2118 \sa setBrushOrigin(), {QPainter#Settings}{Settings}
2119*/
2120
2121QPoint QPainter::brushOrigin() const
2122{
2123 Q_D(const QPainter);
2124 if (!d->engine) {
2125 qWarning("QPainter::brushOrigin: Painter not active");
2126 return QPoint();
2127 }
2128 return QPointF(d->state->brushOrigin).toPoint();
2129}
2130
2131/*!
2132 \fn void QPainter::setBrushOrigin(const QPointF &position)
2133
2134 Sets the brush origin to \a position.
2135
2136 The brush origin specifies the (0, 0) coordinate of the painter's
2137 brush.
2138
2139 Note that while the brushOrigin() was necessary to adopt the
2140 parent's background for a widget in Qt 3, this is no longer the
2141 case since the Qt 4 painter doesn't paint the background unless
2142 you explicitly tell it to do so by setting the widget's \l
2143 {QWidget::autoFillBackground}{autoFillBackground} property to
2144 true.
2145
2146 \sa brushOrigin(), {QPainter#Settings}{Settings}
2147*/
2148
2149void QPainter::setBrushOrigin(const QPointF &p)
2150{
2151 Q_D(QPainter);
2152#ifdef QT_DEBUG_DRAW
2153 if (qt_show_painter_debug_output)
2154 printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
2155#endif
2156
2157 if (!d->engine) {
2158 qWarning("QPainter::setBrushOrigin: Painter not active");
2159 return;
2160 }
2161
2162 d->state->brushOrigin = p;
2163
2164 if (d->extended) {
2165 d->extended->brushOriginChanged();
2166 return;
2167 }
2168
2169 d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
2170}
2171
2172/*!
2173 \fn void QPainter::setBrushOrigin(const QPoint &position)
2174 \overload
2175
2176 Sets the brush's origin to the given \a position.
2177*/
2178
2179/*!
2180 \fn void QPainter::setBrushOrigin(int x, int y)
2181
2182 \overload
2183
2184 Sets the brush's origin to point (\a x, \a y).
2185*/
2186
2187/*!
2188 \enum QPainter::CompositionMode
2189
2190 Defines the modes supported for digital image compositing.
2191 Composition modes are used to specify how the pixels in one image,
2192 the source, are merged with the pixel in another image, the
2193 destination.
2194
2195 Please note that the bitwise raster operation modes, denoted with
2196 a RasterOp prefix, are only natively supported in the X11 and
2197 raster paint engines. This means that the only way to utilize
2198 these modes on the Mac is via a QImage. The RasterOp denoted blend
2199 modes are \e not supported for pens and brushes with alpha
2200 components. Also, turning on the QPainter::Antialiasing render
2201 hint will effectively disable the RasterOp modes.
2202
2203
2204 \image qpainter-compositionmode1.png
2205 \image qpainter-compositionmode2.png
2206
2207 The most common type is SourceOver (often referred to as just
2208 alpha blending) where the source pixel is blended on top of the
2209 destination pixel in such a way that the alpha component of the
2210 source defines the translucency of the pixel.
2211
2212 Several composition modes require an alpha channel in the source or
2213 target images to have an effect. For optimal performance the
2214 image format \l {QImage::Format}{Format_ARGB32_Premultiplied} is
2215 preferred.
2216
2217 When a composition mode is set it applies to all painting
2218 operator, pens, brushes, gradients and pixmap/image drawing.
2219
2220 \value CompositionMode_SourceOver This is the default mode. The
2221 alpha of the source is used to blend the pixel on top of the
2222 destination.
2223
2224 \value CompositionMode_DestinationOver The alpha of the
2225 destination is used to blend it on top of the source pixels. This
2226 mode is the inverse of CompositionMode_SourceOver.
2227
2228 \value CompositionMode_Clear The pixels in the destination are
2229 cleared (set to fully transparent) independent of the source.
2230
2231 \value CompositionMode_Source The output is the source
2232 pixel. (This means a basic copy operation and is identical to
2233 SourceOver when the source pixel is opaque).
2234
2235 \value CompositionMode_Destination The output is the destination
2236 pixel. This means that the blending has no effect. This mode is
2237 the inverse of CompositionMode_Source.
2238
2239 \value CompositionMode_SourceIn The output is the source, where
2240 the alpha is reduced by that of the destination.
2241
2242 \value CompositionMode_DestinationIn The output is the
2243 destination, where the alpha is reduced by that of the
2244 source. This mode is the inverse of CompositionMode_SourceIn.
2245
2246 \value CompositionMode_SourceOut The output is the source, where
2247 the alpha is reduced by the inverse of destination.
2248
2249 \value CompositionMode_DestinationOut The output is the
2250 destination, where the alpha is reduced by the inverse of the
2251 source. This mode is the inverse of CompositionMode_SourceOut.
2252
2253 \value CompositionMode_SourceAtop The source pixel is blended on
2254 top of the destination, with the alpha of the source pixel reduced
2255 by the alpha of the destination pixel.
2256
2257 \value CompositionMode_DestinationAtop The destination pixel is
2258 blended on top of the source, with the alpha of the destination
2259 pixel is reduced by the alpha of the destination pixel. This mode
2260 is the inverse of CompositionMode_SourceAtop.
2261
2262 \value CompositionMode_Xor The source, whose alpha is reduced with
2263 the inverse of the destination alpha, is merged with the
2264 destination, whose alpha is reduced by the inverse of the source
2265 alpha. CompositionMode_Xor is not the same as the bitwise Xor.
2266
2267 \value CompositionMode_Plus Both the alpha and color of the source
2268 and destination pixels are added together.
2269
2270 \value CompositionMode_Multiply The output is the source color
2271 multiplied by the destination. Multiplying a color with white
2272 leaves the color unchanged, while multiplying a color
2273 with black produces black.
2274
2275 \value CompositionMode_Screen The source and destination colors
2276 are inverted and then multiplied. Screening a color with white
2277 produces white, whereas screening a color with black leaves the
2278 color unchanged.
2279
2280 \value CompositionMode_Overlay Multiplies or screens the colors
2281 depending on the destination color. The destination color is mixed
2282 with the source color to reflect the lightness or darkness of the
2283 destination.
2284
2285 \value CompositionMode_Darken The darker of the source and
2286 destination colors is selected.
2287
2288 \value CompositionMode_Lighten The lighter of the source and
2289 destination colors is selected.
2290
2291 \value CompositionMode_ColorDodge The destination color is
2292 brightened to reflect the source color. A black source color
2293 leaves the destination color unchanged.
2294
2295 \value CompositionMode_ColorBurn The destination color is darkened
2296 to reflect the source color. A white source color leaves the
2297 destination color unchanged.
2298
2299 \value CompositionMode_HardLight Multiplies or screens the colors
2300 depending on the source color. A light source color will lighten
2301 the destination color, whereas a dark source color will darken the
2302 destination color.
2303
2304 \value CompositionMode_SoftLight Darkens or lightens the colors
2305 depending on the source color. Similar to
2306 CompositionMode_HardLight.
2307
2308 \value CompositionMode_Difference Subtracts the darker of the
2309 colors from the lighter. Painting with white inverts the
2310 destination color, whereas painting with black leaves the
2311 destination color unchanged.
2312
2313 \value CompositionMode_Exclusion Similar to
2314 CompositionMode_Difference, but with a lower contrast. Painting
2315 with white inverts the destination color, whereas painting with
2316 black leaves the destination color unchanged.
2317
2318 \value RasterOp_SourceOrDestination Does a bitwise OR operation on
2319 the source and destination pixels (src OR dst).
2320
2321 \value RasterOp_SourceAndDestination Does a bitwise AND operation
2322 on the source and destination pixels (src AND dst).
2323
2324 \value RasterOp_SourceXorDestination Does a bitwise XOR operation
2325 on the source and destination pixels (src XOR dst).
2326
2327 \value RasterOp_NotSourceAndNotDestination Does a bitwise NOR
2328 operation on the source and destination pixels ((NOT src) AND (NOT
2329 dst)).
2330
2331 \value RasterOp_NotSourceOrNotDestination Does a bitwise NAND
2332 operation on the source and destination pixels ((NOT src) OR (NOT
2333 dst)).
2334
2335 \value RasterOp_NotSourceXorDestination Does a bitwise operation
2336 where the source pixels are inverted and then XOR'ed with the
2337 destination ((NOT src) XOR dst).
2338
2339 \value RasterOp_NotSource Does a bitwise operation where the
2340 source pixels are inverted (NOT src).
2341
2342 \value RasterOp_NotSourceAndDestination Does a bitwise operation
2343 where the source is inverted and then AND'ed with the destination
2344 ((NOT src) AND dst).
2345
2346 \value RasterOp_SourceAndNotDestination Does a bitwise operation
2347 where the source is AND'ed with the inverted destination pixels
2348 (src AND (NOT dst)).
2349
2350 \value RasterOp_NotSourceOrDestination Does a bitwise operation
2351 where the source is inverted and then OR'ed with the destination
2352 ((NOT src) OR dst).
2353
2354 \value RasterOp_ClearDestination The pixels in the destination are
2355 cleared (set to 0) independent of the source.
2356
2357 \value RasterOp_SetDestination The pixels in the destination are
2358 set (set to 1) independent of the source.
2359
2360 \value RasterOp_NotDestination Does a bitwise operation
2361 where the destination pixels are inverted (NOT dst).
2362
2363 \value RasterOp_SourceOrNotDestination Does a bitwise operation
2364 where the source is OR'ed with the inverted destination pixels
2365 (src OR (NOT dst)).
2366
2367 \sa compositionMode(), setCompositionMode(), {QPainter#Composition
2368 Modes}{Composition Modes}, {Image Composition Example}
2369*/
2370
2371/*!
2372 Sets the composition mode to the given \a mode.
2373
2374 \warning Only a QPainter operating on a QImage fully supports all
2375 composition modes. The RasterOp modes are supported for X11 as
2376 described in compositionMode().
2377
2378 \sa compositionMode()
2379*/
2380void QPainter::setCompositionMode(CompositionMode mode)
2381{
2382 Q_D(QPainter);
2383 if (!d->engine) {
2384 qWarning("QPainter::setCompositionMode: Painter not active");
2385 return;
2386 }
2387 if (d->state->composition_mode == mode)
2388 return;
2389 if (d->extended) {
2390 d->state->composition_mode = mode;
2391 d->extended->compositionModeChanged();
2392 return;
2393 }
2394
2395 if (mode >= QPainter::RasterOp_SourceOrDestination) {
2396 if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
2397 qWarning("QPainter::setCompositionMode: "
2398 "Raster operation modes not supported on device");
2399 return;
2400 }
2401 } else if (mode >= QPainter::CompositionMode_Plus) {
2402 if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
2403 qWarning("QPainter::setCompositionMode: "
2404 "Blend modes not supported on device");
2405 return;
2406 }
2407 } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
2408 if (mode != CompositionMode_Source && mode != CompositionMode_SourceOver) {
2409 qWarning("QPainter::setCompositionMode: "
2410 "PorterDuff modes not supported on device");
2411 return;
2412 }
2413 }
2414
2415 d->state->composition_mode = mode;
2416 d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
2417}
2418
2419/*!
2420 Returns the current composition mode.
2421
2422 \sa CompositionMode, setCompositionMode()
2423*/
2424QPainter::CompositionMode QPainter::compositionMode() const
2425{
2426 Q_D(const QPainter);
2427 if (!d->engine) {
2428 qWarning("QPainter::compositionMode: Painter not active");
2429 return QPainter::CompositionMode_SourceOver;
2430 }
2431 return d->state->composition_mode;
2432}
2433
2434/*!
2435 Returns the current background brush.
2436
2437 \sa setBackground(), {QPainter#Settings}{Settings}
2438*/
2439
2440const QBrush &QPainter::background() const
2441{
2442 Q_D(const QPainter);
2443 if (!d->engine) {
2444 qWarning("QPainter::background: Painter not active");
2445 return d->fakeState()->brush;
2446 }
2447 return d->state->bgBrush;
2448}
2449
2450
2451/*!
2452 Returns \c true if clipping has been set; otherwise returns \c false.
2453
2454 \sa setClipping(), {QPainter#Clipping}{Clipping}
2455*/
2456
2457bool QPainter::hasClipping() const
2458{
2459 Q_D(const QPainter);
2460 if (!d->engine) {
2461 qWarning("QPainter::hasClipping: Painter not active");
2462 return false;
2463 }
2464 return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
2465}
2466
2467
2468/*!
2469 Enables clipping if \a enable is true, or disables clipping if \a
2470 enable is false.
2471
2472 \sa hasClipping(), {QPainter#Clipping}{Clipping}
2473*/
2474
2475void QPainter::setClipping(bool enable)
2476{
2477 Q_D(QPainter);
2478#ifdef QT_DEBUG_DRAW
2479 if (qt_show_painter_debug_output)
2480 printf("QPainter::setClipping(), enable=%s, was=%s\n",
2481 enable ? "on" : "off",
2482 hasClipping() ? "on" : "off");
2483#endif
2484 if (!d->engine) {
2485 qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
2486 return;
2487 }
2488
2489 if (hasClipping() == enable)
2490 return;
2491
2492 // we can't enable clipping if we don't have a clip
2493 if (enable
2494 && (d->state->clipInfo.isEmpty() || d->state->clipInfo.constLast().operation == Qt::NoClip))
2495 return;
2496 d->state->clipEnabled = enable;
2497
2498 if (d->extended) {
2499 d->extended->clipEnabledChanged();
2500 return;
2501 }
2502
2503 d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
2504 d->updateState(d->state);
2505}
2506
2507
2508/*!
2509 Returns the currently set clip region. Note that the clip region
2510 is given in logical coordinates.
2511
2512 \warning QPainter does not store the combined clip explicitly as
2513 this is handled by the underlying QPaintEngine, so the path is
2514 recreated on demand and transformed to the current logical
2515 coordinate system. This is potentially an expensive operation.
2516
2517 \sa setClipRegion(), clipPath(), setClipping()
2518*/
2519
2520QRegion QPainter::clipRegion() const
2521{
2522 Q_D(const QPainter);
2523 if (!d->engine) {
2524 qWarning("QPainter::clipRegion: Painter not active");
2525 return QRegion();
2526 }
2527
2528 QRegion region;
2529 bool lastWasNothing = true;
2530
2531 if (!d->txinv)
2532 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2533
2534 // ### Falcon: Use QPainterPath
2535 for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
2536 switch (info.clipType) {
2537
2538 case QPainterClipInfo::RegionClip: {
2539 QTransform matrix = (info.matrix * d->invMatrix);
2540 if (lastWasNothing) {
2541 region = info.region * matrix;
2542 lastWasNothing = false;
2543 continue;
2544 }
2545 if (info.operation == Qt::IntersectClip)
2546 region &= info.region * matrix;
2547 else if (info.operation == Qt::NoClip) {
2548 lastWasNothing = true;
2549 region = QRegion();
2550 } else
2551 region = info.region * matrix;
2552 break;
2553 }
2554
2555 case QPainterClipInfo::PathClip: {
2556 QTransform matrix = (info.matrix * d->invMatrix);
2557 if (lastWasNothing) {
2558 region = QRegion((info.path * matrix).toFillPolygon(QTransform()).toPolygon(),
2559 info.path.fillRule());
2560 lastWasNothing = false;
2561 continue;
2562 }
2563 if (info.operation == Qt::IntersectClip) {
2564 region &= QRegion((info.path * matrix).toFillPolygon(QTransform()).toPolygon(),
2565 info.path.fillRule());
2566 } else if (info.operation == Qt::NoClip) {
2567 lastWasNothing = true;
2568 region = QRegion();
2569 } else {
2570 region = QRegion((info.path * matrix).toFillPolygon(QTransform()).toPolygon(),
2571 info.path.fillRule());
2572 }
2573 break;
2574 }
2575
2576 case QPainterClipInfo::RectClip: {
2577 QTransform matrix = (info.matrix * d->invMatrix);
2578 if (lastWasNothing) {
2579 region = QRegion(info.rect) * matrix;
2580 lastWasNothing = false;
2581 continue;
2582 }
2583 if (info.operation == Qt::IntersectClip) {
2584 // Use rect intersection if possible.
2585 if (matrix.type() <= QTransform::TxScale)
2586 region &= matrix.mapRect(info.rect);
2587 else
2588 region &= matrix.map(QRegion(info.rect));
2589 } else if (info.operation == Qt::NoClip) {
2590 lastWasNothing = true;
2591 region = QRegion();
2592 } else {
2593 region = QRegion(info.rect) * matrix;
2594 }
2595 break;
2596 }
2597
2598 case QPainterClipInfo::RectFClip: {
2599 QTransform matrix = (info.matrix * d->invMatrix);
2600 if (lastWasNothing) {
2601 region = QRegion(info.rectf.toRect()) * matrix;
2602 lastWasNothing = false;
2603 continue;
2604 }
2605 if (info.operation == Qt::IntersectClip) {
2606 // Use rect intersection if possible.
2607 if (matrix.type() <= QTransform::TxScale)
2608 region &= matrix.mapRect(info.rectf.toRect());
2609 else
2610 region &= matrix.map(QRegion(info.rectf.toRect()));
2611 } else if (info.operation == Qt::NoClip) {
2612 lastWasNothing = true;
2613 region = QRegion();
2614 } else {
2615 region = QRegion(info.rectf.toRect()) * matrix;
2616 }
2617 break;
2618 }
2619 }
2620 }
2621
2622 return region;
2623}
2624
2625extern QPainterPath qt_regionToPath(const QRegion &region);
2626
2627/*!
2628 Returns the current clip path in logical coordinates.
2629
2630 \warning QPainter does not store the combined clip explicitly as
2631 this is handled by the underlying QPaintEngine, so the path is
2632 recreated on demand and transformed to the current logical
2633 coordinate system. This is potentially an expensive operation.
2634
2635 \sa setClipPath(), clipRegion(), setClipping()
2636*/
2637QPainterPath QPainter::clipPath() const
2638{
2639 Q_D(const QPainter);
2640
2641 // ### Since we do not support path intersections and path unions yet,
2642 // we just use clipRegion() here...
2643 if (!d->engine) {
2644 qWarning("QPainter::clipPath: Painter not active");
2645 return QPainterPath();
2646 }
2647
2648 // No clip, return empty
2649 if (d->state->clipInfo.isEmpty()) {
2650 return QPainterPath();
2651 } else {
2652
2653 // Update inverse matrix, used below.
2654 if (!d->txinv)
2655 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2656
2657 // For the simple case avoid conversion.
2658 if (d->state->clipInfo.size() == 1
2659 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
2660 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2661 return d->state->clipInfo.at(0).path * matrix;
2662
2663 } else if (d->state->clipInfo.size() == 1
2664 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
2665 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2666 QPainterPath path;
2667 path.addRect(d->state->clipInfo.at(0).rect);
2668 return path * matrix;
2669 } else {
2670 // Fallback to clipRegion() for now, since we don't have isect/unite for paths
2671 return qt_regionToPath(clipRegion());
2672 }
2673 }
2674}
2675
2676/*!
2677 Returns the bounding rectangle of the current clip if there is a clip;
2678 otherwise returns an empty rectangle. Note that the clip region is
2679 given in logical coordinates.
2680
2681 The bounding rectangle is not guaranteed to be tight.
2682
2683 \sa setClipRect(), setClipPath(), setClipRegion()
2684
2685 \since 4.8
2686 */
2687
2688QRectF QPainter::clipBoundingRect() const
2689{
2690 Q_D(const QPainter);
2691
2692 if (!d->engine) {
2693 qWarning("QPainter::clipBoundingRect: Painter not active");
2694 return QRectF();
2695 }
2696
2697 // Accumulate the bounding box in device space. This is not 100%
2698 // precise, but it fits within the guarantee and it is reasonably
2699 // fast.
2700 QRectF bounds;
2701 bool first = true;
2702 for (const QPainterClipInfo &info : qAsConst(d->state->clipInfo)) {
2703 QRectF r;
2704
2705 if (info.clipType == QPainterClipInfo::RectClip)
2706 r = info.rect;
2707 else if (info.clipType == QPainterClipInfo::RectFClip)
2708 r = info.rectf;
2709 else if (info.clipType == QPainterClipInfo::RegionClip)
2710 r = info.region.boundingRect();
2711 else
2712 r = info.path.boundingRect();
2713
2714 r = info.matrix.mapRect(r);
2715
2716 if (first)
2717 bounds = r;
2718 else if (info.operation == Qt::IntersectClip)
2719 bounds &= r;
2720 first = false;
2721 }
2722
2723
2724 // Map the rectangle back into logical space using the inverse
2725 // matrix.
2726 if (!d->txinv)
2727 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2728
2729 return d->invMatrix.mapRect(bounds);
2730}
2731
2732/*!
2733 \fn void QPainter::setClipRect(const QRectF &rectangle, Qt::ClipOperation operation)
2734
2735 Enables clipping, and sets the clip region to the given \a
2736 rectangle using the given clip \a operation. The default operation
2737 is to replace the current clip rectangle.
2738
2739 Note that the clip rectangle is specified in logical (painter)
2740 coordinates.
2741
2742 \sa clipRegion(), setClipping(), {QPainter#Clipping}{Clipping}
2743*/
2744void QPainter::setClipRect(const QRectF &rect, Qt::ClipOperation op)
2745{
2746 Q_D(QPainter);
2747
2748 if (d->extended) {
2749 if (!d->engine) {
2750 qWarning("QPainter::setClipRect: Painter not active");
2751 return;
2752 }
2753 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2754 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2755 op = Qt::ReplaceClip;
2756
2757 qreal right = rect.x() + rect.width();
2758 qreal bottom = rect.y() + rect.height();
2759 qreal pts[] = { rect.x(), rect.y(),
2760 right, rect.y(),
2761 right, bottom,
2762 rect.x(), bottom };
2763 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
2764 d->state->clipEnabled = true;
2765 d->extended->clip(vp, op);
2766 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2767 d->state->clipInfo.clear();
2768 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2769 d->state->clipOperation = op;
2770 return;
2771 }
2772
2773 if (qreal(int(rect.top())) == rect.top()
2774 && qreal(int(rect.bottom())) == rect.bottom()
2775 && qreal(int(rect.left())) == rect.left()
2776 && qreal(int(rect.right())) == rect.right())
2777 {
2778 setClipRect(rect.toRect(), op);
2779 return;
2780 }
2781
2782 if (rect.isEmpty()) {
2783 setClipRegion(QRegion(), op);
2784 return;
2785 }
2786
2787 QPainterPath path;
2788 path.addRect(rect);
2789 setClipPath(path, op);
2790}
2791
2792/*!
2793 \fn void QPainter::setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
2794 \overload
2795
2796 Enables clipping, and sets the clip region to the given \a rectangle using the given
2797 clip \a operation.
2798*/
2799void QPainter::setClipRect(const QRect &rect, Qt::ClipOperation op)
2800{
2801 Q_D(QPainter);
2802
2803 if (!d->engine) {
2804 qWarning("QPainter::setClipRect: Painter not active");
2805 return;
2806 }
2807 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2808
2809 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2810 op = Qt::ReplaceClip;
2811
2812 if (d->extended) {
2813 d->state->clipEnabled = true;
2814 d->extended->clip(rect, op);
2815 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2816 d->state->clipInfo.clear();
2817 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2818 d->state->clipOperation = op;
2819 return;
2820 }
2821
2822 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2823 op = Qt::ReplaceClip;
2824
2825 d->state->clipRegion = rect;
2826 d->state->clipOperation = op;
2827 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2828 d->state->clipInfo.clear();
2829 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2830 d->state->clipEnabled = true;
2831 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2832 d->updateState(d->state);
2833}
2834
2835/*!
2836 \fn void QPainter::setClipRect(int x, int y, int width, int height, Qt::ClipOperation operation)
2837
2838 Enables clipping, and sets the clip region to the rectangle beginning at (\a x, \a y)
2839 with the given \a width and \a height.
2840*/
2841
2842/*!
2843 \fn void QPainter::setClipRegion(const QRegion &region, Qt::ClipOperation operation)
2844
2845 Sets the clip region to the given \a region using the specified clip
2846 \a operation. The default clip operation is to replace the current
2847 clip region.
2848
2849 Note that the clip region is given in logical coordinates.
2850
2851 \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
2852*/
2853void QPainter::setClipRegion(const QRegion &r, Qt::ClipOperation op)
2854{
2855 Q_D(QPainter);
2856#ifdef QT_DEBUG_DRAW
2857 QRect rect = r.boundingRect();
2858 if (qt_show_painter_debug_output)
2859 printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2860 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2861#endif
2862 if (!d->engine) {
2863 qWarning("QPainter::setClipRegion: Painter not active");
2864 return;
2865 }
2866 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2867
2868 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2869 op = Qt::ReplaceClip;
2870
2871 if (d->extended) {
2872 d->state->clipEnabled = true;
2873 d->extended->clip(r, op);
2874 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2875 d->state->clipInfo.clear();
2876 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2877 d->state->clipOperation = op;
2878 return;
2879 }
2880
2881 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2882 op = Qt::ReplaceClip;
2883
2884 d->state->clipRegion = r;
2885 d->state->clipOperation = op;
2886 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2887 d->state->clipInfo.clear();
2888 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2889 d->state->clipEnabled = true;
2890 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2891 d->updateState(d->state);
2892}
2893
2894#if QT_DEPRECATED_SINCE(5, 13)
2895/*!
2896 \since 4.2
2897 \obsolete
2898
2899 Sets the transformation matrix to \a matrix and enables transformations.
2900
2901 \note It is advisable to use setWorldTransform() instead of this function to
2902 preserve the properties of perspective transformations.
2903
2904 If \a combine is true, then \a matrix is combined with the current
2905 transformation matrix; otherwise \a matrix replaces the current
2906 transformation matrix.
2907
2908 If \a matrix is the identity matrix and \a combine is false, this
2909 function calls setWorldMatrixEnabled(false). (The identity matrix is the
2910 matrix where QMatrix::m11() and QMatrix::m22() are 1.0 and the
2911 rest are 0.0.)
2912
2913 The following functions can transform the coordinate system without using
2914 a QMatrix:
2915 \list
2916 \li translate()
2917 \li scale()
2918 \li shear()
2919 \li rotate()
2920 \endlist
2921
2922 They operate on the painter's worldMatrix() and are implemented like this:
2923
2924 \snippet code/src_gui_painting_qpainter.cpp 4
2925
2926 Note that when using setWorldMatrix() function you should always have
2927 \a combine be true when you are drawing into a QPicture. Otherwise
2928 it may not be possible to replay the picture with additional
2929 transformations; using the translate(), scale(), etc. convenience
2930 functions is safe.
2931
2932 For more information about the coordinate system, transformations
2933 and window-viewport conversion, see \l {Coordinate System}.
2934
2935 \sa setWorldTransform(), QTransform
2936*/
2937
2938void QPainter::setWorldMatrix(const QMatrix &matrix, bool combine)
2939{
2940 setWorldTransform(QTransform(matrix), combine);
2941}
2942
2943/*!
2944 \since 4.2
2945 \obsolete
2946
2947 Returns the world transformation matrix.
2948
2949 It is advisable to use worldTransform() because worldMatrix() does not
2950 preserve the properties of perspective transformations.
2951
2952 \sa {QPainter#Coordinate Transformations}{Coordinate Transformations},
2953 {Coordinate System}
2954*/
2955
2956const QMatrix &QPainter::worldMatrix() const
2957{
2958 Q_D(const QPainter);
2959 if (!d->engine) {
2960 qWarning("QPainter::worldMatrix: Painter not active");
2961 return d->fakeState()->transform.toAffine();
2962 }
2963 return d->state->worldMatrix.toAffine();
2964}
2965
2966/*!
2967 \obsolete
2968
2969 Use setWorldTransform() instead.
2970
2971 \sa setWorldTransform()
2972*/
2973
2974void QPainter::setMatrix(const QMatrix &matrix, bool combine)
2975{
2976 setWorldTransform(QTransform(matrix), combine);
2977}
2978
2979/*!
2980 \obsolete
2981
2982 Use worldTransform() instead.
2983
2984 \sa worldTransform()
2985*/
2986
2987const QMatrix &QPainter::matrix() const
2988{
2989QT_WARNING_PUSH
2990QT_WARNING_DISABLE_DEPRECATED
2991 return worldMatrix();
2992QT_WARNING_POP
2993}
2994
2995
2996/*!
2997 \since 4.2
2998 \obsolete
2999
3000 Returns the transformation matrix combining the current
3001 window/viewport and world transformation.
3002
3003 It is advisable to use combinedTransform() instead of this
3004 function to preserve the properties of perspective transformations.
3005
3006 \sa setWorldTransform(), setWindow(), setViewport()
3007*/
3008QMatrix QPainter::combinedMatrix() const
3009{
3010 return combinedTransform().toAffine();
3011}
3012
3013
3014/*!
3015 \obsolete
3016
3017 Returns the matrix that transforms from logical coordinates to
3018 device coordinates of the platform dependent paint device.
3019
3020 \note It is advisable to use deviceTransform() instead of this
3021 function to preserve the properties of perspective transformations.
3022
3023 This function is \e only needed when using platform painting
3024 commands on the platform dependent handle (Qt::HANDLE), and the
3025 platform does not do transformations nativly.
3026
3027 The QPaintEngine::PaintEngineFeature enum can be queried to
3028 determine whether the platform performs the transformations or
3029 not.
3030
3031 \sa worldMatrix(), QPaintEngine::hasFeature(),
3032*/
3033const QMatrix &QPainter::deviceMatrix() const
3034{
3035 Q_D(const QPainter);
3036 if (!d->engine) {
3037 qWarning("QPainter::deviceMatrix: Painter not active");
3038 return d->fakeState()->transform.toAffine();
3039 }
3040 return d->state->matrix.toAffine();
3041}
3042
3043/*!
3044 \obsolete
3045
3046 Resets any transformations that were made using translate(), scale(),
3047 shear(), rotate(), setWorldMatrix(), setViewport() and
3048 setWindow().
3049
3050 It is advisable to use resetTransform() instead of this function
3051 to preserve the properties of perspective transformations.
3052
3053 \sa {QPainter#Coordinate Transformations}{Coordinate
3054 Transformations}
3055*/
3056
3057void QPainter::resetMatrix()
3058{
3059 resetTransform();
3060}
3061#endif
3062
3063/*!
3064 \since 4.2
3065
3066 Enables transformations if \a enable is true, or disables
3067 transformations if \a enable is false. The world transformation
3068 matrix is not changed.
3069
3070 \sa worldMatrixEnabled(), worldTransform(), {QPainter#Coordinate
3071 Transformations}{Coordinate Transformations}
3072*/
3073
3074void QPainter::setWorldMatrixEnabled(bool enable)
3075{
3076 Q_D(QPainter);
3077#ifdef QT_DEBUG_DRAW
3078 if (qt_show_painter_debug_output)
3079 printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
3080#endif
3081
3082 if (!d->engine) {
3083 qWarning("QPainter::setMatrixEnabled: Painter not active");
3084 return;
3085 }
3086 if (enable == d->state->WxF)
3087 return;
3088
3089 d->state->WxF = enable;
3090 d->updateMatrix();
3091}
3092
3093/*!
3094 \since 4.2
3095
3096 Returns \c true if world transformation is enabled; otherwise returns
3097 false.
3098
3099 \sa setWorldMatrixEnabled(), worldTransform(), {Coordinate System}
3100*/
3101
3102bool QPainter::worldMatrixEnabled() const
3103{
3104 Q_D(const QPainter);
3105 if (!d->engine) {
3106 qWarning("QPainter::worldMatrixEnabled: Painter not active");
3107 return false;
3108 }
3109 return d->state->WxF;
3110}
3111
3112#if QT_DEPRECATED_SINCE(5, 13)
3113/*!
3114 \obsolete
3115
3116 Use setWorldMatrixEnabled() instead.
3117
3118 \sa setWorldMatrixEnabled()
3119*/
3120
3121void QPainter::setMatrixEnabled(bool enable)
3122{
3123 setWorldMatrixEnabled(enable);
3124}
3125
3126/*!
3127 \obsolete
3128
3129 Use worldMatrixEnabled() instead
3130
3131 \sa worldMatrixEnabled()
3132*/
3133
3134bool QPainter::matrixEnabled() const
3135{
3136 return worldMatrixEnabled();
3137}
3138#endif
3139
3140/*!
3141 Scales the coordinate system by (\a{sx}, \a{sy}).
3142
3143 \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
3144*/
3145
3146void QPainter::scale(qreal sx, qreal sy)
3147{
3148#ifdef QT_DEBUG_DRAW
3149 if (qt_show_painter_debug_output)
3150 printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
3151#endif
3152 Q_D(QPainter);
3153 if (!d->engine) {
3154 qWarning("QPainter::scale: Painter not active");
3155 return;
3156 }
3157
3158 d->state->worldMatrix.scale(sx,sy);
3159 d->state->WxF = true;
3160 d->updateMatrix();
3161}
3162
3163/*!
3164 Shears the coordinate system by (\a{sh}, \a{sv}).
3165
3166 \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
3167*/
3168
3169void QPainter::shear(qreal sh, qreal sv)
3170{
3171#ifdef QT_DEBUG_DRAW
3172 if (qt_show_painter_debug_output)
3173 printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
3174#endif
3175 Q_D(QPainter);
3176 if (!d->engine) {
3177 qWarning("QPainter::shear: Painter not active");
3178 return;
3179 }
3180
3181 d->state->worldMatrix.shear(sh, sv);
3182 d->state->WxF = true;
3183 d->updateMatrix();
3184}
3185
3186/*!
3187 \fn void QPainter::rotate(qreal angle)
3188
3189 Rotates the coordinate system clockwise. The given \a angle parameter is in degrees.
3190
3191 \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
3192*/
3193
3194void QPainter::rotate(qreal a)
3195{
3196#ifdef QT_DEBUG_DRAW
3197 if (qt_show_painter_debug_output)
3198 printf("QPainter::rotate(), angle=%f\n", a);
3199#endif
3200 Q_D(QPainter);
3201 if (!d->engine) {
3202 qWarning("QPainter::rotate: Painter not active");
3203 return;
3204 }
3205
3206 d->state->worldMatrix.rotate(a);
3207 d->state->WxF = true;
3208 d->updateMatrix();
3209}
3210
3211/*!
3212 Translates the coordinate system by the given \a offset; i.e. the
3213 given \a offset is added to points.
3214
3215 \sa setWorldTransform(), {QPainter#Coordinate Transformations}{Coordinate Transformations}
3216*/
3217void QPainter::translate(const QPointF &offset)
3218{
3219 qreal dx = offset.x();
3220 qreal dy = offset.y();
3221#ifdef QT_DEBUG_DRAW
3222 if (qt_show_painter_debug_output)
3223 printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
3224#endif
3225 Q_D(QPainter);
3226 if (!d->engine) {
3227 qWarning("QPainter::translate: Painter not active");
3228 return;
3229 }
3230
3231 d->state->worldMatrix.translate(dx, dy);
3232 d->state->WxF = true;
3233 d->updateMatrix();
3234}
3235
3236/*!
3237 \fn void QPainter::translate(const QPoint &offset)
3238 \overload
3239
3240 Translates the coordinate system by the given \a offset.
3241*/
3242
3243/*!
3244 \fn void QPainter::translate(qreal dx, qreal dy)
3245 \overload
3246
3247 Translates the coordinate system by the vector (\a dx, \a dy).
3248*/
3249
3250/*!
3251 \fn void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation operation)
3252
3253 Enables clipping, and sets the clip path for the painter to the
3254 given \a path, with the clip \a operation.
3255
3256 Note that the clip path is specified in logical (painter)
3257 coordinates.
3258
3259 \sa clipPath(), clipRegion(), {QPainter#Clipping}{Clipping}
3260
3261*/
3262void QPainter::setClipPath(const QPainterPath &path, Qt::ClipOperation op)
3263{
3264#ifdef QT_DEBUG_DRAW
3265 if (qt_show_painter_debug_output) {
3266 QRectF b = path.boundingRect();
3267 printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3268 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3269 }
3270#endif
3271 Q_D(QPainter);
3272
3273 if (!d->engine) {
3274 qWarning("QPainter::setClipPath: Painter not active");
3275 return;
3276 }
3277
3278 if ((!d->state->clipEnabled && op != Qt::NoClip))
3279 op = Qt::ReplaceClip;
3280
3281 if (d->extended) {
3282 d->state->clipEnabled = true;
3283 d->extended->clip(path, op);
3284 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3285 d->state->clipInfo.clear();
3286 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3287 d->state->clipOperation = op;
3288 return;
3289 }
3290
3291 if (d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3292 op = Qt::ReplaceClip;
3293
3294 d->state->clipPath = path;
3295 d->state->clipOperation = op;
3296 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3297 d->state->clipInfo.clear();
3298 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3299 d->state->clipEnabled = true;
3300 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3301 d->updateState(d->state);
3302}
3303
3304/*!
3305 Draws the outline (strokes) the path \a path with the pen specified
3306 by \a pen
3307
3308 \sa fillPath(), {QPainter#Drawing}{Drawing}
3309*/
3310void QPainter::strokePath(const QPainterPath &path, const QPen &pen)
3311{
3312 Q_D(QPainter);
3313
3314 if (!d->engine) {
3315 qWarning("QPainter::strokePath: Painter not active");
3316 return;
3317 }
3318
3319 if (path.isEmpty())
3320 return;
3321
3322 if (d->extended) {
3323 const QGradient *g = qpen_brush(pen).gradient();
3324 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
3325 d->extended->stroke(qtVectorPathForPath(path), pen);
3326 return;
3327 }
3328 }
3329
3330 QBrush oldBrush = d->state->brush;
3331 QPen oldPen = d->state->pen;
3332
3333 setPen(pen);
3334 setBrush(Qt::NoBrush);
3335
3336 drawPath(path);
3337
3338 // Reset old state
3339 setPen(oldPen);
3340 setBrush(oldBrush);
3341}
3342
3343/*!
3344 Fills the given \a path using the given \a brush. The outline is
3345 not drawn.
3346
3347 Alternatively, you can specify a QColor instead of a QBrush; the
3348 QBrush constructor (taking a QColor argument) will automatically
3349 create a solid pattern brush.
3350
3351 \sa drawPath()
3352*/
3353void QPainter::fillPath(const QPainterPath &path, const QBrush &brush)
3354{
3355 Q_D(QPainter);
3356
3357 if (!d->engine) {
3358 qWarning("QPainter::fillPath: Painter not active");
3359 return;
3360 }
3361
3362 if (path.isEmpty())
3363 return;
3364
3365 if (d->extended) {
3366 const QGradient *g = brush.gradient();
3367 if (!g || g->coordinateMode() == QGradient::LogicalMode) {
3368 d->extended->fill(qtVectorPathForPath(path), brush);
3369 return;
3370 }
3371 }
3372
3373 QBrush oldBrush = d->state->brush;
3374 QPen oldPen = d->state->pen;
3375
3376 setPen(Qt::NoPen);
3377 setBrush(brush);
3378
3379 drawPath(path);
3380
3381 // Reset old state
3382 setPen(oldPen);
3383 setBrush(oldBrush);
3384}
3385
3386/*!
3387 Draws the given painter \a path using the current pen for outline
3388 and the current brush for filling.
3389
3390 \table 100%
3391 \row
3392 \li \inlineimage qpainter-path.png
3393 \li
3394 \snippet code/src_gui_painting_qpainter.cpp 5
3395 \endtable
3396
3397 \sa {painting/painterpaths}{the Painter Paths
3398 example},{painting/deform}{the Vector Deformation example}
3399*/
3400void QPainter::drawPath(const QPainterPath &path)
3401{
3402#ifdef QT_DEBUG_DRAW
3403 QRectF pathBounds = path.boundingRect();
3404 if (qt_show_painter_debug_output)
3405 printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
3406 path.elementCount(),
3407 pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
3408#endif
3409
3410 Q_D(QPainter);
3411
3412 if (!d->engine) {
3413 qWarning("QPainter::drawPath: Painter not active");
3414 return;
3415 }
3416
3417 if (d->extended) {
3418 d->extended->drawPath(path);
3419 return;
3420 }
3421 d->updateState(d->state);
3422
3423 if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
3424 d->engine->drawPath(path);
3425 } else {
3426 d->draw_helper(path);
3427 }
3428}
3429
3430/*!
3431 \fn void QPainter::drawLine(const QLineF &line)
3432
3433 Draws a line defined by \a line.
3434
3435 \table 100%
3436 \row
3437 \li \inlineimage qpainter-line.png
3438 \li
3439 \snippet code/src_gui_painting_qpainter.cpp 6
3440 \endtable
3441
3442 \sa drawLines(), drawPolyline(), {Coordinate System}
3443*/
3444
3445/*!
3446 \fn void QPainter::drawLine(const QLine &line)
3447 \overload
3448
3449 Draws a line defined by \a line.
3450*/
3451
3452/*!
3453 \fn void QPainter::drawLine(const QPoint &p1, const QPoint &p2)
3454 \overload
3455
3456 Draws a line from \a p1 to \a p2.
3457*/
3458
3459/*!
3460 \fn void QPainter::drawLine(const QPointF &p1, const QPointF &p2)
3461 \overload
3462
3463 Draws a line from \a p1 to \a p2.
3464*/
3465
3466/*!
3467 \fn void QPainter::drawLine(int x1, int y1, int x2, int y2)
3468 \overload
3469
3470 Draws a line from (\a x1, \a y1) to (\a x2, \a y2).
3471*/
3472
3473/*!
3474 \fn void QPainter::drawRect(const QRectF &rectangle)
3475
3476 Draws the current \a rectangle with the current pen and brush.
3477
3478 A filled rectangle has a size of \a{rectangle}.size(). A stroked
3479 rectangle has a size of \a{rectangle}.size() plus the pen width.
3480
3481 \table 100%
3482 \row
3483 \li \inlineimage qpainter-rectangle.png
3484 \li
3485 \snippet code/src_gui_painting_qpainter.cpp 7
3486 \endtable
3487
3488 \sa drawRects(), drawPolygon(), {Coordinate System}
3489*/
3490
3491/*!
3492 \fn void QPainter::drawRect(const QRect &rectangle)
3493
3494 \overload
3495
3496 Draws the current \a rectangle with the current pen and brush.
3497*/
3498
3499/*!
3500 \fn void QPainter::drawRect(int x, int y, int width, int height)
3501
3502 \overload
3503
3504 Draws a rectangle with upper left corner at (\a{x}, \a{y}) and
3505 with the given \a width and \a height.
3506*/
3507
3508/*!
3509 \fn void QPainter::drawRects(const QRectF *rectangles, int rectCount)
3510
3511 Draws the first \a rectCount of the given \a rectangles using the
3512 current pen and brush.
3513
3514 \sa drawRect()
3515*/
3516void QPainter::drawRects(const QRectF *rects, int rectCount)
3517{
3518#ifdef QT_DEBUG_DRAW
3519 if (qt_show_painter_debug_output)
3520 printf("QPainter::drawRects(), count=%d\n", rectCount);
3521#endif
3522 Q_D(QPainter);
3523
3524 if (!d->engine) {
3525 qWarning("QPainter::drawRects: Painter not active");
3526 return;
3527 }
3528
3529 if (rectCount <= 0)
3530 return;
3531
3532 if (d->extended) {
3533 d->extended->drawRects(rects, rectCount);
3534 return;
3535 }
3536
3537 d->updateState(d->state);
3538
3539 if (!d->state->emulationSpecifier) {
3540 d->engine->drawRects(rects, rectCount);
3541 return;
3542 }
3543
3544 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3545 && d->state->matrix.type() == QTransform::TxTranslate) {
3546 for (int i=0; i<rectCount; ++i) {
3547 QRectF r(rects[i].x() + d->state->matrix.dx(),
3548 rects[i].y() + d->state->matrix.dy(),
3549 rects[i].width(),
3550 rects[i].height());
3551 d->engine->drawRects(&r, 1);
3552 }
3553 } else {
3554 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3555 for (int i=0; i<rectCount; ++i) {
3556 QPainterPath rectPath;
3557 rectPath.addRect(rects[i]);
3558 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3559 }
3560 } else {
3561 QPainterPath rectPath;
3562 for (int i=0; i<rectCount; ++i)
3563 rectPath.addRect(rects[i]);
3564 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3565 }
3566 }
3567}
3568
3569/*!
3570 \fn void QPainter::drawRects(const QRect *rectangles, int rectCount)
3571 \overload
3572
3573 Draws the first \a rectCount of the given \a rectangles using the
3574 current pen and brush.
3575*/
3576void QPainter::drawRects(const QRect *rects, int rectCount)
3577{
3578#ifdef QT_DEBUG_DRAW
3579 if (qt_show_painter_debug_output)
3580 printf("QPainter::drawRects(), count=%d\n", rectCount);
3581#endif
3582 Q_D(QPainter);
3583
3584 if (!d->engine) {
3585 qWarning("QPainter::drawRects: Painter not active");
3586 return;
3587 }
3588
3589 if (rectCount <= 0)
3590 return;
3591
3592 if (d->extended) {
3593 d->extended->drawRects(rects, rectCount);
3594 return;
3595 }
3596
3597 d->updateState(d->state);
3598
3599 if (!d->state->emulationSpecifier) {
3600 d->engine->drawRects(rects, rectCount);
3601 return;
3602 }
3603
3604 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3605 && d->state->matrix.type() == QTransform::TxTranslate) {
3606 for (int i=0; i<rectCount; ++i) {
3607 QRectF r(rects[i].x() + d->state->matrix.dx(),
3608 rects[i].y() + d->state->matrix.dy(),
3609 rects[i].width(),
3610 rects[i].height());
3611
3612 d->engine->drawRects(&r, 1);
3613 }
3614 } else {
3615 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3616 for (int i=0; i<rectCount; ++i) {
3617 QPainterPath rectPath;
3618 rectPath.addRect(rects[i]);
3619 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3620 }
3621 } else {
3622 QPainterPath rectPath;
3623 for (int i=0; i<rectCount; ++i)
3624 rectPath.addRect(rects[i]);
3625
3626 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3627 }
3628 }
3629}
3630
3631/*!
3632 \fn void QPainter::drawRects(const QVector<QRectF> &rectangles)
3633 \overload
3634
3635 Draws the given \a rectangles using the current pen and brush.
3636*/
3637
3638/*!
3639 \fn void QPainter::drawRects(const QVector<QRect> &rectangles)
3640
3641 \overload
3642
3643 Draws the given \a rectangles using the current pen and brush.
3644*/
3645
3646/*!
3647 \fn void QPainter::drawPoint(const QPointF &position)
3648
3649 Draws a single point at the given \a position using the current
3650 pen's color.
3651
3652 \sa {Coordinate System}
3653*/
3654
3655/*!
3656 \fn void QPainter::drawPoint(const QPoint &position)
3657 \overload
3658
3659 Draws a single point at the given \a position using the current
3660 pen's color.
3661*/
3662
3663/*! \fn void QPainter::drawPoint(int x, int y)
3664
3665 \overload
3666
3667 Draws a single point at position (\a x, \a y).
3668*/
3669
3670/*!
3671 Draws the first \a pointCount points in the array \a points using
3672 the current pen's color.
3673
3674 \sa {Coordinate System}
3675*/
3676void QPainter::drawPoints(const QPointF *points, int pointCount)
3677{
3678#ifdef QT_DEBUG_DRAW
3679 if (qt_show_painter_debug_output)
3680 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3681#endif
3682 Q_D(QPainter);
3683
3684 if (!d->engine) {
3685 qWarning("QPainter::drawPoints: Painter not active");
3686 return;
3687 }
3688
3689 if (pointCount <= 0)
3690 return;
3691
3692 if (d->extended) {
3693 d->extended->drawPoints(points, pointCount);
3694 return;
3695 }
3696
3697 d->updateState(d->state);
3698
3699 if (!d->state->emulationSpecifier) {
3700 d->engine->drawPoints(points, pointCount);
3701 return;
3702 }
3703
3704 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3705 && d->state->matrix.type() == QTransform::TxTranslate) {
3706 // ### use drawPoints function
3707 for (int i=0; i<pointCount; ++i) {
3708 QPointF pt(points[i].x() + d->state->matrix.dx(),
3709 points[i].y() + d->state->