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 &region);
2626 
2627 /*!
2628     Returns the current clip path in logical coordinates.
2629 
2630     \warning QPainter does not store the combined clip explicitly as
2631     this is handled by the underlying QPaintEngine, so the path is
2632     recreated on demand and transformed to the current logical
2633     coordinate system. This is potentially an expensive operation.
2634 
2635     \sa setClipPath(), clipRegion(), setClipping()
2636 */
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 &region, Qt::ClipOperation operation)
2844 
2845     Sets the clip region to the given \a region using the specified clip
2846     \a operation. The default clip operation is to replace the current
2847     clip region.
2848 
2849     Note that the clip region is given in logical coordinates.
2850 
2851     \sa clipRegion(), setClipRect(), {QPainter#Clipping}{Clipping}
2852 */
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 &center, 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 &center, 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