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