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