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