Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qpainter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4// QtCore
5#include <memory>
6#include <qdebug.h>
7#include <qmath.h>
8#include <qmutex.h>
9
10// QtGui
11#include "qbitmap.h"
12#include "qimage.h"
13#include "qpaintdevice.h"
14#include "qpaintengine.h"
15#include "qpainter.h"
16#include "qpainter_p.h"
17#include "qpainterpath.h"
18#include "qpicture.h"
19#include "qpixmapcache.h"
20#include "qpolygon.h"
21#include "qtextlayout.h"
22#include "qthread.h"
23#include "qvarlengtharray.h"
24#include "qstatictext.h"
25#include "qglyphrun.h"
26
27#include <qpa/qplatformtheme.h>
28#include <qpa/qplatformintegration.h>
29
30#include <private/qfontengine_p.h>
31#include <private/qpaintengine_p.h>
32#include <private/qemulationpaintengine_p.h>
33#include <private/qpainterpath_p.h>
34#include <private/qtextengine_p.h>
35#include <private/qpaintengine_raster_p.h>
36#include <private/qmath_p.h>
37#include <private/qstatictext_p.h>
38#include <private/qglyphrun_p.h>
39#include <private/qhexstring_p.h>
40#include <private/qguiapplication_p.h>
41#include <private/qrawfont_p.h>
42#include <private/qfont_p.h>
43
45
46using namespace Qt::StringLiterals;
47
48// We changed the type from QScopedPointer to unique_ptr, make sure it's binary compatible:
49static_assert(sizeof(QScopedPointer<QPainterPrivate>) == sizeof(std::unique_ptr<QPainterPrivate>));
50
51#define QGradient_StretchToDevice 0x10000000
52#define QPaintEngine_OpaqueBackground 0x40000000
53
54// #define QT_DEBUG_DRAW
55#ifdef QT_DEBUG_DRAW
56bool qt_show_painter_debug_output = true;
57#endif
58
59extern QPixmap qt_pixmapForBrush(int style, bool invert);
60
61void qt_format_text(const QFont &font,
62 const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
63 int tabstops, int* tabarray, int tabarraylen,
65static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine,
67 QTextItem::RenderFlags flags, qreal width,
68 const QTextCharFormat &charFormat);
69// Helper function to calculate left most position, width and flags for decoration drawing
71 const QPointF &decorationPosition,
72 const glyph_t *glyphArray,
74 int glyphCount,
75 QFontEngine *fontEngine,
76 bool underline,
77 bool overline,
78 bool strikeOut);
79
81{
82 switch (brush.style()) {
86 return brush.gradient()->coordinateMode();
87 default:
88 ;
89 }
91}
92
93extern bool qHasPixmapTexture(const QBrush &);
94
95static inline bool is_brush_transparent(const QBrush &brush) {
96 Qt::BrushStyle s = brush.style();
97 if (s != Qt::TexturePattern)
100 return brush.texture().isQBitmap() || brush.texture().hasAlphaChannel();
101 else {
102 const QImage texture = brush.textureImage();
103 return texture.hasAlphaChannel() || (texture.depth() == 1 && texture.colorCount() == 0);
104 }
105}
106
107static inline bool is_pen_transparent(const QPen &pen) {
108 return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());
109}
110
111/* Discards the emulation flags that are not relevant for line drawing
112 and returns the result
113*/
125
126#ifndef QT_NO_DEBUG
127static bool qt_painter_thread_test(int devType, int engineType, const char *what)
128{
130 switch (devType) {
131 case QInternal::Image:
134 // can be drawn onto these devices safely from any thread
135 break;
136 default:
137 if (QThread::currentThread() != qApp->thread()
138 // pixmaps cannot be targets unless threaded pixmaps are supported
139 && (devType != QInternal::Pixmap || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedPixmaps))
140 // framebuffer objects and such cannot be targets unless threaded GL is supported
141 && (devType != QInternal::OpenGL || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL))
142 // widgets cannot be targets except for QGLWidget
143 && (devType != QInternal::Widget || !platformIntegration->hasCapability(QPlatformIntegration::ThreadedOpenGL)
144 || (engineType != QPaintEngine::OpenGL && engineType != QPaintEngine::OpenGL2))) {
145 qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
146 return false;
147 }
148 break;
149 }
150 return true;
151}
152#endif
153
154static bool needsEmulation(const QBrush &brush)
155{
156 bool res = false;
157
158 const QGradient *bg = brush.gradient();
159 if (bg) {
161 } else if (brush.style() == Qt::TexturePattern) {
163 res = !qFuzzyCompare(brush.texture().devicePixelRatio(), qreal(1.0));
164 else
165 res = !qFuzzyCompare(brush.textureImage().devicePixelRatio(), qreal(1.0));
166 }
167
168 return res;
169}
170
172{
174 bool doEmulation = false;
175 if (state->bgMode == Qt::OpaqueMode)
176 doEmulation = true;
177
178 if (needsEmulation(state->brush))
179 doEmulation = true;
180
182 doEmulation = true;
183
184 if (doEmulation && extended->flags() & QPaintEngineEx::DoNotEmulate)
185 return;
186
187 if (doEmulation) {
188 if (extended != emulationEngine.get()) {
189 if (!emulationEngine)
190 emulationEngine = std::make_unique<QEmulationPaintEngine>(extended);
192 extended->setState(state.get());
193 }
194 } else if (emulationEngine.get() == extended) {
195 extended = emulationEngine->real_engine;
196 }
197}
198
200 : q_ptr(painter), txinv(0), inDestructor(false)
201{
202}
203
205 = default;
206
208{
209 if (state->VxF) {
210 qreal scaleW = qreal(state->vw)/qreal(state->ww);
211 qreal scaleH = qreal(state->vh)/qreal(state->wh);
212 return QTransform(scaleW, 0, 0, scaleH,
213 state->vx - state->wx*scaleW, state->vy - state->wy*scaleH);
214 }
215 return QTransform();
216}
217
219{
220 // Special cases for devices that does not support PdmDevicePixelRatio go here:
222 return qreal(1);
223
224 return device->devicePixelRatio();
225}
226
228{
229 const qreal devicePixelRatio = effectiveDevicePixelRatio();
230 return QTransform::fromScale(devicePixelRatio, devicePixelRatio);
231}
232
233/*
234 \internal
235 Returns \c true if using a shared painter; otherwise false.
236*/
238{
239 Q_ASSERT(q);
240 Q_ASSERT(pdev);
241
242 QPainter *sp = pdev->sharedPainter();
243 if (!sp)
244 return false;
245
246 // Save the current state of the shared painter and assign
247 // the current d_ptr to the shared painter's d_ptr.
248 sp->save();
249 ++sp->d_ptr->refcount;
250 sp->d_ptr->d_ptrs.push_back(q->d_ptr.get());
251 Q_UNUSED(q->d_ptr.release());
252 q->d_ptr.reset(sp->d_ptr.get());
253
254 Q_ASSERT(q->d_ptr->state);
255
256 // Now initialize the painter with correct widget properties.
257 q->d_ptr->initFrom(pdev);
259 pdev->redirected(&offset);
260 offset += q->d_ptr->engine->coordinateOffset();
261
262 // Update system rect.
263 q->d_ptr->state->ww = q->d_ptr->state->vw = pdev->width();
264 q->d_ptr->state->wh = q->d_ptr->state->vh = pdev->height();
265
266 // Update matrix.
267 if (q->d_ptr->state->WxF) {
268 q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
269 q->d_ptr->state->redirectionMatrix *= q->d_ptr->hidpiScaleTransform().inverted();
270 q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
271 q->d_ptr->state->worldMatrix = QTransform();
272 q->d_ptr->state->WxF = false;
273 } else {
274 q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
275 }
276 q->d_ptr->updateMatrix();
277
278 QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
279 if (enginePrivate->currentClipDevice == pdev) {
280 enginePrivate->systemStateChanged();
281 return true;
282 }
283
284 // Update system transform and clip.
285 enginePrivate->currentClipDevice = pdev;
286 enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
287 return true;
288}
289
291{
292 Q_ASSERT(refcount > 1);
293 Q_ASSERT(q);
294
295 --refcount;
296 QPainterPrivate *original = d_ptrs.back();
298 if (inDestructor) {
299 inDestructor = false;
300 if (original)
301 original->inDestructor = true;
302 } else if (!original) {
303 original = new QPainterPrivate(q);
304 }
305
306 q->restore();
307 Q_UNUSED(q->d_ptr.release());
308 q->d_ptr.reset(original);
309
310 if (emulationEngine) {
311 extended = emulationEngine->real_engine;
312 emulationEngine = nullptr;
313 }
314}
315
316
318{
319#ifdef QT_DEBUG_DRAW
320 if (qt_show_painter_debug_output) {
321 printf("QPainter::drawHelper\n");
322 }
323#endif
324
325 if (originalPath.isEmpty())
326 return;
327
328 QPaintEngine::PaintEngineFeatures gradientStretch =
329 QPaintEngine::PaintEngineFeatures(QGradient_StretchToDevice
331
332 const bool mustEmulateObjectBoundingModeGradients = extended
333 || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
334 && !engine->hasFeature(QPaintEngine::PatternTransform));
335
336 if (!(state->emulationSpecifier & ~gradientStretch)
337 && !mustEmulateObjectBoundingModeGradients) {
338 drawStretchedGradient(originalPath, op);
339 return;
340 } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) {
341 drawOpaqueBackground(originalPath, op);
342 return;
343 }
344
345 Q_Q(QPainter);
346
347 qreal strokeOffsetX = 0, strokeOffsetY = 0;
348
349 QPainterPath path = originalPath * state->matrix;
350 QRectF pathBounds = path.boundingRect();
351 QRectF strokeBounds;
352 bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
353 if (doStroke) {
354 qreal penWidth = state->pen.widthF();
355 if (penWidth == 0) {
356 strokeOffsetX = 1;
357 strokeOffsetY = 1;
358 } else {
359 // In case of complex xform
360 if (state->matrix.type() > QTransform::TxScale) {
361 QPainterPathStroker stroker;
362 stroker.setWidth(penWidth);
363 stroker.setJoinStyle(state->pen.joinStyle());
364 stroker.setCapStyle(state->pen.capStyle());
365 QPainterPath stroke = stroker.createStroke(originalPath);
366 strokeBounds = (stroke * state->matrix).boundingRect();
367 } else {
368 strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
369 strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
370 }
371 }
372 }
373
374 QRect absPathRect;
375 if (!strokeBounds.isEmpty()) {
376 absPathRect = strokeBounds.intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
377 } else {
378 absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
379 .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
380 }
381
382 if (q->hasClipping()) {
383 bool hasPerspectiveTransform = false;
384 for (const QPainterClipInfo &info : std::as_const(state->clipInfo)) {
385 if (info.matrix.type() == QTransform::TxProject) {
386 hasPerspectiveTransform = true;
387 break;
388 }
389 }
390 // avoid mapping QRegions with perspective transforms
391 if (!hasPerspectiveTransform) {
392 // The trick with txinv and invMatrix is done in order to
393 // avoid transforming the clip to logical coordinates, and
394 // then back to device coordinates. This is a problem with
395 // QRegion/QRect based clips, since they use integer
396 // coordinates and converting to/from logical coordinates will
397 // lose precision.
398 bool old_txinv = txinv;
399 QTransform old_invMatrix = invMatrix;
400 txinv = true;
402 QPainterPath clipPath = q->clipPath();
403 QRectF r = clipPath.boundingRect().intersected(absPathRect);
404 absPathRect = r.toAlignedRect();
405 txinv = old_txinv;
406 invMatrix = old_invMatrix;
407 }
408 }
409
410// qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",
411// devMinX, devMinY, device->width(), device->height());
412// qDebug() << " - matrix" << state->matrix;
413// qDebug() << " - originalPath.bounds" << originalPath.boundingRect();
414// qDebug() << " - path.bounds" << path.boundingRect();
415
416 if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
417 return;
418
419 QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
420 image.fill(0);
421
422 QPainter p(&image);
423
424 p.d_ptr->helper_device = helper_device;
425
426 p.setOpacity(state->opacity);
427 p.translate(-absPathRect.x(), -absPathRect.y());
428 p.setTransform(state->matrix, true);
429 p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
430 p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
431 p.setBackground(state->bgBrush);
432 p.setBackgroundMode(state->bgMode);
433 p.setBrushOrigin(state->brushOrigin);
434
435 p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
438
439 p.drawPath(originalPath);
440
441#ifndef QT_NO_DEBUG
442 static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty("QT_PAINT_FALLBACK_OVERLAY");
443 if (do_fallback_overlay) {
445 QPainter pt(&block);
446 pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
447 pt.drawLine(0, 0, 8, 8);
448 pt.end();
449 p.resetTransform();
450 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
451 p.setOpacity(0.5);
452 p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
453 }
454#endif
455
456 p.end();
457
458 q->save();
459 state->matrix = QTransform();
460 if (extended) {
462 } else {
463 state->dirtyFlags |= QPaintEngine::DirtyTransform;
465 }
466 engine->drawImage(absPathRect,
467 image,
468 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
470 q->restore();
471}
472
474{
475 Q_Q(QPainter);
476
477 q->setBackgroundMode(Qt::TransparentMode);
478
479 if (op & FillDraw && state->brush.style() != Qt::NoBrush) {
480 q->fillPath(path, state->bgBrush.color());
481 q->fillPath(path, state->brush);
482 }
483
484 if (op & StrokeDraw && state->pen.style() != Qt::NoPen) {
485 q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width()));
486 q->strokePath(path, state->pen);
487 }
488
489 q->setBackgroundMode(Qt::OpaqueMode);
490}
491
493{
495 && brush.style() <= Qt::ConicalGradientPattern);
496
497 QTransform gradientToUser(boundingRect.width(), 0, 0, boundingRect.height(),
498 boundingRect.x(), boundingRect.y());
499
500 QGradient g = *brush.gradient();
501 g.setCoordinateMode(QGradient::LogicalMode);
502
503 QBrush b(g);
504 if (brush.gradient()->coordinateMode() == QGradient::ObjectMode)
505 b.setTransform(b.transform() * gradientToUser);
506 else
507 b.setTransform(gradientToUser * b.transform());
508 return b;
509}
510
512{
513 Q_Q(QPainter);
514
515 const qreal sw = helper_device->width();
516 const qreal sh = helper_device->height();
517
518 bool changedPen = false;
519 bool changedBrush = false;
520 bool needsFill = false;
521
522 const QPen pen = state->pen;
523 const QBrush brush = state->brush;
524
525 const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
527
529
530 // Draw the xformed fill if the brush is a stretch gradient.
531 if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
532 if (brushMode == QGradient::StretchToDeviceMode) {
533 q->setPen(Qt::NoPen);
534 changedPen = pen.style() != Qt::NoPen;
535 q->scale(sw, sh);
537
538 const qreal isw = 1.0 / sw;
539 const qreal ish = 1.0 / sh;
540 QTransform inv(isw, 0, 0, ish, 0, 0);
541 engine->drawPath(path * inv);
542 q->scale(isw, ish);
543 } else {
544 needsFill = true;
545
546 if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
548 boundingRect = path.boundingRect();
550 changedBrush = true;
551 }
552 }
553 }
554
555 if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
556 // Draw the xformed outline if the pen is a stretch gradient.
557 if (penMode == QGradient::StretchToDeviceMode) {
558 q->setPen(Qt::NoPen);
559 changedPen = true;
560
561 if (needsFill) {
563 engine->drawPath(path);
564 }
565
566 q->scale(sw, sh);
567 q->setBrush(pen.brush());
568 changedBrush = true;
570
571 QPainterPathStroker stroker;
572 stroker.setDashPattern(pen.style());
573 stroker.setWidth(pen.widthF());
574 stroker.setJoinStyle(pen.joinStyle());
575 stroker.setCapStyle(pen.capStyle());
576 stroker.setMiterLimit(pen.miterLimit());
577 QPainterPath stroke = stroker.createStroke(path);
578
579 const qreal isw = 1.0 / sw;
580 const qreal ish = 1.0 / sh;
581 QTransform inv(isw, 0, 0, ish, 0, 0);
582 engine->drawPath(stroke * inv);
583 q->scale(isw, ish);
584 } else {
585 if (!needsFill && brush.style() != Qt::NoBrush) {
586 q->setBrush(Qt::NoBrush);
587 changedBrush = true;
588 }
589
590 if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
592
593 // avoid computing the bounding rect twice
594 if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
595 boundingRect = path.boundingRect();
596
597 QPen p = pen;
599 q->setPen(p);
600 changedPen = true;
601 } else if (changedPen) {
602 q->setPen(pen);
603 changedPen = false;
604 }
605
607 engine->drawPath(path);
608 }
609 } else if (needsFill) {
610 if (pen.style() != Qt::NoPen) {
611 q->setPen(Qt::NoPen);
612 changedPen = true;
613 }
614
616 engine->drawPath(path);
617 }
618
619 if (changedPen)
620 q->setPen(pen);
621 if (changedBrush)
622 q->setBrush(brush);
623}
624
625
627{
628 state->matrix = state->WxF ? state->worldMatrix : QTransform();
629 if (state->VxF)
630 state->matrix *= viewTransform();
631
632 txinv = false; // no inverted matrix
633 state->matrix *= state->redirectionMatrix;
634 if (extended)
636 else
637 state->dirtyFlags |= QPaintEngine::DirtyTransform;
638
639 state->matrix *= hidpiScaleTransform();
640
641// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);
642// qDebug() << " --- using matrix" << state->matrix << redirection_offset;
643}
644
647{
648 Q_ASSERT(txinv == false);
649 txinv = true; // creating inverted matrix
650 invMatrix = state->matrix.inverted();
651}
652
653extern bool qt_isExtendedRadialGradient(const QBrush &brush);
654
656{
657 bool alpha = false;
658 bool linearGradient = false;
659 bool radialGradient = false;
660 bool extendedRadialGradient = false;
661 bool conicalGradient = false;
662 bool patternBrush = false;
663 bool xform = false;
664 bool complexXform = false;
665
666 bool skip = true;
667
668 // Pen and brush properties (we have to check both if one changes because the
669 // one that's unchanged can still be in a state which requires emulation)
671 // Check Brush stroke emulation
672 if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
673 s->emulationSpecifier |= QPaintEngine::BrushStroke;
674 else
675 s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
676
677 skip = false;
678
679 QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
680 Qt::BrushStyle brushStyle = qbrush_style(s->brush);
681 Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
682 alpha = (penBrushStyle != Qt::NoBrush
683 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
684 && !penBrush.isOpaque())
685 || (brushStyle != Qt::NoBrush
686 && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
687 && !s->brush.isOpaque());
688 linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
689 (brushStyle == Qt::LinearGradientPattern));
690 radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
691 (brushStyle == Qt::RadialGradientPattern));
692 extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
693 conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
694 (brushStyle == Qt::ConicalGradientPattern));
695 patternBrush = (((penBrushStyle > Qt::SolidPattern
696 && penBrushStyle < Qt::LinearGradientPattern)
697 || penBrushStyle == Qt::TexturePattern) ||
698 ((brushStyle > Qt::SolidPattern
699 && brushStyle < Qt::LinearGradientPattern)
700 || brushStyle == Qt::TexturePattern));
701
702 bool penTextureAlpha = false;
703 if (penBrush.style() == Qt::TexturePattern)
704 penTextureAlpha = qHasPixmapTexture(penBrush)
705 ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
706 : penBrush.textureImage().hasAlphaChannel();
707 bool brushTextureAlpha = false;
708 if (s->brush.style() == Qt::TexturePattern) {
709 brushTextureAlpha = qHasPixmapTexture(s->brush)
710 ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
711 : s->brush.textureImage().hasAlphaChannel();
712 }
713 if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
714 || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
715 && !engine->hasFeature(QPaintEngine::MaskedBrush))
716 s->emulationSpecifier |= QPaintEngine::MaskedBrush;
717 else
718 s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
719 }
720
721 if (s->state() & (QPaintEngine::DirtyHints
724 skip = false;
725 }
726
727 if (skip)
728 return;
729
730#if 0
731 qDebug("QPainterPrivate::updateEmulationSpecifier, state=%p\n"
732 " - alpha: %d\n"
733 " - linearGradient: %d\n"
734 " - radialGradient: %d\n"
735 " - conicalGradient: %d\n"
736 " - patternBrush: %d\n"
737 " - hints: %x\n"
738 " - xform: %d\n",
739 s,
740 alpha,
741 linearGradient,
742 radialGradient,
743 conicalGradient,
744 patternBrush,
745 uint(s->renderHints),
746 xform);
747#endif
748
749 // XForm properties
750 if (s->state() & QPaintEngine::DirtyTransform) {
751 xform = !s->matrix.isIdentity();
752 complexXform = !s->matrix.isAffine();
753 } else if (s->matrix.type() >= QTransform::TxTranslate) {
754 xform = true;
755 complexXform = !s->matrix.isAffine();
756 }
757
758 const bool brushXform = (s->brush.transform().type() != QTransform::TxNone);
759 const bool penXform = (s->pen.brush().transform().type() != QTransform::TxNone);
760
761 const bool patternXform = patternBrush && (xform || brushXform || penXform);
762
763 // Check alphablending
764 if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
765 s->emulationSpecifier |= QPaintEngine::AlphaBlend;
766 else
767 s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
768
769 // Linear gradient emulation
770 if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
771 s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
772 else
773 s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
774
775 // Radial gradient emulation
776 if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
777 s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
778 else
779 s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
780
781 // Conical gradient emulation
782 if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
783 s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
784 else
785 s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
786
787 // Pattern brushes
788 if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
789 s->emulationSpecifier |= QPaintEngine::PatternBrush;
790 else
791 s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
792
793 // Pattern XForms
794 if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
795 s->emulationSpecifier |= QPaintEngine::PatternTransform;
796 else
797 s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
798
799 // Primitive XForms
800 if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
801 s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
802 else
803 s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
804
805 // Perspective XForms
806 if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
807 s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
808 else
809 s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
810
811 // Constant opacity
812 if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
813 s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
814 else
815 s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
816
817 bool gradientStretch = false;
818 bool objectBoundingMode = false;
819 if (linearGradient || conicalGradient || radialGradient) {
820 QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
821 QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
822
823 gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
824 gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
825
826 objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
827 objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
828 }
829 if (gradientStretch)
830 s->emulationSpecifier |= QGradient_StretchToDevice;
831 else
832 s->emulationSpecifier &= ~QGradient_StretchToDevice;
833
834 if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
835 s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
836 else
837 s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
838
839 // Opaque backgrounds...
840 if (s->bgMode == Qt::OpaqueMode &&
841 (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
842 s->emulationSpecifier |= QPaintEngine_OpaqueBackground;
843 else
844 s->emulationSpecifier &= ~QPaintEngine_OpaqueBackground;
845
846#if 0
847 //won't be correct either way because the device can already have
848 // something rendered to it in which case subsequent emulation
849 // on a fully transparent qimage and then blitting the results
850 // won't produce correct results
851 // Blend modes
852 if (state->composition_mode > QPainter::CompositionMode_Xor &&
853 !engine->hasFeature(QPaintEngine::BlendModes))
854 s->emulationSpecifier |= QPaintEngine::BlendModes;
855 else
856 s->emulationSpecifier &= ~QPaintEngine::BlendModes;
857#endif
858}
859
861{
862 // ### we might have to call QPainter::begin() here...
863 if (!engine->state) {
866 }
867
868 if (engine->state->painter() != newState->painter)
869 // ### this could break with clip regions vs paths.
871
872 // Upon restore, revert all changes since last save
873 else if (engine->state != newState)
874 newState->dirtyFlags |= QPaintEngine::DirtyFlags(static_cast<QPainterState *>(engine->state)->changeFlags);
875
876 // We need to store all changes made so that restore can deal with them
877 else
878 newState->changeFlags |= newState->dirtyFlags;
879
881
882 // Unset potential dirty background mode
885
886 engine->state = newState;
887 engine->updateState(*newState);
888 engine->clearDirty(QPaintEngine::AllDirty);
889
890}
891
893{
894
895 if (!newState) {
896 engine->state = newState;
897 } else if (newState->state() || engine->state!=newState) {
899 }
900}
901
902
1432 : d_ptr(new QPainterPrivate(this))
1433{
1434}
1435
1461 : d_ptr(nullptr)
1462{
1463 Q_ASSERT(pd != nullptr);
1465 d_ptr.reset(new QPainterPrivate(this));
1466 begin(pd);
1467 }
1468 Q_ASSERT(d_ptr);
1469}
1470
1475{
1476 d_ptr->inDestructor = true;
1477 QT_TRY {
1478 if (isActive())
1479 end();
1480 else if (d_ptr->refcount > 1)
1481 d_ptr->detachPainterPrivate(this);
1482 } QT_CATCH(...) {
1483 // don't throw anything in the destructor.
1484 }
1485 if (d_ptr) {
1486 // Make sure we haven't messed things up.
1487 Q_ASSERT(d_ptr->inDestructor);
1488 d_ptr->inDestructor = false;
1489 Q_ASSERT(d_ptr->refcount == 1);
1490 }
1491}
1492
1501{
1502 Q_D(const QPainter);
1503 if (isActive() && d->engine->d_func()->currentClipDevice)
1504 return d->engine->d_func()->currentClipDevice;
1505 return d->original_device;
1506}
1507
1516{
1517 Q_D(const QPainter);
1518 return d->engine != nullptr;
1519}
1520
1522{
1523 if (!engine) {
1524 qWarning("QPainter::initFrom: Painter not active, aborted");
1525 return;
1526 }
1527
1528 Q_Q(QPainter);
1530
1531 if (extended) {
1533 } else if (engine) {
1534 engine->setDirty(QPaintEngine::DirtyPen);
1537 }
1538}
1539
1549{
1550#ifdef QT_DEBUG_DRAW
1551 if (qt_show_painter_debug_output)
1552 printf("QPainter::save()\n");
1553#endif
1554 Q_D(QPainter);
1555 if (!d->engine) {
1556 qWarning("QPainter::save: Painter not active");
1557 return;
1558 }
1559
1560 std::unique_ptr<QPainterState> prev;
1561 if (d->extended) {
1562 // separate the creation of a new state from the update of d->state, since some
1563 // engines access d->state directly (not via createState()'s argument)
1564 std::unique_ptr<QPainterState> next(d->extended->createState(d->state.get()));
1565 prev = std::exchange(d->state, std::move(next));
1566 d->extended->setState(d->state.get());
1567 } else {
1568 d->updateState(d->state);
1569 prev = std::exchange(d->state, std::make_unique<QPainterState>(d->state.get()));
1570 d->engine->state = d->state.get();
1571 }
1572 d->savedStates.push(std::move(prev));
1573}
1574
1583{
1584#ifdef QT_DEBUG_DRAW
1585 if (qt_show_painter_debug_output)
1586 printf("QPainter::restore()\n");
1587#endif
1588 Q_D(QPainter);
1589 if (d->savedStates.empty()) {
1590 qWarning("QPainter::restore: Unbalanced save/restore");
1591 return;
1592 } else if (!d->engine) {
1593 qWarning("QPainter::restore: Painter not active");
1594 return;
1595 }
1596
1597 const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
1598 d->savedStates.pop();
1599 d->txinv = false;
1600
1601 if (d->extended) {
1602 d->checkEmulation();
1603 d->extended->setState(d->state.get());
1604 return;
1605 }
1606
1607 // trigger clip update if the clip path/region has changed since
1608 // last save
1609 if (!d->state->clipInfo.isEmpty()
1610 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1611 // reuse the tmp state to avoid any extra allocs...
1612 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1613 tmp->clipOperation = Qt::NoClip;
1614 tmp->clipPath = QPainterPath();
1615 d->engine->updateState(*tmp);
1616 // replay the list of clip states,
1617 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
1618 tmp->matrix = info.matrix;
1619 tmp->clipOperation = info.operation;
1620 if (info.clipType == QPainterClipInfo::RectClip) {
1622 tmp->clipRegion = info.rect;
1623 } else if (info.clipType == QPainterClipInfo::RegionClip) {
1625 tmp->clipRegion = info.region;
1626 } else { // clipType == QPainterClipInfo::PathClip
1628 tmp->clipPath = info.path;
1629 }
1630 d->engine->updateState(*tmp);
1631 }
1632
1633
1634 //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
1637 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1638 }
1639
1640 d->updateState(d->state.get());
1641}
1642
1643
1672{
1673 d->savedStates.clear();
1674 d->state = nullptr;
1675 d->engine = nullptr;
1676 d->device = nullptr;
1677}
1678
1680{
1681 Q_ASSERT(pd);
1682
1683 if (pd->painters > 0) {
1684 qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
1685 return false;
1686 }
1687
1688 if (d_ptr->engine) {
1689 qWarning("QPainter::begin: Painter already active");
1690 return false;
1691 }
1692
1694 return true;
1695
1696 Q_D(QPainter);
1697
1698 d->helper_device = pd;
1699 d->original_device = pd;
1700
1701 QPoint redirectionOffset;
1702 QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1703 if (rpd)
1704 pd = rpd;
1705
1706#ifdef QT_DEBUG_DRAW
1707 if (qt_show_painter_debug_output)
1708 printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1709#endif
1710
1711 if (pd->devType() == QInternal::Pixmap)
1712 static_cast<QPixmap *>(pd)->detach();
1713 else if (pd->devType() == QInternal::Image)
1714 static_cast<QImage *>(pd)->detach();
1715
1716 d->engine.reset(pd->paintEngine());
1717
1718 if (!d->engine) {
1719 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1720 return false;
1721 }
1722
1723 d->device = pd;
1724
1725 d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine.get()) : nullptr;
1726 if (d->emulationEngine)
1727 d->emulationEngine->real_engine = d->extended;
1728
1729 // Setup new state...
1730 Q_ASSERT(!d->state);
1731 d->state.reset(d->extended ? d->extended->createState(nullptr) : new QPainterState);
1732 d->state->painter = this;
1733
1734 d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1735 d->state->brushOrigin = QPointF();
1736
1737 // Slip a painter state into the engine before we do any other operations
1738 if (d->extended)
1739 d->extended->setState(d->state.get());
1740 else
1741 d->engine->state = d->state.get();
1742
1743 switch (pd->devType()) {
1744 case QInternal::Pixmap:
1745 {
1746 QPixmap *pm = static_cast<QPixmap *>(pd);
1747 Q_ASSERT(pm);
1748 if (pm->isNull()) {
1749 qWarning("QPainter::begin: Cannot paint on a null pixmap");
1751 return false;
1752 }
1753
1754 if (pm->depth() == 1) {
1755 d->state->pen = QPen(Qt::color1);
1756 d->state->brush = QBrush(Qt::color0);
1757 }
1758 break;
1759 }
1760 case QInternal::Image:
1761 {
1762 QImage *img = static_cast<QImage *>(pd);
1763 Q_ASSERT(img);
1764 if (img->isNull()) {
1765 qWarning("QPainter::begin: Cannot paint on a null image");
1767 return false;
1768 } else if (img->format() == QImage::Format_Indexed8 ||
1769 img->format() == QImage::Format_CMYK8888) {
1770 // Painting on these formats is not supported.
1771 qWarning() << "QPainter::begin: Cannot paint on an image with the"
1772 << img->format()
1773 << "format";
1775 return false;
1776 }
1777 if (img->depth() == 1) {
1778 d->state->pen = QPen(Qt::color1);
1779 d->state->brush = QBrush(Qt::color0);
1780 }
1781 break;
1782 }
1783 default:
1784 break;
1785 }
1786 if (d->state->ww == 0) // For compat with 3.x painter defaults
1787 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1788
1789 d->engine->setPaintDevice(pd);
1790
1791 bool begun = d->engine->begin(pd);
1792 if (!begun) {
1793 qWarning("QPainter::begin(): Returned false");
1794 if (d->engine->isActive()) {
1795 end();
1796 } else {
1798 }
1799 return false;
1800 } else {
1801 d->engine->setActive(begun);
1802 }
1803
1804 // Copy painter properties from original paint device,
1805 // required for QPixmap::grabWidget()
1806 if (d->original_device->devType() == QInternal::Widget) {
1807 d->initFrom(d->original_device);
1808 } else {
1809 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1810 // make sure we have a font compatible with the paintdevice
1811 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1812 }
1813
1814 QRect systemRect = d->engine->systemRect();
1815 if (!systemRect.isEmpty()) {
1816 d->state->ww = d->state->vw = systemRect.width();
1817 d->state->wh = d->state->vh = systemRect.height();
1818 } else {
1819 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1820 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1821 }
1822
1823 const QPoint coordinateOffset = d->engine->coordinateOffset();
1824 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1825
1826 Q_ASSERT(d->engine->isActive());
1827
1828 if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
1829 d->updateMatrix();
1830
1831 Q_ASSERT(d->engine->isActive());
1832 d->state->renderHints = QPainter::TextAntialiasing;
1833 ++d->device->painters;
1834
1835 d->state->emulationSpecifier = 0;
1836
1837 return true;
1838}
1839
1851{
1852#ifdef QT_DEBUG_DRAW
1853 if (qt_show_painter_debug_output)
1854 printf("QPainter::end()\n");
1855#endif
1856 Q_D(QPainter);
1857
1858 if (!d->engine) {
1859 qWarning("QPainter::end: Painter not active, aborted");
1861 return false;
1862 }
1863
1864 if (d->refcount > 1) {
1865 d->detachPainterPrivate(this);
1866 return true;
1867 }
1868
1869 bool ended = true;
1870
1871 if (d->engine->isActive()) {
1872 ended = d->engine->end();
1873 d->updateState(nullptr);
1874
1875 --d->device->painters;
1876 if (d->device->painters == 0) {
1877 d->engine->setPaintDevice(nullptr);
1878 d->engine->setActive(false);
1879 }
1880 }
1881
1882 if (d->savedStates.size() > 0) {
1883 qWarning("QPainter::end: Painter ended with %d saved states", int(d->savedStates.size()));
1884 }
1885
1886 d->engine.reset();
1887 d->emulationEngine = nullptr;
1888 d->extended = nullptr;
1889
1891
1892 return ended;
1893}
1894
1895
1903{
1904 Q_D(const QPainter);
1905 return d->engine.get();
1906}
1907
1941{
1942 Q_D(QPainter);
1943 if (!d->engine) {
1944 qWarning("QPainter::beginNativePainting: Painter not active");
1945 return;
1946 }
1947
1948 if (d->extended)
1949 d->extended->beginNativePainting();
1950}
1951
1962{
1963 Q_D(const QPainter);
1964 if (!d->engine) {
1965 qWarning("QPainter::beginNativePainting: Painter not active");
1966 return;
1967 }
1968
1969 if (d->extended)
1970 d->extended->endNativePainting();
1971 else
1972 d->engine->syncState();
1973}
1974
1983{
1984 Q_D(const QPainter);
1985 if (!d->engine) {
1986 qWarning("QPainter::fontMetrics: Painter not active");
1987 return QFontMetrics(QFont());
1988 }
1989 return QFontMetrics(d->state->font);
1990}
1991
1992
2001{
2002 Q_D(const QPainter);
2003 if (!d->engine) {
2004 qWarning("QPainter::fontInfo: Painter not active");
2005 return QFontInfo(QFont());
2006 }
2007 return QFontInfo(d->state->font);
2008}
2009
2018{
2019 Q_D(const QPainter);
2020 if (!d->engine) {
2021 qWarning("QPainter::opacity: Painter not active");
2022 return 1.0;
2023 }
2024 return d->state->opacity;
2025}
2026
2039{
2040 Q_D(QPainter);
2041
2042 if (!d->engine) {
2043 qWarning("QPainter::setOpacity: Painter not active");
2044 return;
2045 }
2046
2047 opacity = qMin(qreal(1), qMax(qreal(0), opacity));
2048
2049 if (opacity == d->state->opacity)
2050 return;
2051
2052 d->state->opacity = opacity;
2053
2054 if (d->extended)
2055 d->extended->opacityChanged();
2056 else
2057 d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
2058}
2059
2060
2068{
2069 Q_D(const QPainter);
2070 if (!d->engine) {
2071 qWarning("QPainter::brushOrigin: Painter not active");
2072 return QPoint();
2073 }
2074 return QPointF(d->state->brushOrigin).toPoint();
2075}
2076
2096{
2097 Q_D(QPainter);
2098#ifdef QT_DEBUG_DRAW
2099 if (qt_show_painter_debug_output)
2100 printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
2101#endif
2102
2103 if (!d->engine) {
2104 qWarning("QPainter::setBrushOrigin: Painter not active");
2105 return;
2106 }
2107
2108 d->state->brushOrigin = p;
2109
2110 if (d->extended) {
2111 d->extended->brushOriginChanged();
2112 return;
2113 }
2114
2115 d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
2116}
2117
2327{
2328 Q_D(QPainter);
2329 if (!d->engine) {
2330 qWarning("QPainter::setCompositionMode: Painter not active");
2331 return;
2332 }
2333 if (d->state->composition_mode == mode)
2334 return;
2335 if (d->extended) {
2336 d->state->composition_mode = mode;
2337 d->extended->compositionModeChanged();
2338 return;
2339 }
2340
2342 if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
2343 qWarning("QPainter::setCompositionMode: "
2344 "Raster operation modes not supported on device");
2345 return;
2346 }
2347 } else if (mode >= QPainter::CompositionMode_Plus) {
2348 if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
2349 qWarning("QPainter::setCompositionMode: "
2350 "Blend modes not supported on device");
2351 return;
2352 }
2353 } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
2355 qWarning("QPainter::setCompositionMode: "
2356 "PorterDuff modes not supported on device");
2357 return;
2358 }
2359 }
2360
2361 d->state->composition_mode = mode;
2362 d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
2363}
2364
2371{
2372 Q_D(const QPainter);
2373 if (!d->engine) {
2374 qWarning("QPainter::compositionMode: Painter not active");
2376 }
2377 return d->state->composition_mode;
2378}
2379
2387{
2388 Q_D(const QPainter);
2389 if (!d->engine) {
2390 qWarning("QPainter::background: Painter not active");
2391 return d->fakeState()->brush;
2392 }
2393 return d->state->bgBrush;
2394}
2395
2396
2404{
2405 Q_D(const QPainter);
2406 if (!d->engine) {
2407 qWarning("QPainter::hasClipping: Painter not active");
2408 return false;
2409 }
2410 return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
2411}
2412
2413
2422{
2423 Q_D(QPainter);
2424#ifdef QT_DEBUG_DRAW
2425 if (qt_show_painter_debug_output)
2426 printf("QPainter::setClipping(), enable=%s, was=%s\n",
2427 enable ? "on" : "off",
2428 hasClipping() ? "on" : "off");
2429#endif
2430 if (!d->engine) {
2431 qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
2432 return;
2433 }
2434
2435 if (hasClipping() == enable)
2436 return;
2437
2438 // we can't enable clipping if we don't have a clip
2439 if (enable
2440 && (d->state->clipInfo.isEmpty() || d->state->clipInfo.constLast().operation == Qt::NoClip))
2441 return;
2442 d->state->clipEnabled = enable;
2443
2444 if (d->extended) {
2445 d->extended->clipEnabledChanged();
2446 return;
2447 }
2448
2449 d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
2450 d->updateState(d->state);
2451}
2452
2453
2467{
2468 Q_D(const QPainter);
2469 if (!d->engine) {
2470 qWarning("QPainter::clipRegion: Painter not active");
2471 return QRegion();
2472 }
2473
2474 QRegion region;
2475 bool lastWasNothing = true;
2476
2477 if (!d->txinv)
2478 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2479
2480 // ### Falcon: Use QPainterPath
2481 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2482 switch (info.clipType) {
2483
2485 QTransform matrix = (info.matrix * d->invMatrix);
2486 if (lastWasNothing) {
2487 region = info.region * matrix;
2488 lastWasNothing = false;
2489 continue;
2490 }
2491 if (info.operation == Qt::IntersectClip)
2492 region &= info.region * matrix;
2493 else if (info.operation == Qt::NoClip) {
2494 lastWasNothing = true;
2495 region = QRegion();
2496 } else
2497 region = info.region * matrix;
2498 break;
2499 }
2500
2502 QTransform matrix = (info.matrix * d->invMatrix);
2503 if (lastWasNothing) {
2504 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2505 info.path.fillRule());
2506 lastWasNothing = false;
2507 continue;
2508 }
2509 if (info.operation == Qt::IntersectClip) {
2510 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2511 info.path.fillRule());
2512 } else if (info.operation == Qt::NoClip) {
2513 lastWasNothing = true;
2514 region = QRegion();
2515 } else {
2516 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2517 info.path.fillRule());
2518 }
2519 break;
2520 }
2521
2523 QTransform matrix = (info.matrix * d->invMatrix);
2524 if (lastWasNothing) {
2525 region = QRegion(info.rect) * matrix;
2526 lastWasNothing = false;
2527 continue;
2528 }
2529 if (info.operation == Qt::IntersectClip) {
2530 // Use rect intersection if possible.
2531 if (matrix.type() <= QTransform::TxScale)
2532 region &= matrix.mapRect(info.rect);
2533 else
2534 region &= matrix.map(QRegion(info.rect));
2535 } else if (info.operation == Qt::NoClip) {
2536 lastWasNothing = true;
2537 region = QRegion();
2538 } else {
2539 region = QRegion(info.rect) * matrix;
2540 }
2541 break;
2542 }
2543
2545 QTransform matrix = (info.matrix * d->invMatrix);
2546 if (lastWasNothing) {
2547 region = QRegion(info.rectf.toRect()) * matrix;
2548 lastWasNothing = false;
2549 continue;
2550 }
2551 if (info.operation == Qt::IntersectClip) {
2552 // Use rect intersection if possible.
2553 if (matrix.type() <= QTransform::TxScale)
2554 region &= matrix.mapRect(info.rectf.toRect());
2555 else
2556 region &= matrix.map(QRegion(info.rectf.toRect()));
2557 } else if (info.operation == Qt::NoClip) {
2558 lastWasNothing = true;
2559 region = QRegion();
2560 } else {
2561 region = QRegion(info.rectf.toRect()) * matrix;
2562 }
2563 break;
2564 }
2565 }
2566 }
2567
2568 return region;
2569}
2570
2571extern QPainterPath qt_regionToPath(const QRegion &region);
2572
2584{
2585 Q_D(const QPainter);
2586
2587 // ### Since we do not support path intersections and path unions yet,
2588 // we just use clipRegion() here...
2589 if (!d->engine) {
2590 qWarning("QPainter::clipPath: Painter not active");
2591 return QPainterPath();
2592 }
2593
2594 // No clip, return empty
2595 if (d->state->clipInfo.isEmpty()) {
2596 return QPainterPath();
2597 } else {
2598
2599 // Update inverse matrix, used below.
2600 if (!d->txinv)
2601 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2602
2603 // For the simple case avoid conversion.
2604 if (d->state->clipInfo.size() == 1
2605 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
2606 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2607 return d->state->clipInfo.at(0).path * matrix;
2608
2609 } else if (d->state->clipInfo.size() == 1
2610 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
2611 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2613 path.addRect(d->state->clipInfo.at(0).rect);
2614 return path * matrix;
2615 } else {
2616 // Fallback to clipRegion() for now, since we don't have isect/unite for paths
2617 return qt_regionToPath(clipRegion());
2618 }
2619 }
2620}
2621
2635{
2636 Q_D(const QPainter);
2637
2638 if (!d->engine) {
2639 qWarning("QPainter::clipBoundingRect: Painter not active");
2640 return QRectF();
2641 }
2642
2643 // Accumulate the bounding box in device space. This is not 100%
2644 // precise, but it fits within the guarantee and it is reasonably
2645 // fast.
2646 QRectF bounds;
2647 bool first = true;
2648 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2649 QRectF r;
2650
2651 if (info.clipType == QPainterClipInfo::RectClip)
2652 r = info.rect;
2653 else if (info.clipType == QPainterClipInfo::RectFClip)
2654 r = info.rectf;
2655 else if (info.clipType == QPainterClipInfo::RegionClip)
2656 r = info.region.boundingRect();
2657 else
2658 r = info.path.boundingRect();
2659
2660 r = info.matrix.mapRect(r);
2661
2662 if (first)
2663 bounds = r;
2664 else if (info.operation == Qt::IntersectClip)
2665 bounds &= r;
2666 first = false;
2667 }
2668
2669
2670 // Map the rectangle back into logical space using the inverse
2671 // matrix.
2672 if (!d->txinv)
2673 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2674
2675 return d->invMatrix.mapRect(bounds);
2676}
2677
2691{
2692 Q_D(QPainter);
2693
2694 if (d->extended) {
2695 if (!d->engine) {
2696 qWarning("QPainter::setClipRect: Painter not active");
2697 return;
2698 }
2699 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2700 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2701 op = Qt::ReplaceClip;
2702
2703 qreal right = rect.x() + rect.width();
2704 qreal bottom = rect.y() + rect.height();
2705 qreal pts[] = { rect.x(), rect.y(),
2706 right, rect.y(),
2707 right, bottom,
2708 rect.x(), bottom };
2709 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
2710 d->state->clipEnabled = true;
2711 d->extended->clip(vp, op);
2712 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2713 d->state->clipInfo.clear();
2714 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2715 d->state->clipOperation = op;
2716 return;
2717 }
2718
2719 if (qreal(int(rect.top())) == rect.top()
2720 && qreal(int(rect.bottom())) == rect.bottom()
2721 && qreal(int(rect.left())) == rect.left()
2722 && qreal(int(rect.right())) == rect.right())
2723 {
2724 setClipRect(rect.toRect(), op);
2725 return;
2726 }
2727
2728 if (rect.isEmpty()) {
2729 setClipRegion(QRegion(), op);
2730 return;
2731 }
2732
2734 path.addRect(rect);
2735 setClipPath(path, op);
2736}
2737
2746{
2747 Q_D(QPainter);
2748
2749 if (!d->engine) {
2750 qWarning("QPainter::setClipRect: Painter not active");
2751 return;
2752 }
2753 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2754
2755 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2756 op = Qt::ReplaceClip;
2757
2758 if (d->extended) {
2759 d->state->clipEnabled = true;
2760 d->extended->clip(rect, op);
2761 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2762 d->state->clipInfo.clear();
2763 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2764 d->state->clipOperation = op;
2765 return;
2766 }
2767
2768 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2769 op = Qt::ReplaceClip;
2770
2771 d->state->clipRegion = rect;
2772 d->state->clipOperation = op;
2773 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2774 d->state->clipInfo.clear();
2775 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2776 d->state->clipEnabled = true;
2778 d->updateState(d->state);
2779}
2780
2800{
2801 Q_D(QPainter);
2802#ifdef QT_DEBUG_DRAW
2803 QRect rect = r.boundingRect();
2804 if (qt_show_painter_debug_output)
2805 printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2806 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2807#endif
2808 if (!d->engine) {
2809 qWarning("QPainter::setClipRegion: Painter not active");
2810 return;
2811 }
2812 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2813
2814 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2815 op = Qt::ReplaceClip;
2816
2817 if (d->extended) {
2818 d->state->clipEnabled = true;
2819 d->extended->clip(r, op);
2820 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2821 d->state->clipInfo.clear();
2822 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2823 d->state->clipOperation = op;
2824 return;
2825 }
2826
2827 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2828 op = Qt::ReplaceClip;
2829
2830 d->state->clipRegion = r;
2831 d->state->clipOperation = op;
2832 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2833 d->state->clipInfo.clear();
2834 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2835 d->state->clipEnabled = true;
2837 d->updateState(d->state);
2838}
2839
2852{
2853 Q_D(QPainter);
2854#ifdef QT_DEBUG_DRAW
2855 if (qt_show_painter_debug_output)
2856 printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
2857#endif
2858
2859 if (!d->engine) {
2860 qWarning("QPainter::setMatrixEnabled: Painter not active");
2861 return;
2862 }
2863 if (enable == d->state->WxF)
2864 return;
2865
2866 d->state->WxF = enable;
2867 d->updateMatrix();
2868}
2869
2880{
2881 Q_D(const QPainter);
2882 if (!d->engine) {
2883 qWarning("QPainter::worldMatrixEnabled: Painter not active");
2884 return false;
2885 }
2886 return d->state->WxF;
2887}
2888
2896{
2897#ifdef QT_DEBUG_DRAW
2898 if (qt_show_painter_debug_output)
2899 printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
2900#endif
2901 Q_D(QPainter);
2902 if (!d->engine) {
2903 qWarning("QPainter::scale: Painter not active");
2904 return;
2905 }
2906
2907 d->state->worldMatrix.scale(sx,sy);
2908 d->state->WxF = true;
2909 d->updateMatrix();
2910}
2911
2919{
2920#ifdef QT_DEBUG_DRAW
2921 if (qt_show_painter_debug_output)
2922 printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
2923#endif
2924 Q_D(QPainter);
2925 if (!d->engine) {
2926 qWarning("QPainter::shear: Painter not active");
2927 return;
2928 }
2929
2930 d->state->worldMatrix.shear(sh, sv);
2931 d->state->WxF = true;
2932 d->updateMatrix();
2933}
2934
2944{
2945#ifdef QT_DEBUG_DRAW
2946 if (qt_show_painter_debug_output)
2947 printf("QPainter::rotate(), angle=%f\n", a);
2948#endif
2949 Q_D(QPainter);
2950 if (!d->engine) {
2951 qWarning("QPainter::rotate: Painter not active");
2952 return;
2953 }
2954
2955 d->state->worldMatrix.rotate(a);
2956 d->state->WxF = true;
2957 d->updateMatrix();
2958}
2959
2967{
2968 qreal dx = offset.x();
2969 qreal dy = offset.y();
2970#ifdef QT_DEBUG_DRAW
2971 if (qt_show_painter_debug_output)
2972 printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
2973#endif
2974 Q_D(QPainter);
2975 if (!d->engine) {
2976 qWarning("QPainter::translate: Painter not active");
2977 return;
2978 }
2979
2980 d->state->worldMatrix.translate(dx, dy);
2981 d->state->WxF = true;
2982 d->updateMatrix();
2983}
2984
3012{
3013#ifdef QT_DEBUG_DRAW
3014 if (qt_show_painter_debug_output) {
3015 QRectF b = path.boundingRect();
3016 printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3017 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3018 }
3019#endif
3020 Q_D(QPainter);
3021
3022 if (!d->engine) {
3023 qWarning("QPainter::setClipPath: Painter not active");
3024 return;
3025 }
3026
3027 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3028 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3029 op = Qt::ReplaceClip;
3030
3031 if (d->extended) {
3032 d->state->clipEnabled = true;
3033 d->extended->clip(path, op);
3034 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3035 d->state->clipInfo.clear();
3036 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3037 d->state->clipOperation = op;
3038 return;
3039 }
3040
3041 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3042 op = Qt::ReplaceClip;
3043
3044 d->state->clipPath = path;
3045 d->state->clipOperation = op;
3046 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3047 d->state->clipInfo.clear();
3048 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3049 d->state->clipEnabled = true;
3051 d->updateState(d->state);
3052}
3053
3061{
3062 Q_D(QPainter);
3063
3064 if (!d->engine) {
3065 qWarning("QPainter::strokePath: Painter not active");
3066 return;
3067 }
3068
3069 if (path.isEmpty())
3070 return;
3071
3072 if (d->extended && !needsEmulation(pen.brush())) {
3073 d->extended->stroke(qtVectorPathForPath(path), pen);
3074 return;
3075 }
3076
3077 QBrush oldBrush = d->state->brush;
3078 QPen oldPen = d->state->pen;
3079
3080 setPen(pen);
3082
3083 drawPath(path);
3084
3085 // Reset old state
3086 setPen(oldPen);
3087 setBrush(oldBrush);
3088}
3089
3101{
3102 Q_D(QPainter);
3103
3104 if (!d->engine) {
3105 qWarning("QPainter::fillPath: Painter not active");
3106 return;
3107 }
3108
3109 if (path.isEmpty())
3110 return;
3111
3112 if (d->extended && !needsEmulation(brush)) {
3113 d->extended->fill(qtVectorPathForPath(path), brush);
3114 return;
3115 }
3116
3117 QBrush oldBrush = d->state->brush;
3118 QPen oldPen = d->state->pen;
3119
3121 setBrush(brush);
3122
3123 drawPath(path);
3124
3125 // Reset old state
3126 setPen(oldPen);
3127 setBrush(oldBrush);
3128}
3129
3145{
3146#ifdef QT_DEBUG_DRAW
3147 QRectF pathBounds = path.boundingRect();
3148 if (qt_show_painter_debug_output)
3149 printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
3150 path.elementCount(),
3151 pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
3152#endif
3153
3154 Q_D(QPainter);
3155
3156 if (!d->engine) {
3157 qWarning("QPainter::drawPath: Painter not active");
3158 return;
3159 }
3160
3161 if (d->extended) {
3162 d->extended->drawPath(path);
3163 return;
3164 }
3165 d->updateState(d->state);
3166
3167 if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
3168 d->engine->drawPath(path);
3169 } else {
3170 d->draw_helper(path);
3171 }
3172}
3173
3260void QPainter::drawRects(const QRectF *rects, int rectCount)
3261{
3262#ifdef QT_DEBUG_DRAW
3263 if (qt_show_painter_debug_output)
3264 printf("QPainter::drawRects(), count=%d\n", rectCount);
3265#endif
3266 Q_D(QPainter);
3267
3268 if (!d->engine) {
3269 qWarning("QPainter::drawRects: Painter not active");
3270 return;
3271 }
3272
3273 if (rectCount <= 0)
3274 return;
3275
3276 if (d->extended) {
3277 d->extended->drawRects(rects, rectCount);
3278 return;
3279 }
3280
3281 d->updateState(d->state);
3282
3283 if (!d->state->emulationSpecifier) {
3284 d->engine->drawRects(rects, rectCount);
3285 return;
3286 }
3287
3288 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3289 && d->state->matrix.type() == QTransform::TxTranslate) {
3290 for (int i=0; i<rectCount; ++i) {
3291 QRectF r(rects[i].x() + d->state->matrix.dx(),
3292 rects[i].y() + d->state->matrix.dy(),
3293 rects[i].width(),
3294 rects[i].height());
3295 d->engine->drawRects(&r, 1);
3296 }
3297 } else {
3298 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3299 for (int i=0; i<rectCount; ++i) {
3300 QPainterPath rectPath;
3301 rectPath.addRect(rects[i]);
3302 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3303 }
3304 } else {
3305 QPainterPath rectPath;
3306 for (int i=0; i<rectCount; ++i)
3307 rectPath.addRect(rects[i]);
3308 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3309 }
3310 }
3311}
3312
3320void QPainter::drawRects(const QRect *rects, int rectCount)
3321{
3322#ifdef QT_DEBUG_DRAW
3323 if (qt_show_painter_debug_output)
3324 printf("QPainter::drawRects(), count=%d\n", rectCount);
3325#endif
3326 Q_D(QPainter);
3327
3328 if (!d->engine) {
3329 qWarning("QPainter::drawRects: Painter not active");
3330 return;
3331 }
3332
3333 if (rectCount <= 0)
3334 return;
3335
3336 if (d->extended) {
3337 d->extended->drawRects(rects, rectCount);
3338 return;
3339 }
3340
3341 d->updateState(d->state);
3342
3343 if (!d->state->emulationSpecifier) {
3344 d->engine->drawRects(rects, rectCount);
3345 return;
3346 }
3347
3348 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3349 && d->state->matrix.type() == QTransform::TxTranslate) {
3350 for (int i=0; i<rectCount; ++i) {
3351 QRectF r(rects[i].x() + d->state->matrix.dx(),
3352 rects[i].y() + d->state->matrix.dy(),
3353 rects[i].width(),
3354 rects[i].height());
3355
3356 d->engine->drawRects(&r, 1);
3357 }
3358 } else {
3359 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3360 for (int i=0; i<rectCount; ++i) {
3361 QPainterPath rectPath;
3362 rectPath.addRect(rects[i]);
3363 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3364 }
3365 } else {
3366 QPainterPath rectPath;
3367 for (int i=0; i<rectCount; ++i)
3368 rectPath.addRect(rects[i]);
3369
3370 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3371 }
3372 }
3373}
3374
3420void QPainter::drawPoints(const QPointF *points, int pointCount)
3421{
3422#ifdef QT_DEBUG_DRAW
3423 if (qt_show_painter_debug_output)
3424 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3425#endif
3426 Q_D(QPainter);
3427
3428 if (!d->engine) {
3429 qWarning("QPainter::drawPoints: Painter not active");
3430 return;
3431 }
3432
3433 if (pointCount <= 0)
3434 return;
3435
3436 if (d->extended) {
3437 d->extended->drawPoints(points, pointCount);
3438 return;
3439 }
3440
3441 d->updateState(d->state);
3442
3443 if (!d->state->emulationSpecifier) {
3444 d->engine->drawPoints(points, pointCount);
3445 return;
3446 }
3447
3448 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3449 && d->state->matrix.type() == QTransform::TxTranslate) {
3450 // ### use drawPoints function
3451 for (int i=0; i<pointCount; ++i) {
3452 QPointF pt(points[i].x() + d->state->matrix.dx(),
3453 points[i].y() + d->state->matrix.dy());
3454 d->engine->drawPoints(&pt, 1);
3455 }
3456 } else {
3457 QPen pen = d->state->pen;
3458 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3459 if (flat_pen) {
3460 save();
3462 setPen(pen);
3463 }
3465 for (int i=0; i<pointCount; ++i) {
3466 path.moveTo(points[i].x(), points[i].y());
3467 path.lineTo(points[i].x() + 0.0001, points[i].y());
3468 }
3469 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3470 if (flat_pen)
3471 restore();
3472 }
3473}
3474
3482void QPainter::drawPoints(const QPoint *points, int pointCount)
3483{
3484#ifdef QT_DEBUG_DRAW
3485 if (qt_show_painter_debug_output)
3486 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3487#endif
3488 Q_D(QPainter);
3489
3490 if (!d->engine) {
3491 qWarning("QPainter::drawPoints: Painter not active");
3492 return;
3493 }
3494
3495 if (pointCount <= 0)
3496 return;
3497
3498 if (d->extended) {
3499 d->extended->drawPoints(points, pointCount);
3500 return;
3501 }
3502
3503 d->updateState(d->state);
3504
3505 if (!d->state->emulationSpecifier) {
3506 d->engine->drawPoints(points, pointCount);
3507 return;
3508 }
3509
3510 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3511 && d->state->matrix.type() == QTransform::TxTranslate) {
3512 // ### use drawPoints function
3513 for (int i=0; i<pointCount; ++i) {
3514 QPointF pt(points[i].x() + d->state->matrix.dx(),
3515 points[i].y() + d->state->matrix.dy());
3516 d->engine->drawPoints(&pt, 1);
3517 }
3518 } else {
3519 QPen pen = d->state->pen;
3520 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3521 if (flat_pen) {
3522 save();
3524 setPen(pen);
3525 }
3527 for (int i=0; i<pointCount; ++i) {
3528 path.moveTo(points[i].x(), points[i].y());
3529 path.lineTo(points[i].x() + 0.0001, points[i].y());
3530 }
3531 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3532 if (flat_pen)
3533 restore();
3534 }
3535}
3536
3568{
3569#ifdef QT_DEBUG_DRAW
3570 if (qt_show_painter_debug_output)
3571 printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
3572#endif
3573
3574 Q_D(QPainter);
3575 if (!d->engine) {
3576 qWarning("QPainter::setBackgroundMode: Painter not active");
3577 return;
3578 }
3579 if (d->state->bgMode == mode)
3580 return;
3581
3582 d->state->bgMode = mode;
3583 if (d->extended) {
3584 d->checkEmulation();
3585 } else {
3586 d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
3587 }
3588}
3589
3596{
3597 Q_D(const QPainter);
3598 if (!d->engine) {
3599 qWarning("QPainter::backgroundMode: Painter not active");
3600 return Qt::TransparentMode;
3601 }
3602 return d->state->bgMode;
3603}
3604
3605
3614{
3615#ifdef QT_DEBUG_DRAW
3616 if (qt_show_painter_debug_output)
3617 printf("QPainter::setPen(), color=%04x\n", color.rgb());
3618#endif
3619 Q_D(QPainter);
3620 if (!d->engine) {
3621 qWarning("QPainter::setPen: Painter not active");
3622 return;
3623 }
3624
3625 QPen pen(color.isValid() ? color : QColor(Qt::black));
3626
3627 if (d->state->pen == pen)
3628 return;
3629
3630 d->state->pen = pen;
3631 if (d->extended)
3632 d->extended->penChanged();
3633 else
3634 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3635}
3636
3646void QPainter::setPen(const QPen &pen)
3647{
3648
3649#ifdef QT_DEBUG_DRAW
3650 if (qt_show_painter_debug_output)
3651 printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
3652 pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
3653#endif
3654 Q_D(QPainter);
3655 if (!d->engine) {
3656 qWarning("QPainter::setPen: Painter not active");
3657 return;
3658 }
3659
3660 if (d->state->pen == pen)
3661 return;
3662
3663 d->state->pen = pen;
3664
3665 if (d->extended) {
3666 d->checkEmulation();
3667 d->extended->penChanged();
3668 return;
3669 }
3670
3671 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3672}
3673
3682{
3683 Q_D(QPainter);
3684 if (!d->engine) {
3685 qWarning("QPainter::setPen: Painter not active");
3686 return;
3687 }
3688
3689 QPen pen = QPen(style);
3690
3691 if (d->state->pen == pen)
3692 return;
3693
3694 d->state->pen = pen;
3695
3696 if (d->extended)
3697 d->extended->penChanged();
3698 else
3699 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3700
3701}
3702
3709const QPen &QPainter::pen() const
3710{
3711 Q_D(const QPainter);
3712 if (!d->engine) {
3713 qWarning("QPainter::pen: Painter not active");
3714 return d->fakeState()->pen;
3715 }
3716 return d->state->pen;
3717}
3718
3719
3729{
3730#ifdef QT_DEBUG_DRAW
3731 if (qt_show_painter_debug_output)
3732 printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
3733#endif
3734 Q_D(QPainter);
3735 if (!d->engine) {
3736 qWarning("QPainter::setBrush: Painter not active");
3737 return;
3738 }
3739
3740 if (d->state->brush.d == brush.d)
3741 return;
3742
3743 if (d->extended) {
3744 d->state->brush = brush;
3745 d->checkEmulation();
3746 d->extended->brushChanged();
3747 return;
3748 }
3749
3750 d->state->brush = brush;
3751 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3752}
3753
3754
3763{
3764 Q_D(QPainter);
3765 if (!d->engine) {
3766 qWarning("QPainter::setBrush: Painter not active");
3767 return;
3768 }
3769 if (d->state->brush.style() == style &&
3770 (style == Qt::NoBrush
3771 || (style == Qt::SolidPattern && d->state->brush.color() == QColor(0, 0, 0))))
3772 return;
3773 d->state->brush = QBrush(Qt::black, style);
3774 if (d->extended)
3775 d->extended->brushChanged();
3776 else
3777 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3778}
3779
3787{
3788 Q_D(const QPainter);
3789 if (!d->engine) {
3790 qWarning("QPainter::brush: Painter not active");
3791 return d->fakeState()->brush;
3792 }
3793 return d->state->brush;
3794}
3795
3810{
3811#ifdef QT_DEBUG_DRAW
3812 if (qt_show_painter_debug_output)
3813 printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
3814#endif
3815
3816 Q_D(QPainter);
3817 if (!d->engine) {
3818 qWarning("QPainter::setBackground: Painter not active");
3819 return;
3820 }
3821 d->state->bgBrush = bg;
3822 if (!d->extended)
3823 d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
3824}
3825
3840{
3841 Q_D(QPainter);
3842
3843#ifdef QT_DEBUG_DRAW
3844 if (qt_show_painter_debug_output)
3845 printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.families().first().toLatin1().constData(), font.pointSize());
3846#endif
3847
3848 if (!d->engine) {
3849 qWarning("QPainter::setFont: Painter not active");
3850 return;
3851 }
3852
3853 d->state->font = QFont(font.resolve(d->state->deviceFont), device());
3854 if (!d->extended)
3855 d->state->dirtyFlags |= QPaintEngine::DirtyFont;
3856}
3857
3863const QFont &QPainter::font() const
3864{
3865 Q_D(const QPainter);
3866 if (!d->engine) {
3867 qWarning("QPainter::font: Painter not active");
3868 return d->fakeState()->font;
3869 }
3870 return d->state->font;
3871}
3872
3898{
3899#ifdef QT_DEBUG_DRAW
3900 if (qt_show_painter_debug_output)
3901 printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
3902#endif
3903 Q_D(QPainter);
3904
3905 if (!d->engine) {
3906 qWarning("QPainter::drawRoundedRect: Painter not active");
3907 return;
3908 }
3909
3910 if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
3911 drawRect(rect);
3912 return;
3913 }
3914
3915 if (d->extended) {
3916 d->extended->drawRoundedRect(rect, xRadius, yRadius, mode);
3917 return;
3918 }
3919
3921 path.addRoundedRect(rect, xRadius, yRadius, mode);
3922 drawPath(path);
3923}
3924
3962{
3963#ifdef QT_DEBUG_DRAW
3964 if (qt_show_painter_debug_output)
3965 printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
3966#endif
3967 Q_D(QPainter);
3968
3969 if (!d->engine) {
3970 qWarning("QPainter::drawEllipse: Painter not active");
3971 return;
3972 }
3973
3974 QRectF rect(r.normalized());
3975
3976 if (d->extended) {
3977 d->extended->drawEllipse(rect);
3978 return;
3979 }
3980
3981 d->updateState(d->state);
3982 if (d->state->emulationSpecifier) {
3983 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3984 && d->state->matrix.type() == QTransform::TxTranslate) {
3985 rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
3986 } else {
3988 path.addEllipse(rect);
3990 return;
3991 }
3992 }
3993
3994 d->engine->drawEllipse(rect);
3995}
3996
4005{
4006#ifdef QT_DEBUG_DRAW
4007 if (qt_show_painter_debug_output)
4008 printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
4009#endif
4010 Q_D(QPainter);
4011
4012 if (!d->engine) {
4013 qWarning("QPainter::drawEllipse: Painter not active");
4014 return;
4015 }
4016
4017 QRect rect(r.normalized());
4018
4019 if (d->extended) {
4020 d->extended->drawEllipse(rect);
4021 return;
4022 }
4023
4024 d->updateState(d->state);
4025
4026 if (d->state->emulationSpecifier) {
4027 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4028 && d->state->matrix.type() == QTransform::TxTranslate) {
4029 rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
4030 } else {
4032 path.addEllipse(rect);
4034 return;
4035 }
4036 }
4037
4038 d->engine->drawEllipse(rect);
4039}
4040
4092void QPainter::drawArc(const QRectF &r, int a, int alen)
4093{
4094#ifdef QT_DEBUG_DRAW
4095 if (qt_show_painter_debug_output)
4096 printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4097 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4098#endif
4099 Q_D(QPainter);
4100
4101 if (!d->engine) {
4102 qWarning("QPainter::drawArc: Painter not active");
4103 return;
4104 }
4105
4106 QRectF rect = r.normalized();
4107
4109 path.arcMoveTo(rect, a/16.0);
4110 path.arcTo(rect, a/16.0, alen/16.0);
4111 strokePath(path, d->state->pen);
4112}
4113
4156void QPainter::drawPie(const QRectF &r, int a, int alen)
4157{
4158#ifdef QT_DEBUG_DRAW
4159 if (qt_show_painter_debug_output)
4160 printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4161 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4162#endif
4163 Q_D(QPainter);
4164
4165 if (!d->engine) {
4166 qWarning("QPainter::drawPie: Painter not active");
4167 return;
4168 }
4169
4170 if (a > (360*16)) {
4171 a = a % (360*16);
4172 } else if (a < 0) {
4173 a = a % (360*16);
4174 if (a < 0) a += (360*16);
4175 }
4176
4177 QRectF rect = r.normalized();
4178
4180 path.moveTo(rect.center());
4181 path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/16.0, alen/16.0);
4182 path.closeSubpath();
4183 drawPath(path);
4184
4185}
4186
4227void QPainter::drawChord(const QRectF &r, int a, int alen)
4228{
4229#ifdef QT_DEBUG_DRAW
4230 if (qt_show_painter_debug_output)
4231 printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4232 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4233#endif
4234 Q_D(QPainter);
4235
4236 if (!d->engine) {
4237 qWarning("QPainter::drawChord: Painter not active");
4238 return;
4239 }
4240
4241 QRectF rect = r.normalized();
4242
4244 path.arcMoveTo(rect, a/16.0);
4245 path.arcTo(rect, a/16.0, alen/16.0);
4246 path.closeSubpath();
4247 drawPath(path);
4248}
4276void QPainter::drawLines(const QLineF *lines, int lineCount)
4277{
4278#ifdef QT_DEBUG_DRAW
4279 if (qt_show_painter_debug_output)
4280 printf("QPainter::drawLines(), line count=%d\n", lineCount);
4281#endif
4282
4283 Q_D(QPainter);
4284
4285 if (!d->engine || lineCount < 1)
4286 return;
4287
4288 if (d->extended) {
4289 d->extended->drawLines(lines, lineCount);
4290 return;
4291 }
4292
4293 d->updateState(d->state);
4294
4295 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4296
4297 if (lineEmulation) {
4298 if (lineEmulation == QPaintEngine::PrimitiveTransform
4299 && d->state->matrix.type() == QTransform::TxTranslate) {
4300 for (int i = 0; i < lineCount; ++i) {
4301 QLineF line = lines[i];
4302 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4303 d->engine->drawLines(&line, 1);
4304 }
4305 } else {
4306 QPainterPath linePath;
4307 for (int i = 0; i < lineCount; ++i) {
4308 linePath.moveTo(lines[i].p1());
4309 linePath.lineTo(lines[i].p2());
4310 }
4311 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4312 }
4313 return;
4314 }
4315 d->engine->drawLines(lines, lineCount);
4316}
4317
4325void QPainter::drawLines(const QLine *lines, int lineCount)
4326{
4327#ifdef QT_DEBUG_DRAW
4328 if (qt_show_painter_debug_output)
4329 printf("QPainter::drawLine(), line count=%d\n", lineCount);
4330#endif
4331
4332 Q_D(QPainter);
4333
4334 if (!d->engine || lineCount < 1)
4335 return;
4336
4337 if (d->extended) {
4338 d->extended->drawLines(lines, lineCount);
4339 return;
4340 }
4341
4342 d->updateState(d->state);
4343
4344 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4345
4346 if (lineEmulation) {
4347 if (lineEmulation == QPaintEngine::PrimitiveTransform
4348 && d->state->matrix.type() == QTransform::TxTranslate) {
4349 for (int i = 0; i < lineCount; ++i) {
4350 QLineF line = lines[i];
4351 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4352 d->engine->drawLines(&line, 1);
4353 }
4354 } else {
4355 QPainterPath linePath;
4356 for (int i = 0; i < lineCount; ++i) {
4357 linePath.moveTo(lines[i].p1());
4358 linePath.lineTo(lines[i].p2());
4359 }
4360 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4361 }
4362 return;
4363 }
4364 d->engine->drawLines(lines, lineCount);
4365}
4366
4375void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
4376{
4377 Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
4378
4379 drawLines((const QLineF*)pointPairs, lineCount);
4380}
4381
4388void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
4389{
4390 Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
4391
4392 drawLines((const QLine*)pointPairs, lineCount);
4393}
4394
4395
4444void QPainter::drawPolyline(const QPointF *points, int pointCount)
4445{
4446#ifdef QT_DEBUG_DRAW
4447 if (qt_show_painter_debug_output)
4448 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4449#endif
4450 Q_D(QPainter);
4451
4452 if (!d->engine || pointCount < 2)
4453 return;
4454
4455 if (d->extended) {
4456 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4457 return;
4458 }
4459
4460 d->updateState(d->state);
4461
4462 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4463
4464 if (lineEmulation) {
4465 // ###
4466// if (lineEmulation == QPaintEngine::PrimitiveTransform
4467// && d->state->matrix.type() == QTransform::TxTranslate) {
4468// } else {
4469 QPainterPath polylinePath(points[0]);
4470 for (int i=1; i<pointCount; ++i)
4471 polylinePath.lineTo(points[i]);
4472 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4473// }
4474 } else {
4475 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4476 }
4477}
4478
4485void QPainter::drawPolyline(const QPoint *points, int pointCount)
4486{
4487#ifdef QT_DEBUG_DRAW
4488 if (qt_show_painter_debug_output)
4489 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4490#endif
4491 Q_D(QPainter);
4492
4493 if (!d->engine || pointCount < 2)
4494 return;
4495
4496 if (d->extended) {
4497 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4498 return;
4499 }
4500
4501 d->updateState(d->state);
4502
4503 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4504
4505 if (lineEmulation) {
4506 // ###
4507// if (lineEmulation == QPaintEngine::PrimitiveTransform
4508// && d->state->matrix.type() == QTransform::TxTranslate) {
4509// } else {
4510 QPainterPath polylinePath(points[0]);
4511 for (int i=1; i<pointCount; ++i)
4512 polylinePath.lineTo(points[i]);
4513 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4514// }
4515 } else {
4516 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4517 }
4518}
4519
4560void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
4561{
4562#ifdef QT_DEBUG_DRAW
4563 if (qt_show_painter_debug_output)
4564 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4565#endif
4566
4567 Q_D(QPainter);
4568
4569 if (!d->engine || pointCount < 2)
4570 return;
4571
4572 if (d->extended) {
4573 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4574 return;
4575 }
4576
4577 d->updateState(d->state);
4578
4579 uint emulationSpecifier = d->state->emulationSpecifier;
4580
4581 if (emulationSpecifier) {
4582 QPainterPath polygonPath(points[0]);
4583 for (int i=1; i<pointCount; ++i)
4584 polygonPath.lineTo(points[i]);
4585 polygonPath.closeSubpath();
4586 polygonPath.setFillRule(fillRule);
4587 d->draw_helper(polygonPath);
4588 return;
4589 }
4590
4591 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4592}
4593
4599void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
4600{
4601#ifdef QT_DEBUG_DRAW
4602 if (qt_show_painter_debug_output)
4603 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4604#endif
4605
4606 Q_D(QPainter);
4607
4608 if (!d->engine || pointCount < 2)
4609 return;
4610
4611 if (d->extended) {
4612 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4613 return;
4614 }
4615
4616 d->updateState(d->state);
4617
4618 uint emulationSpecifier = d->state->emulationSpecifier;
4619
4620 if (emulationSpecifier) {
4621 QPainterPath polygonPath(points[0]);
4622 for (int i=1; i<pointCount; ++i)
4623 polygonPath.lineTo(points[i]);
4624 polygonPath.closeSubpath();
4625 polygonPath.setFillRule(fillRule);
4626 d->draw_helper(polygonPath);
4627 return;
4628 }
4629
4630 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4631}
4632
4698void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
4699{
4700#ifdef QT_DEBUG_DRAW
4701 if (qt_show_painter_debug_output)
4702 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4703#endif
4704
4705 Q_D(QPainter);
4706
4707 if (!d->engine || pointCount < 2)
4708 return;
4709
4710 if (d->extended) {
4711 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4712 return;
4713 }
4714
4715 d->updateState(d->state);
4716
4717 uint emulationSpecifier = d->state->emulationSpecifier;
4718
4719 if (emulationSpecifier) {
4720 QPainterPath polygonPath(points[0]);
4721 for (int i=1; i<pointCount; ++i)
4722 polygonPath.lineTo(points[i]);
4723 polygonPath.closeSubpath();
4724 polygonPath.setFillRule(Qt::WindingFill);
4725 d->draw_helper(polygonPath);
4726 return;
4727 }
4728
4729 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4730}
4731
4732void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
4733{
4734#ifdef QT_DEBUG_DRAW
4735 if (qt_show_painter_debug_output)
4736 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4737#endif
4738
4739 Q_D(QPainter);
4740
4741 if (!d->engine || pointCount < 2)
4742 return;
4743
4744 if (d->extended) {
4745 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4746 return;
4747 }
4748
4749 d->updateState(d->state);
4750
4751 uint emulationSpecifier = d->state->emulationSpecifier;
4752
4753 if (emulationSpecifier) {
4754 QPainterPath polygonPath(points[0]);
4755 for (int i=1; i<pointCount; ++i)
4756 polygonPath.lineTo(points[i]);
4757 polygonPath.closeSubpath();
4758 polygonPath.setFillRule(Qt::WindingFill);
4759 d->draw_helper(polygonPath);
4760 return;
4761 }
4762
4763 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4764}
4765
4767{
4768 return m.inverted().map(QPointF(m.map(p).toPoint()));
4769}
4770
4796void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
4797{
4798#if defined QT_DEBUG_DRAW
4799 if (qt_show_painter_debug_output)
4800 printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4801 p.x(), p.y(),
4802 pm.width(), pm.height());
4803#endif
4804
4805 Q_D(QPainter);
4806
4807 if (!d->engine || pm.isNull())
4808 return;
4809
4810#ifndef QT_NO_DEBUG
4811 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4812#endif
4813
4814 if (d->extended) {
4815 d->extended->drawPixmap(p, pm);
4816 return;
4817 }
4818
4819 qreal x = p.x();
4820 qreal y = p.y();
4821
4822 int w = pm.width();
4823 int h = pm.height();
4824
4825 if (w <= 0)
4826 return;
4827
4828 // Emulate opaque background for bitmaps
4829 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4830 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4831 }
4832
4833 d->updateState(d->state);
4834
4835 if ((d->state->matrix.type() > QTransform::TxTranslate
4836 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4837 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4838 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4839 {
4840 save();
4841 // If there is no rotation involved we have to make sure we use the
4842 // antialiased and not the aliased coordinate system by rounding the coordinates.
4843 if (d->state->matrix.type() <= QTransform::TxScale) {
4844 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4845 x = p.x();
4846 y = p.y();
4847 }
4848 translate(x, y);
4851 QBrush brush(d->state->pen.color(), pm);
4852 setBrush(brush);
4854 setBrushOrigin(QPointF(0, 0));
4855
4856 drawRect(pm.rect());
4857 restore();
4858 } else {
4859 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4860 x += d->state->matrix.dx();
4861 y += d->state->matrix.dy();
4862 }
4864 d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4865 }
4866}
4867
4868void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
4869{
4870#if defined QT_DEBUG_DRAW
4871 if (qt_show_painter_debug_output)
4872 printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4873 r.x(), r.y(), r.width(), r.height(),
4874 pm.width(), pm.height(),
4875 sr.x(), sr.y(), sr.width(), sr.height());
4876#endif
4877
4878 Q_D(QPainter);
4879 if (!d->engine || pm.isNull())
4880 return;
4881#ifndef QT_NO_DEBUG
4882 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4883#endif
4884
4885 qreal x = r.x();
4886 qreal y = r.y();
4887 qreal w = r.width();
4888 qreal h = r.height();
4889 qreal sx = sr.x();
4890 qreal sy = sr.y();
4891 qreal sw = sr.width();
4892 qreal sh = sr.height();
4893
4894 // Get pixmap scale. Use it when calculating the target
4895 // rect size from pixmap size. For example, a 2X 64x64 pixel
4896 // pixmap should result in a 32x32 point target rect.
4897 const qreal pmscale = pm.devicePixelRatio();
4898
4899 // Sanity-check clipping
4900 if (sw <= 0)
4901 sw = pm.width() - sx;
4902
4903 if (sh <= 0)
4904 sh = pm.height() - sy;
4905
4906 if (w < 0)
4907 w = sw / pmscale;
4908 if (h < 0)
4909 h = sh / pmscale;
4910
4911 if (sx < 0) {
4912 qreal w_ratio = sx * w/sw;
4913 x -= w_ratio;
4914 w += w_ratio;
4915 sw += sx;
4916 sx = 0;
4917 }
4918
4919 if (sy < 0) {
4920 qreal h_ratio = sy * h/sh;
4921 y -= h_ratio;
4922 h += h_ratio;
4923 sh += sy;
4924 sy = 0;
4925 }
4926
4927 if (sw + sx > pm.width()) {
4928 qreal delta = sw - (pm.width() - sx);
4929 qreal w_ratio = delta * w/sw;
4930 sw -= delta;
4931 w -= w_ratio;
4932 }
4933
4934 if (sh + sy > pm.height()) {
4935 qreal delta = sh - (pm.height() - sy);
4936 qreal h_ratio = delta * h/sh;
4937 sh -= delta;
4938 h -= h_ratio;
4939 }
4940
4941 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
4942 return;
4943
4944 if (d->extended) {
4945 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
4946 return;
4947 }
4948
4949 // Emulate opaque background for bitmaps
4950 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
4951 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4952
4953 d->updateState(d->state);
4954
4955 if ((d->state->matrix.type() > QTransform::TxTranslate
4956 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4957 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4958 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
4959 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
4960 {
4961 save();
4962 // If there is no rotation involved we have to make sure we use the
4963 // antialiased and not the aliased coordinate system by rounding the coordinates.
4964 if (d->state->matrix.type() <= QTransform::TxScale) {
4965 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4966 x = p.x();
4967 y = p.y();
4968 }
4969
4970 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
4971 sx = qRound(sx);
4972 sy = qRound(sy);
4973 sw = qRound(sw);
4974 sh = qRound(sh);
4975 }
4976
4977 translate(x, y);
4978 scale(w / sw, h / sh);
4981 QBrush brush;
4982
4983 if (sw == pm.width() && sh == pm.height())
4984 brush = QBrush(d->state->pen.color(), pm);
4985 else
4986 brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
4987
4988 setBrush(brush);
4990
4991 drawRect(QRectF(0, 0, sw, sh));
4992 restore();
4993 } else {
4994 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4995 x += d->state->matrix.dx();
4996 y += d->state->matrix.dy();
4997 }
4998 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
4999 }
5000}
5001
5002
5106{
5107 Q_D(QPainter);
5108
5109 if (!d->engine || image.isNull())
5110 return;
5111
5112 if (d->extended) {
5113 d->extended->drawImage(p, image);
5114 return;
5115 }
5116
5117 qreal x = p.x();
5118 qreal y = p.y();
5119
5120 int w = image.width();
5121 int h = image.height();
5122 qreal scale = image.devicePixelRatio();
5123
5124 d->updateState(d->state);
5125
5126 if (((d->state->matrix.type() > QTransform::TxTranslate)
5127 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5128 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5129 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5130 {
5131 save();
5132 // If there is no rotation involved we have to make sure we use the
5133 // antialiased and not the aliased coordinate system by rounding the coordinates.
5134 if (d->state->matrix.type() <= QTransform::TxScale) {
5135 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5136 x = p.x();
5137 y = p.y();
5138 }
5139 translate(x, y);
5143 setBrush(brush);
5145 setBrushOrigin(QPointF(0, 0));
5146 drawRect(QRect(QPoint(0, 0), image.size() / scale));
5147 restore();
5148 return;
5149 }
5150
5151 if (d->state->matrix.type() == QTransform::TxTranslate
5152 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5153 x += d->state->matrix.dx();
5154 y += d->state->matrix.dy();
5155 }
5156
5157 d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5158}
5159
5160void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
5161 Qt::ImageConversionFlags flags)
5162{
5163 Q_D(QPainter);
5164
5165 if (!d->engine || image.isNull())
5166 return;
5167
5168 qreal x = targetRect.x();
5169 qreal y = targetRect.y();
5170 qreal w = targetRect.width();
5171 qreal h = targetRect.height();
5172 qreal sx = sourceRect.x();
5173 qreal sy = sourceRect.y();
5174 qreal sw = sourceRect.width();
5175 qreal sh = sourceRect.height();
5176 qreal imageScale = image.devicePixelRatio();
5177
5178 // Sanity-check clipping
5179 if (sw <= 0)
5180 sw = image.width() - sx;
5181
5182 if (sh <= 0)
5183 sh = image.height() - sy;
5184
5185 if (w < 0)
5186 w = sw / imageScale;
5187 if (h < 0)
5188 h = sh / imageScale;
5189
5190 if (sx < 0) {
5191 qreal w_ratio = sx * w/sw;
5192 x -= w_ratio;
5193 w += w_ratio;
5194 sw += sx;
5195 sx = 0;
5196 }
5197
5198 if (sy < 0) {
5199 qreal h_ratio = sy * h/sh;
5200 y -= h_ratio;
5201 h += h_ratio;
5202 sh += sy;
5203 sy = 0;
5204 }
5205
5206 if (sw + sx > image.width()) {
5207 qreal delta = sw - (image.width() - sx);
5208 qreal w_ratio = delta * w/sw;
5209 sw -= delta;
5210 w -= w_ratio;
5211 }
5212
5213 if (sh + sy > image.height()) {
5214 qreal delta = sh - (image.height() - sy);
5215 qreal h_ratio = delta * h/sh;
5216 sh -= delta;
5217 h -= h_ratio;
5218 }
5219
5220 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5221 return;
5222
5223 if (d->extended) {
5224 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5225 return;
5226 }
5227
5228 d->updateState(d->state);
5229
5230 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5231 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5232 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5233 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5234 {
5235 save();
5236 // If there is no rotation involved we have to make sure we use the
5237 // antialiased and not the aliased coordinate system by rounding the coordinates.
5238 if (d->state->matrix.type() <= QTransform::TxScale) {
5239 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5240 x = p.x();
5241 y = p.y();
5242 }
5243
5244 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5245 sx = qRound(sx);
5246 sy = qRound(sy);
5247 sw = qRound(sw);
5248 sh = qRound(sh);
5249 }
5250 translate(x, y);
5251 scale(w / sw, h / sh);
5255 setBrush(brush);
5257 setBrushOrigin(QPointF(-sx, -sy));
5258
5259 drawRect(QRectF(0, 0, sw, sh));
5260 restore();
5261 return;
5262 }
5263
5264 if (d->state->matrix.type() == QTransform::TxTranslate
5265 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5266 x += d->state->matrix.dx();
5267 y += d->state->matrix.dy();
5268 }
5269
5270 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5271}
5272
5284#if !defined(QT_NO_RAWFONT)
5286{
5287 Q_D(QPainter);
5288
5289 if (!d->engine) {
5290 qWarning("QPainter::drawGlyphRun: Painter not active");
5291 return;
5292 }
5293
5294 QRawFont font = glyphRun.rawFont();
5295 if (!font.isValid())
5296 return;
5297
5298 QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5299
5300 const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5301 const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5302
5303 int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5304 QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5305
5307 bool engineRequiresPretransformedGlyphPositions = d->extended
5308 ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5309 : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5310
5311 for (int i=0; i<count; ++i) {
5312 QPointF processedPosition = position + glyphPositions[i];
5313 if (engineRequiresPretransformedGlyphPositions)
5314 processedPosition = d->state->transform().map(processedPosition);
5315 fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5316 }
5317
5318 d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5319 ? d->state->transform().map(position)
5320 : position,
5321 glyphIndexes,
5322 fixedPointPositions.data(),
5323 count,
5324 fontD->fontEngine,
5325 glyphRun.overline(),
5326 glyphRun.underline(),
5327 glyphRun.strikeOut());
5328}
5329
5330void QPainterPrivate::drawGlyphs(const QPointF &decorationPosition,
5331 const quint32 *glyphArray,
5333 int glyphCount,
5334 QFontEngine *fontEngine,
5335 bool overline,
5336 bool underline,
5337 bool strikeOut)
5338{
5339 Q_Q(QPainter);
5340
5342
5343 if (extended != nullptr && state->matrix.isAffine()) {
5344 QStaticTextItem staticTextItem;
5345 staticTextItem.color = state->pen.color();
5346 staticTextItem.font = state->font;
5347 staticTextItem.setFontEngine(fontEngine);
5348 staticTextItem.numGlyphs = glyphCount;
5349 staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray));
5350 staticTextItem.glyphPositions = positions;
5351 // The font property is meaningless, the fontengine must be used directly:
5352 staticTextItem.usesRawFont = true;
5353
5354 extended->drawStaticTextItem(&staticTextItem);
5355 } else {
5356 QTextItemInt textItem;
5357 textItem.fontEngine = fontEngine;
5358
5359 QVarLengthArray<QFixed, 128> advances(glyphCount);
5360 QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5361 QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5362 memset(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(QGlyphAttributes));
5363 memset(static_cast<void *>(advances.data()), 0, advances.size() * sizeof(QFixed));
5364 memset(static_cast<void *>(glyphJustifications.data()), 0, glyphJustifications.size() * sizeof(QGlyphJustification));
5365
5366 textItem.glyphs.numGlyphs = glyphCount;
5367 textItem.glyphs.glyphs = const_cast<glyph_t *>(glyphArray);
5368 textItem.glyphs.offsets = positions;
5369 textItem.glyphs.advances = advances.data();
5370 textItem.glyphs.justifications = glyphJustifications.data();
5371 textItem.glyphs.attributes = glyphAttributes.data();
5372
5373 engine->drawTextItem(QPointF(0, 0), textItem);
5374 }
5375
5377 decorationPosition,
5378 glyphArray,
5379 positions,
5380 glyphCount,
5381 fontEngine,
5382 underline,
5383 overline,
5384 strikeOut);
5385}
5386#endif // QT_NO_RAWFONT
5387
5430{
5431 drawText(p, str, 0, 0);
5432}
5433
5455void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
5456{
5457 Q_D(QPainter);
5458 if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5459 return;
5460
5461 QStaticTextPrivate *staticText_d =
5462 const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5463
5465 QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5466 if (font() != staticText_d->font || fp == nullptr || stfp == nullptr || fp->dpi != stfp->dpi) {
5467 staticText_d->font = font();
5468 staticText_d->needsRelayout = true;
5469 } else if (stfp->engineData == nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5470 staticText_d->needsRelayout = true;
5471 }
5472
5473 QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5474 if (fe->type() == QFontEngine::Multi)
5475 fe = static_cast<QFontEngineMulti *>(fe)->engine(0);
5476
5477 // If we don't have an extended paint engine, if the painter is projected,
5478 // or if the font engine does not support the matrix, we go through standard
5479 // code path
5480 if (d->extended == nullptr
5481 || !d->state->matrix.isAffine()
5482 || !fe->supportsTransformation(d->state->matrix)) {
5483 staticText_d->paintText(topLeftPosition, this, pen().color());
5484 return;
5485 }
5486
5487 bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5488 if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5489 // The coordinates are untransformed, and the engine can't deal with that
5490 // nativly, so we have to pre-transform the static text.
5491 staticText_d->untransformedCoordinates = false;
5492 staticText_d->needsRelayout = true;
5493 } else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5494 // The coordinates are already transformed, but the engine can handle that
5495 // nativly, so undo the transform of the static text.
5496 staticText_d->untransformedCoordinates = true;
5497 staticText_d->needsRelayout = true;
5498 }
5499
5500 // Don't recalculate entire layout because of translation, rather add the dx and dy
5501 // into the position to move each text item the correct distance.
5502 QPointF transformedPosition = topLeftPosition;
5503 if (!staticText_d->untransformedCoordinates)
5504 transformedPosition = transformedPosition * d->state->matrix;
5505 QTransform oldMatrix;
5506
5507 // The translation has been applied to transformedPosition. Remove translation
5508 // component from matrix.
5509 if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5510 qreal m11 = d->state->matrix.m11();
5511 qreal m12 = d->state->matrix.m12();
5512 qreal m13 = d->state->matrix.m13();
5513 qreal m21 = d->state->matrix.m21();
5514 qreal m22 = d->state->matrix.m22();
5515 qreal m23 = d->state->matrix.m23();
5516 qreal m33 = d->state->matrix.m33();
5517
5518 oldMatrix = d->state->matrix;
5519 d->state->matrix.setMatrix(m11, m12, m13,
5520 m21, m22, m23,
5521 0.0, 0.0, m33);
5522 }
5523
5524 // If the transform is not identical to the text transform,
5525 // we have to relayout the text (for other transformations than plain translation)
5526 bool staticTextNeedsReinit = staticText_d->needsRelayout;
5527 if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5528 staticText_d->matrix = d->state->matrix;
5529 staticTextNeedsReinit = true;
5530 }
5531
5532 // Recreate the layout of the static text because the matrix or font has changed
5533 if (staticTextNeedsReinit)
5534 staticText_d->init();
5535
5536 if (transformedPosition != staticText_d->position) { // Translate to actual position
5537 QFixed fx = QFixed::fromReal(transformedPosition.x());
5538 QFixed fy = QFixed::fromReal(transformedPosition.y());
5539 QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5540 QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5541 for (int item=0; item<staticText_d->itemCount;++item) {
5542 QStaticTextItem *textItem = staticText_d->items + item;
5543 for (int i=0; i<textItem->numGlyphs; ++i) {
5544 textItem->glyphPositions[i].x += fx - oldX;
5545 textItem->glyphPositions[i].y += fy - oldY;
5546 }
5547 textItem->userDataNeedsUpdate = true;
5548 }
5549
5550 staticText_d->position = transformedPosition;
5551 }
5552
5553 QPen oldPen = d->state->pen;
5554 QColor currentColor = oldPen.color();
5555 static const QColor bodyIndicator(0, 0, 0, 0);
5556 for (int i=0; i<staticText_d->itemCount; ++i) {
5557 QStaticTextItem *item = staticText_d->items + i;
5558 if (item->color.isValid() && currentColor != item->color
5559 && item->color != bodyIndicator) {
5560 setPen(item->color);
5561 currentColor = item->color;
5562 } else if (item->color == bodyIndicator) {
5563 setPen(oldPen);
5564 currentColor = oldPen.color();
5565 }
5566 d->extended->drawStaticTextItem(item);
5567
5569 topLeftPosition,
5570 item->glyphs,
5571 item->glyphPositions,
5572 item->numGlyphs,
5573 item->fontEngine(),
5574 staticText_d->font.underline(),
5575 staticText_d->font.overline(),
5576 staticText_d->font.strikeOut());
5577 }
5578 if (currentColor != oldPen.color())
5579 setPen(oldPen);
5580
5581 if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5582 d->state->matrix = oldMatrix;
5583}
5584
5588void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
5589{
5590#ifdef QT_DEBUG_DRAW
5591 if (qt_show_painter_debug_output)
5592 printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5593#endif
5594
5595 Q_D(QPainter);
5596
5597 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5598 return;
5599
5600 QStackTextEngine engine(str, d->state->font);
5601 engine.option.setTextDirection(d->state->layoutDirection);
5603 engine.ignoreBidi = true;
5604 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5605 }
5606 engine.itemize();
5608 line.length = str.size();
5609 engine.shapeLine(line);
5610
5611 int nItems = engine.layoutData->items.size();
5612 QVarLengthArray<int> visualOrder(nItems);
5613 QVarLengthArray<uchar> levels(nItems);
5614 for (int i = 0; i < nItems; ++i)
5615 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5616 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5617
5618 if (justificationPadding > 0) {
5619 engine.option.setAlignment(Qt::AlignJustify);
5620 engine.forceJustification = true;
5621 // this works because justify() is only interested in the difference between width and textWidth
5622 line.width = justificationPadding;
5623 engine.justify(line);
5624 }
5625 QFixed x = QFixed::fromReal(p.x());
5626
5627 for (int i = 0; i < nItems; ++i) {
5628 int item = visualOrder[i];
5629 const QScriptItem &si = engine.layoutData->items.at(item);
5631 x += si.width;
5632 continue;
5633 }
5634 QFont f = engine.font(si);
5635 QTextItemInt gf(si, &f);
5636 gf.glyphs = engine.shapedGlyphs(&si);
5637 gf.chars = engine.layoutData->string.unicode() + si.position;
5638 gf.num_chars = engine.length(item);
5639 if (engine.forceJustification) {
5640 for (int j=0; j<gf.glyphs.numGlyphs; ++j)
5641 gf.width += gf.glyphs.effectiveAdvance(j);
5642 } else {
5643 gf.width = si.width;
5644 }
5645 gf.logClusters = engine.logClusters(&si);
5646
5647 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5648
5649 x += gf.width;
5650 }
5651}
5652
5653void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
5654{
5655#ifdef QT_DEBUG_DRAW
5656 if (qt_show_painter_debug_output)
5657 printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
5658 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5659#endif
5660
5661 Q_D(QPainter);
5662
5663 if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5664 return;
5665
5666 if (!d->extended)
5667 d->updateState(d->state);
5668
5669 QRectF bounds;
5670 qt_format_text(d->state->font, r, flags, nullptr, str, br ? &bounds : nullptr, 0, nullptr, 0, this);
5671 if (br)
5672 *br = bounds.toAlignedRect();
5673}
5674
5740void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
5741{
5742#ifdef QT_DEBUG_DRAW
5743 if (qt_show_painter_debug_output)
5744 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
5745 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5746#endif
5747
5748 Q_D(QPainter);
5749
5750 if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5751 return;
5752
5753 if (!d->extended)
5754 d->updateState(d->state);
5755
5756 qt_format_text(d->state->font, r, flags, nullptr, str, br, 0, nullptr, 0, this);
5757}
5758
5860{
5861#ifdef QT_DEBUG_DRAW
5862 if (qt_show_painter_debug_output)
5863 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
5864 r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
5865#endif
5866
5867 Q_D(QPainter);
5868
5869 if (!d->engine || text.size() == 0 || pen().style() == Qt::NoPen)
5870 return;
5871
5872 if (!d->extended)
5873 d->updateState(d->state);
5874
5875 qt_format_text(d->state->font, r, 0, &o, text, nullptr, 0, nullptr, 0, this);
5876}
5877
5913static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
5914{
5915 const qreal radiusBase = qMax(qreal(1), maxRadius);
5916
5917 QString key = "WaveUnderline-"_L1
5918 % pen.color().name()
5919 % HexString<qreal>(radiusBase)
5920 % HexString<qreal>(pen.widthF());
5921
5924 return pixmap;
5925
5926 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio
5927 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
5928 const qreal radius = qFloor(radiusBase * 2) / 2.;
5929
5931
5932 qreal xs = 0;
5933 qreal ys = radius;
5934
5935 while (xs < width) {
5936 xs += halfPeriod;
5937 ys = -ys;
5938 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
5939 }
5940
5941 pixmap = QPixmap(width, radius * 2);
5942 pixmap.fill(Qt::transparent);
5943 {
5944 QPen wavePen = pen;
5945 wavePen.setCapStyle(Qt::SquareCap);
5946
5947 // This is to protect against making the line too fat, as happens on OS X
5948 // due to it having a rather thick width for the regular underline.
5949 const qreal maxPenWidth = .8 * radius;
5950 if (wavePen.widthF() > maxPenWidth)
5951 wavePen.setWidthF(maxPenWidth);
5952
5953 QPainter imgPainter(&pixmap);
5954 imgPainter.setPen(wavePen);
5955 imgPainter.setRenderHint(QPainter::Antialiasing);
5956 imgPainter.translate(0, radius);
5957 imgPainter.drawPath(path);
5958 }
5959
5961
5962 return pixmap;
5963}
5964
5965static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine,
5966 QTextCharFormat::UnderlineStyle underlineStyle,
5967 QTextItem::RenderFlags flags, qreal width,
5968 const QTextCharFormat &charFormat)
5969{
5970 if (underlineStyle == QTextCharFormat::NoUnderline
5972 return;
5973
5974 const QPen oldPen = painter->pen();
5975 const QBrush oldBrush = painter->brush();
5977 QPen pen = oldPen;
5979 pen.setWidthF(fe->lineThickness().toReal());
5981
5982 QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
5983
5984 const qreal underlineOffset = fe->underlinePosition().toReal();
5985
5986 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
5988 if (theme)
5990 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved
5991 underlineStyle = QTextCharFormat::WaveUnderline;
5992 }
5993
5994 if (underlineStyle == QTextCharFormat::WaveUnderline) {
5995 painter->save();
5996 painter->translate(0, pos.y() + 1);
5997 qreal maxHeight = fe->descent().toReal() - qreal(1);
5998
5999 QColor uc = charFormat.underlineColor();
6000 if (uc.isValid())
6001 pen.setColor(uc);
6002
6003 // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
6004 const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
6005 const int descent = qFloor(maxHeight);
6006
6008 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
6009 painter->restore();
6010 } else if (underlineStyle != QTextCharFormat::NoUnderline) {
6011 // Deliberately ceil the offset to avoid the underline coming too close to
6012 // the text above it, but limit it to stay within descent.
6013 qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + 0.5;
6014 if (underlineOffset <= fe->descent().toReal())
6015 adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - qreal(0.5));
6016 const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6017 QColor uc = charFormat.underlineColor();
6018 if (uc.isValid())
6019 pen.setColor(uc);
6020
6021 pen.setStyle((Qt::PenStyle)(underlineStyle));
6022 painter->setPen(pen);
6023 QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6024 if (textEngine)
6025 textEngine->addUnderline(painter, underline);
6026 else
6027 painter->drawLine(underline);
6028 }
6029
6031 pen.setColor(oldPen.color());
6032
6034 QLineF strikeOutLine = line;
6035 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6036 QColor uc = charFormat.underlineColor();
6037 if (uc.isValid())
6038 pen.setColor(uc);
6039 painter->setPen(pen);
6040 if (textEngine)
6041 textEngine->addStrikeOut(painter, strikeOutLine);
6042 else
6043 painter->drawLine(strikeOutLine);
6044 }
6045
6046 if (flags & QTextItem::Overline) {
6047 QLineF overline = line;
6048 overline.translate(0., - fe->ascent().toReal());
6049 QColor uc = charFormat.underlineColor();
6050 if (uc.isValid())
6051 pen.setColor(uc);
6052 painter->setPen(pen);
6053 if (textEngine)
6054 textEngine->addOverline(painter, overline);
6055 else
6056 painter->drawLine(overline);
6057 }
6058
6059 painter->setPen(oldPen);
6060 painter->setBrush(oldBrush);
6061}
6062
6064 const QPointF &decorationPosition,
6065 const glyph_t *glyphArray,
6066 const QFixedPoint *positions,
6067 int glyphCount,
6068 QFontEngine *fontEngine,
6069 bool underline,
6070 bool overline,
6071 bool strikeOut)
6072{
6073 if (!underline && !overline && !strikeOut)
6074 return;
6075
6076 QTextItem::RenderFlags flags;
6077 if (underline)
6079 if (overline)
6081 if (strikeOut)
6083
6084 bool rtl = positions[glyphCount - 1].x < positions[0].x;
6085 QFixed baseline = positions[0].y;
6086 glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[rtl ? 0 : glyphCount - 1]);
6087
6088 qreal width = rtl
6089 ? (positions[0].x + gm.xoff - positions[glyphCount - 1].x).toReal()
6090 : (positions[glyphCount - 1].x + gm.xoff - positions[0].x).toReal();
6091
6093 QPointF(decorationPosition.x(), baseline.toReal()),
6094 fontEngine,
6095 nullptr, // textEngine
6098 flags,
6099 width,
6100 QTextCharFormat());
6101}
6102
6104{
6105 Q_D(QPainter);
6106
6107 d->drawTextItem(p, ti, static_cast<QTextEngine *>(nullptr));
6108}
6109
6110void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine)
6111{
6112#ifdef QT_DEBUG_DRAW
6113 if (qt_show_painter_debug_output)
6114 printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6115 p.x(), p.y(), qPrintable(_ti.text()));
6116#endif
6117
6118 Q_Q(QPainter);
6119
6120 if (!engine)
6121 return;
6122
6123 QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
6124
6125 if (!extended && state->bgMode == Qt::OpaqueMode) {
6126 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6127 q->fillRect(rect, state->bgBrush);
6128 }
6129
6130 if (q->pen().style() == Qt::NoPen)
6131 return;
6132
6133 const QPainter::RenderHints oldRenderHints = state->renderHints;
6134 if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6135 // draw antialias decoration (underline/overline/strikeout) with
6136 // transformed text
6137
6138 bool aa = true;
6139 const QTransform &m = state->matrix;
6140 if (state->matrix.type() < QTransform::TxShear) {
6141 bool isPlain90DegreeRotation =
6142 (qFuzzyIsNull(m.m11())
6143 && qFuzzyIsNull(m.m12() - qreal(1))
6144 && qFuzzyIsNull(m.m21() + qreal(1))
6145 && qFuzzyIsNull(m.m22())
6146 )
6147 ||
6148 (qFuzzyIsNull(m.m11() + qreal(1))
6149 && qFuzzyIsNull(m.m12())
6150 && qFuzzyIsNull(m.m21())
6151 && qFuzzyIsNull(m.m22() + qreal(1))
6152 )
6153 ||
6154 (qFuzzyIsNull(m.m11())
6155 && qFuzzyIsNull(m.m12() + qreal(1))
6156 && qFuzzyIsNull(m.m21() - qreal(1))
6157 && qFuzzyIsNull(m.m22())
6158 )
6159 ;
6160 aa = !isPlain90DegreeRotation;
6161 }
6162 if (aa)
6163 q->setRenderHint(QPainter::Antialiasing, true);
6164 }
6165
6166 if (!extended)
6168
6169 if (!ti.glyphs.numGlyphs) {
6170 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6171 ti.flags, ti.width.toReal(), ti.charFormat);
6172 } else if (ti.fontEngine->type() == QFontEngine::Multi) {
6173 QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
6174
6175 const QGlyphLayout &glyphs = ti.glyphs;
6176 int which = glyphs.glyphs[0] >> 24;
6177
6178 qreal x = p.x();
6179 qreal y = p.y();
6180
6181 bool rtl = ti.flags & QTextItem::RightToLeft;
6182 if (rtl)
6183 x += ti.width.toReal();
6184
6185 int start = 0;
6186 int end, i;
6187 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6188 const int e = glyphs.glyphs[end] >> 24;
6189 if (e == which)
6190 continue;
6191
6192
6193 multi->ensureEngineAt(which);
6194 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6195 ti2.width = 0;
6196 // set the high byte to zero and calc the width
6197 for (i = start; i < end; ++i) {
6198 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6199 ti2.width += ti.glyphs.effectiveAdvance(i);
6200 }
6201
6202 if (rtl)
6203 x -= ti2.width.toReal();
6204
6205 if (extended)
6206 extended->drawTextItem(QPointF(x, y), ti2);
6207 else
6208 engine->drawTextItem(QPointF(x, y), ti2);
6209 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6210 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6211
6212 if (!rtl)
6213 x += ti2.width.toReal();
6214
6215 // reset the high byte for all glyphs and advance to the next sub-string
6216 const int hi = which << 24;
6217 for (i = start; i < end; ++i) {
6218 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6219 }
6220
6221 // change engine
6222 start = end;
6223 which = e;
6224 }
6225
6226 multi->ensureEngineAt(which);
6227 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6228 ti2.width = 0;
6229 // set the high byte to zero and calc the width
6230 for (i = start; i < end; ++i) {
6231 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6232 ti2.width += ti.glyphs.effectiveAdvance(i);
6233 }
6234
6235 if (rtl)
6236 x -= ti2.width.toReal();
6237
6238 if (extended)
6239 extended->drawTextItem(QPointF(x, y), ti2);
6240 else
6241 engine->drawTextItem(QPointF(x,y), ti2);
6242 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6243 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6244
6245 // reset the high byte for all glyphs
6246 const int hi = which << 24;
6247 for (i = start; i < end; ++i)
6248 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6249
6250 } else {
6251 if (extended)
6252 extended->drawTextItem(p, ti);
6253 else
6254 engine->drawTextItem(p, ti);
6255 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6256 ti.flags, ti.width.toReal(), ti.charFormat);
6257 }
6258
6259 if (state->renderHints != oldRenderHints) {
6260 state->renderHints = oldRenderHints;
6261 if (extended)
6263 else
6264 state->dirtyFlags |= QPaintEngine::DirtyHints;
6265 }
6266}
6267
6324{
6325 if (str.isEmpty())
6326 return QRect(rect.x(),rect.y(), 0,0);
6327 QRect brect;
6329 return brect;
6330}
6331
6332
6333
6335{
6336 if (str.isEmpty())
6337 return QRectF(rect.x(),rect.y(), 0,0);
6338 QRectF brect;
6340 return brect;
6341}
6342
6357{
6358 Q_D(QPainter);
6359
6360 if (!d->engine || text.size() == 0)
6361 return QRectF(r.x(),r.y(), 0,0);
6362
6363 QRectF br;
6364 qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, nullptr, 0, this);
6365 return br;
6366}
6367
6392{
6393#ifdef QT_DEBUG_DRAW
6394 if (qt_show_painter_debug_output)
6395 printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6396 r.x(), r.y(), r.width(), r.height(),
6397 pixmap.width(), pixmap.height(),
6398 sp.x(), sp.y());
6399#endif
6400
6401 Q_D(QPainter);
6402 if (!d->engine || pixmap.isNull() || r.isEmpty())
6403 return;
6404
6405#ifndef QT_NO_DEBUG
6406 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawTiledPixmap()");
6407#endif
6408
6409 qreal sw = pixmap.width();
6410 qreal sh = pixmap.height();
6411 qreal sx = sp.x();
6412 qreal sy = sp.y();
6413 if (sx < 0)
6414 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6415 else
6416 sx = qRound(sx) % qRound(sw);
6417 if (sy < 0)
6418 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6419 else
6420 sy = qRound(sy) % qRound(sh);
6421
6422
6423 if (d->extended) {
6424 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6425 return;
6426 }
6427
6428 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6429 fillRect(r, d->state->bgBrush);
6430
6431 d->updateState(d->state);
6432 if ((d->state->matrix.type() > QTransform::TxTranslate
6433 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6434 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6435 {
6436 save();
6439 setBrush(QBrush(d->state->pen.color(), pixmap));
6441
6442 // If there is no rotation involved we have to make sure we use the
6443 // antialiased and not the aliased coordinate system by rounding the coordinates.
6444 if (d->state->matrix.type() <= QTransform::TxScale) {
6445 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6446
6447 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6448 sx = qRound(sx);
6449 sy = qRound(sy);
6450 }
6451
6452 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6453 drawRect(QRectF(p, r.size()));
6454 } else {
6455 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6456 drawRect(r);
6457 }
6458 restore();
6459 return;
6460 }
6461
6462 qreal x = r.x();
6463 qreal y = r.y();
6464 if (d->state->matrix.type() == QTransform::TxTranslate
6465 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6466 x += d->state->matrix.dx();
6467 y += d->state->matrix.dy();
6468 }
6469
6470 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
6471}
6472
6495#ifndef QT_NO_PICTURE
6496
6522{
6523 Q_D(QPainter);
6524
6525 if (!d->engine) {
6526 qWarning("QPainter::drawPicture: Painter not active");
6527 return;
6528 }
6529
6530 if (!d->extended)
6531 d->updateState(d->state);
6532
6533 save();
6534 translate(p);
6535 const_cast<QPicture *>(&picture)->play(this);
6536 restore();
6537}
6538
6553#endif // QT_NO_PICTURE
6554
6565{
6566 Q_D(QPainter);
6567
6568 fillRect(r, d->state->bgBrush);
6569}
6570
6571static inline bool needsResolving(const QBrush &brush)
6572{
6573 Qt::BrushStyle s = brush.style();
6576 (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ||
6577 brush.gradient()->coordinateMode() == QGradient::ObjectMode));
6578}
6579
6636{
6637 Q_D(QPainter);
6638
6639 if (!d->engine) {
6640 qWarning("QPainter::fillRect: Painter not active");
6641 return;
6642 }
6643
6644 if (d->extended && !needsEmulation(brush)) {
6645 d->extended->fillRect(r, brush);
6646 return;
6647 }
6648
6649 QPen oldPen = pen();
6650 QBrush oldBrush = this->brush();
6652 if (brush.style() == Qt::SolidPattern) {
6653 d->colorBrush.setStyle(Qt::SolidPattern);
6654 d->colorBrush.setColor(brush.color());
6655 setBrush(d->colorBrush);
6656 } else {
6657 setBrush(brush);
6658 }
6659
6660 drawRect(r);
6661 setBrush(oldBrush);
6662 setPen(oldPen);
6663}
6664
6673{
6674 Q_D(QPainter);
6675
6676 if (!d->engine) {
6677 qWarning("QPainter::fillRect: Painter not active");
6678 return;
6679 }
6680
6681 if (d->extended && !needsEmulation(brush)) {
6682 d->extended->fillRect(r, brush);
6683 return;
6684 }
6685
6686 QPen oldPen = pen();
6687 QBrush oldBrush = this->brush();
6689 if (brush.style() == Qt::SolidPattern) {
6690 d->colorBrush.setStyle(Qt::SolidPattern);
6691 d->colorBrush.setColor(brush.color());
6692 setBrush(d->colorBrush);
6693 } else {
6694 setBrush(brush);
6695 }
6696
6697 drawRect(r);
6698 setBrush(oldBrush);
6699 setPen(oldPen);
6700}
6701
6702
6703
6713{
6714 Q_D(QPainter);
6715
6716 if (!d->engine) {
6717 qWarning("QPainter::fillRect: Painter not active");
6718 return;
6719 }
6720
6721 if (d->extended) {
6722 d->extended->fillRect(r, color);
6723 return;
6724 }
6725
6727}
6728
6729
6739{
6740 Q_D(QPainter);
6741
6742 if (!d->engine)
6743 return;
6744
6745 if (d->extended) {
6746 d->extended->fillRect(r, color);
6747 return;
6748 }
6749
6751}
6752
6843{
6844#ifdef QT_DEBUG_DRAW
6845 if (qt_show_painter_debug_output)
6846 printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
6847#endif
6848
6849#ifndef QT_NO_DEBUG
6850 static const bool antialiasingDisabled = qEnvironmentVariableIntValue("QT_NO_ANTIALIASING");
6851 if (hint == QPainter::Antialiasing && antialiasingDisabled)
6852 return;
6853#endif
6854
6855 setRenderHints(hint, on);
6856}
6857
6868void QPainter::setRenderHints(RenderHints hints, bool on)
6869{
6870 Q_D(QPainter);
6871
6872 if (!d->engine) {
6873 qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
6874 return;
6875 }
6876
6877 if (on)
6878 d->state->renderHints |= hints;
6879 else
6880 d->state->renderHints &= ~hints;
6881
6882 if (d->extended)
6883 d->extended->renderHintsChanged();
6884 else
6885 d->state->dirtyFlags |= QPaintEngine::DirtyHints;
6886}
6887
6894QPainter::RenderHints QPainter::renderHints() const
6895{
6896 Q_D(const QPainter);
6897
6898 if (!d->engine)
6899 return { };
6900
6901 return d->state->renderHints;
6902}
6903
6921{
6922 Q_D(const QPainter);
6923 if (!d->engine) {
6924 qWarning("QPainter::viewTransformEnabled: Painter not active");
6925 return false;
6926 }
6927 return d->state->VxF;
6928}
6929
6956{
6957#ifdef QT_DEBUG_DRAW
6958 if (qt_show_painter_debug_output)
6959 printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
6960#endif
6961
6962 Q_D(QPainter);
6963
6964 if (!d->engine) {
6965 qWarning("QPainter::setWindow: Painter not active");
6966 return;
6967 }
6968
6969 d->state->wx = r.x();
6970 d->state->wy = r.y();
6971 d->state->ww = r.width();
6972 d->state->wh = r.height();
6973
6974 d->state->VxF = true;
6975 d->updateMatrix();
6976}
6977
6985{
6986 Q_D(const QPainter);
6987 if (!d->engine) {
6988 qWarning("QPainter::window: Painter not active");
6989 return QRect();
6990 }
6991 return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
6992}
6993
7020{
7021#ifdef QT_DEBUG_DRAW
7022 if (qt_show_painter_debug_output)
7023 printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
7024#endif
7025
7026 Q_D(QPainter);
7027
7028 if (!d->engine) {
7029 qWarning("QPainter::setViewport: Painter not active");
7030 return;
7031 }
7032
7033 d->state->vx = r.x();
7034 d->state->vy = r.y();
7035 d->state->vw = r.width();
7036 d->state->vh = r.height();
7037
7038 d->state->VxF = true;
7039 d->updateMatrix();
7040}
7041
7049{
7050 Q_D(const QPainter);
7051 if (!d->engine) {
7052 qWarning("QPainter::viewport: Painter not active");
7053 return QRect();
7054 }
7055 return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
7056}
7057
7067{
7068#ifdef QT_DEBUG_DRAW
7069 if (qt_show_painter_debug_output)
7070 printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
7071#endif
7072
7073 Q_D(QPainter);
7074
7075 if (!d->engine) {
7076 qWarning("QPainter::setViewTransformEnabled: Painter not active");
7077 return;
7078 }
7079
7080 if (enable == d->state->VxF)
7081 return;
7082
7083 d->state->VxF = enable;
7084 d->updateMatrix();
7085}
7086
7087void qt_format_text(const QFont &fnt, const QRectF &_r,
7088 int tf, const QString& str, QRectF *brect,
7089 int tabstops, int *ta, int tabarraylen,
7091{
7092 qt_format_text(fnt, _r,
7093 tf, nullptr, str, brect,
7094 tabstops, ta, tabarraylen,
7095 painter);
7096}
7097void qt_format_text(const QFont &fnt, const QRectF &_r,
7098 int tf, const QTextOption *option, const QString& str, QRectF *brect,
7099 int tabstops, int *ta, int tabarraylen,
7101{
7102
7103 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=nullptr) ); // we either have an option or flags
7104
7105 if (option) {
7106 tf |= option->alignment();
7107 if (option->wrapMode() != QTextOption::NoWrap)
7108 tf |= Qt::TextWordWrap;
7109
7112
7113 if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7114 tf |= Qt::TextExpandTabs;
7115 }
7116
7117 // we need to copy r here to protect against the case (&r == brect).
7118 QRectF r(_r);
7119
7120 bool dontclip = (tf & Qt::TextDontClip);
7121 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7122 bool singleline = (tf & Qt::TextSingleLine);
7123 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7124 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7125
7127 if (tf & Qt::TextForceLeftToRight)
7129 else if (tf & Qt::TextForceRightToLeft)
7131 else if (option)
7132 layout_direction = option->textDirection();
7133 else if (painter)
7135 else
7137
7139
7140 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7141 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7142 (((tf & Qt::AlignLeft) && !isRightToLeft) ||
7143 ((tf & Qt::AlignRight) && isRightToLeft)));
7144
7145 if (!painter)
7146 tf |= Qt::TextDontPrint;
7147
7148 uint maxUnderlines = 0;
7149
7150 QFontMetricsF fm(fnt);
7151 QString text = str;
7152 int offset = 0;
7153start_lengthVariant:
7154 bool hasMoreLengthVariants = false;
7155 // compatible behaviour to the old implementation. Replace
7156 // tabs by spaces
7157 int old_offset = offset;
7158 for (; offset < text.size(); offset++) {
7159 QChar chr = text.at(offset);
7160 if (chr == u'\r' || (singleline && chr == u'\n')) {
7161 text[offset] = u' ';
7162 } else if (chr == u'\n') {
7163 text[offset] = QChar::LineSeparator;
7164 } else if (chr == u'&') {
7165 ++maxUnderlines;
7166 } else if (chr == u'\t') {
7167 if (!expandtabs) {
7168 text[offset] = u' ';
7169 } else if (!tabarraylen && !tabstops) {
7170 tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7171 }
7172 } else if (chr == u'\x9c') {
7173 // string with multiple length variants
7174 hasMoreLengthVariants = true;
7175 break;
7176 }
7177 }
7178
7179 QList<QTextLayout::FormatRange> underlineFormats;
7180 int length = offset - old_offset;
7181 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7182 QChar *cout = text.data() + old_offset;
7183 QChar *cout0 = cout;
7184 QChar *cin = cout;
7185 int l = length;
7186 while (l) {
7187 if (*cin == u'&') {
7188 ++cin;
7189 --length;
7190 --l;
7191 if (!l)
7192 break;
7193 if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7195 range.start = cout - cout0;
7196 range.length = 1;
7197 range.format.setFontUnderline(true);
7198 underlineFormats.append(range);
7199 }
7200#ifdef Q_OS_MAC
7201 } else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7202 cin[1] == u'&' && cin[2] != u'&' &&
7203 cin[3] == u')') {
7204 int n = 0;
7205 while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7206 ++n;
7207 cout -= n;
7208 cin += 4;
7209 length -= n + 4;
7210 l -= 4;
7211 continue;
7212#endif //Q_OS_MAC
7213 }
7214 *cout = *cin;
7215 ++cout;
7216 ++cin;
7217 --l;
7218 }
7219 }
7220
7221 qreal height = 0;
7222 qreal width = 0;
7223
7224 QString finalText = text.mid(old_offset, length);
7225 QStackTextEngine engine(finalText, fnt);
7226 if (option) {
7227 engine.option = *option;
7228 }
7229
7230 if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7231 engine.option.setTabStopDistance(tabstops);
7232
7233 if (engine.option.tabs().isEmpty() && ta) {
7234 QList<qreal> tabs;
7235 tabs.reserve(tabarraylen);
7236 for (int i = 0; i < tabarraylen; i++)
7237 tabs.append(qreal(ta[i]));
7238 engine.option.setTabArray(tabs);
7239 }
7240
7241 engine.option.setTextDirection(layout_direction);
7242 if (tf & Qt::AlignJustify)
7243 engine.option.setAlignment(Qt::AlignJustify);
7244 else
7245 engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
7246
7247 if (!option && (tf & Qt::TextWrapAnywhere))
7248 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7249
7251 engine.forceJustification = true;
7252 QTextLayout textLayout(&engine);
7253 textLayout.setCacheEnabled(true);
7254 textLayout.setFormats(underlineFormats);
7255
7256 if (finalText.isEmpty()) {
7257 height = fm.height();
7258 width = 0;
7259 tf |= Qt::TextDontPrint;
7260 } else {
7261 qreal lineWidth = 0x01000000;
7262 if (wordwrap || (tf & Qt::TextJustificationForced))
7263 lineWidth = qMax<qreal>(0, r.width());
7264 if (!wordwrap)
7266 textLayout.beginLayout();
7267
7268 qreal leading = fm.leading();
7269 height = -leading;
7270
7271 while (1) {
7272 QTextLine l = textLayout.createLine();
7273 if (!l.isValid())
7274 break;
7275
7276 l.setLineWidth(lineWidth);
7277 height += leading;
7278
7279 // Make sure lines are positioned on whole pixels
7280 height = qCeil(height);
7281 l.setPosition(QPointF(0., height));
7282 height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7284 if (!dontclip && !brect && height >= r.height())
7285 break;
7286 }
7287 textLayout.endLayout();
7288 }
7289
7290 qreal yoff = 0;
7291 qreal xoff = 0;
7292 if (tf & Qt::AlignBottom)
7293 yoff = r.height() - height;
7294 else if (tf & Qt::AlignVCenter)
7295 yoff = (r.height() - height)/2;
7296
7297 if (tf & Qt::AlignRight)
7298 xoff = r.width() - width;
7299 else if (tf & Qt::AlignHCenter)
7300 xoff = (r.width() - width)/2;
7301
7302 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7303
7304 if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7305 offset++;
7306 goto start_lengthVariant;
7307 }
7308 if (brect)
7309 *brect = bounds;
7310
7311 if (!(tf & Qt::TextDontPrint)) {
7312 bool restore = false;
7313 if (!dontclip && !r.contains(bounds)) {
7314 restore = true;
7315 painter->save();
7317 }
7318
7319 for (int i = 0; i < textLayout.lineCount(); i++) {
7320 QTextLine line = textLayout.lineAt(i);
7321 QTextEngine *eng = textLayout.engine();
7323
7324 qreal advance = line.horizontalAdvance();
7325 xoff = 0;
7326 if (tf & Qt::AlignRight) {
7327 xoff = r.width() - advance -
7328 eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7329 }
7330 else if (tf & Qt::AlignHCenter)
7331 xoff = (r.width() - advance) / 2;
7332
7333 line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff));
7335 }
7336
7337 if (restore) {
7338 painter->restore();
7339 }
7340 }
7341}
7342
7353{
7354 Q_D(QPainter);
7355 if (d->state)
7356 d->state->layoutDirection = direction;
7357}
7358
7365{
7366 Q_D(const QPainter);
7367 return d->state ? d->state->layoutDirection : Qt::LayoutDirectionAuto;
7368}
7369
7371 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7372 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7373 clipRegion(s->clipRegion), clipPath(s->clipPath),
7374 clipOperation(s->clipOperation),
7375 renderHints(s->renderHints), clipInfo(s->clipInfo),
7376 worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7377 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7378 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7379 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7380 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7381 layoutDirection(s->layoutDirection),
7382 composition_mode(s->composition_mode),
7383 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7384{
7385 dirtyFlags = s->dirtyFlags;
7386}
7387
7389 : brushOrigin(0, 0), WxF(false), VxF(false), clipEnabled(true),
7390 layoutDirection(QGuiApplication::layoutDirection())
7391{
7392}
7393
7397
7401 WxF = false;
7402 VxF = false;
7403 clipEnabled = true;
7404 wx = wy = ww = wh = 0;
7405 vx = vy = vw = vh = 0;
7406 painter = p;
7407 pen = QPen();
7408 brushOrigin = QPointF(0, 0);
7409 brush = QBrush();
7410 font = deviceFont = QFont();
7411 clipRegion = QRegion();
7414 clipInfo.clear();
7416 matrix.reset();
7420 dirtyFlags = { };
7421 changeFlags = 0;
7422 renderHints = { };
7423 opacity = 1;
7424}
7425
7612{
7613 return static_cast<const QPainterState *>(this)->pen;
7614}
7615
7626{
7627 return static_cast<const QPainterState *>(this)->brush;
7628}
7629
7640{
7641 return static_cast<const QPainterState *>(this)->brushOrigin;
7642}
7643
7654{
7655 return static_cast<const QPainterState *>(this)->bgBrush;
7656}
7657
7669{
7670 return static_cast<const QPainterState *>(this)->bgMode;
7671}
7672
7684{
7685 return static_cast<const QPainterState *>(this)->font;
7686}
7687
7701{
7702 const QPainterState *st = static_cast<const QPainterState *>(this);
7703
7704 return st->matrix;
7705}
7706
7707
7720{
7721 return static_cast<const QPainterState *>(this)->clipOperation;
7722}
7723
7732{
7733 const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
7734 return needsResolving(brush);
7735}
7736
7737
7746{
7747 const QPen &pen = static_cast<const QPainterState *>(this)->pen;
7748 return needsResolving(pen.brush());
7749}
7750
7761{
7762 return static_cast<const QPainterState *>(this)->clipRegion;
7763}
7764
7775{
7776 return static_cast<const QPainterState *>(this)->clipPath;
7777}
7778
7791{
7792 return static_cast<const QPainterState *>(this)->clipEnabled;
7793}
7794
7805QPainter::RenderHints QPaintEngineState::renderHints() const
7806{
7807 return static_cast<const QPainterState *>(this)->renderHints;
7808}
7809
7821{
7822 return static_cast<const QPainterState *>(this)->composition_mode;
7823}
7824
7825
7832{
7833 return static_cast<const QPainterState *>(this)->painter;
7834}
7835
7836
7844{
7845 return static_cast<const QPainterState *>(this)->opacity;
7846}
7847
7859{
7860 setWorldTransform(transform, combine);
7861}
7862
7871{
7872 return worldTransform();
7873}
7874
7875
7892{
7893 Q_D(const QPainter);
7894 if (!d->engine) {
7895 qWarning("QPainter::deviceTransform: Painter not active");
7896 return d->fakeState()->transform;
7897 }
7898 return d->state->matrix;
7899}
7900
7901
7911{
7912 Q_D(QPainter);
7913#ifdef QT_DEBUG_DRAW
7914 if (qt_show_painter_debug_output)
7915 printf("QPainter::resetMatrix()\n");
7916#endif
7917 if (!d->engine) {
7918 qWarning("QPainter::resetMatrix: Painter not active");
7919 return;
7920 }
7921
7922 d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0; // default view origins
7923 d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
7924 d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
7925 d->state->worldMatrix = QTransform();
7926 setWorldMatrixEnabled(false);
7928 if (d->extended)
7929 d->extended->transformChanged();
7930 else
7931 d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
7932}
7933
7943{
7944 Q_D(QPainter);
7945
7946 if (!d->engine) {
7947 qWarning("QPainter::setWorldTransform: Painter not active");
7948 return;
7949 }
7950
7951 if (combine)
7952 d->state->worldMatrix = matrix * d->state->worldMatrix; // combines
7953 else
7954 d->state->worldMatrix = matrix; // set new matrix
7955
7956 d->state->WxF = true;
7957 d->updateMatrix();
7958}
7959
7965{
7966 Q_D(const QPainter);
7967 if (!d->engine) {
7968 qWarning("QPainter::worldTransform: Painter not active");
7969 return d->fakeState()->transform;
7970 }
7971 return d->state->worldMatrix;
7972}
7973
7982{
7983 Q_D(const QPainter);
7984 if (!d->engine) {
7985 qWarning("QPainter::combinedTransform: Painter not active");
7986 return QTransform();
7987 }
7988 return d->state->worldMatrix * d->viewTransform() * d->hidpiScaleTransform();
7989}
7990
8006void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
8007 const QPixmap &pixmap, PixmapFragmentHints hints)
8008{
8009 Q_D(QPainter);
8010
8011 if (!d->engine || pixmap.isNull())
8012 return;
8013
8014#ifndef QT_NO_DEBUG
8015 for (int i = 0; i < fragmentCount; ++i) {
8016 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8017 fragments[i].width, fragments[i].height);
8018 if (!(QRectF(pixmap.rect()).contains(sourceRect)))
8019 qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
8020 }
8021#endif
8022
8023 if (d->engine->isExtended()) {
8024 d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8025 } else {
8026 qreal oldOpacity = opacity();
8027 QTransform oldTransform = transform();
8028
8029 for (int i = 0; i < fragmentCount; ++i) {
8030 QTransform transform = oldTransform;
8031 qreal xOffset = 0;
8032 qreal yOffset = 0;
8033 if (fragments[i].rotation == 0) {
8034 xOffset = fragments[i].x;
8035 yOffset = fragments[i].y;
8036 } else {
8037 transform.translate(fragments[i].x, fragments[i].y);
8038 transform.rotate(fragments[i].rotation);
8039 }
8040 setOpacity(oldOpacity * fragments[i].opacity);
8042
8043 qreal w = fragments[i].scaleX * fragments[i].width;
8044 qreal h = fragments[i].scaleY * fragments[i].height;
8045 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8046 fragments[i].width, fragments[i].height);
8047 drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8048 }
8049
8050 setOpacity(oldOpacity);
8051 setTransform(oldTransform);
8052 }
8053}
8054
8085 qreal scaleX, qreal scaleY, qreal rotation,
8086 qreal opacity)
8087{
8088 PixmapFragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(),
8089 sourceRect.height(), scaleX, scaleY, rotation, opacity};
8090 return fragment;
8091}
8092
8163{
8164 p->draw_helper(path, operation);
8165}
8166
8168
8169#include "moc_qpainter.cpp"
IOBluetoothDevice * device
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QRgb rgb() const noexcept
Returns the RGB value of the color.
Definition qcolor.cpp:1439
QString name(NameFormat format=HexRgb) const
Definition qcolor.cpp:834
bool isValid() const noexcept
Returns true if the color is valid; otherwise returns false.
Definition qcolor.h:285
Definition qflags.h:17
static QFontCache * instance()
Definition qfont.cpp:3336
void ensureEngineAt(int at)
QFontEngine * engine(int at) const
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)
\reentrant
Definition qfontinfo.h:16
\reentrant \inmodule QtGui
\reentrant \inmodule QtGui
static QFontPrivate * get(const QFont &font)
Definition qfont_p.h:193
\reentrant
Definition qfont.h:22
QFont resolve(const QFont &) const
Returns a new QFont that has attributes copied from other that have not been previously set on this f...
Definition qfont.cpp:1893
QStringList families() const
Definition qfont.cpp:2699
int pointSize() const
Returns the point size of the font.
Definition qfont.cpp:884
static QGlyphRunPrivate * get(const QGlyphRun &glyphRun)
Definition qglyphrun_p.h:78
The QGlyphRun class provides direct access to the internal glyphs in a font.
Definition qglyphrun.h:20
bool overline() const
Returns true if this QGlyphRun should be painted with an overline decoration.
bool strikeOut() const
Returns true if this QGlyphRun should be painted with a strike out decoration.
QRawFont rawFont() const
Returns the font selected for this QGlyphRun object.
bool underline() const
Returns true if this QGlyphRun should be painted with an underline decoration.
\inmodule QtGui
Definition qbrush.h:135
CoordinateMode coordinateMode() const
Definition qbrush.cpp:1672
CoordinateMode
Definition qbrush.h:153
@ ObjectBoundingMode
Definition qbrush.h:156
@ LogicalMode
Definition qbrush.h:154
@ StretchToDeviceMode
Definition qbrush.h:155
@ ObjectMode
Definition qbrush.h:157
qreal x() const
This convenience function is equivalent to calling pos().x().
static QPlatformIntegration * platformIntegration()
static Qt::Alignment visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment)
static QPlatformTheme * platformTheme()
\macro qGuiApp
Qt::LayoutDirection layoutDirection
the default layout direction for this application
\inmodule QtGui
Definition qimage.h:37
@ Format_CMYK8888
Definition qimage.h:78
@ Format_Indexed8
Definition qimage.h:45
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
void detach()
Definition qimage.cpp:1128
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
void translate(const QPointF &p)
Translates this line by the given offset.
Definition qline.h:342
\inmodule QtCore\compares equality \compareswith equality QLineF \endcompareswith
Definition qline.h:18
void clear()
Definition qlist.h:434
qreal devicePixelRatio() const
virtual void initPainter(QPainter *painter) const
virtual int devType() const
ushort painters
virtual QPaintDevice * redirected(QPoint *offset) const
int width() const
virtual QPainter * sharedPainter() const
virtual int metric(PaintDeviceMetric metric) const
virtual QPaintEngine * paintEngine() const =0
int height() const
virtual void renderHintsChanged()=0
virtual void penChanged()=0
virtual uint flags() const
virtual void transformChanged()=0
virtual void setState(QPainterState *s)
virtual void drawStaticTextItem(QStaticTextItem *)
void setSystemTransform(const QTransform &xform)
QPaintDevice * currentClipDevice
virtual void systemStateChanged()
QTransform transform() const
QBrush backgroundBrush() const
Returns the background brush in the current paint engine state.
QPainterPath clipPath() const
Returns the clip path in the current paint engine state.
Qt::ClipOperation clipOperation() const
Returns the clip operation in the current paint engine state.
bool brushNeedsResolving() const
QPointF brushOrigin() const
Returns the brush origin in the current paint engine state.
QPaintEngine::DirtyFlags dirtyFlags
QPainter * painter() const
Returns a pointer to the painter currently updating the paint engine.
qreal opacity() const
bool isClipEnabled() const
Returns whether clipping is enabled or not in the current paint engine state.
QBrush brush() const
Returns the brush in the current paint engine state.
QRegion clipRegion() const
Returns the clip region in the current paint engine state.
QPainter::RenderHints renderHints() const
Returns the render hints in the current paint engine state.
QFont font() const
Returns the font in the current paint engine state.
QPen pen() const
Returns the pen in the current paint engine state.
Qt::BGMode backgroundMode() const
Returns the background mode in the current paint engine state.
bool penNeedsResolving() const
QPainter::CompositionMode compositionMode() const
Returns the composition mode in the current paint engine state.
\inmodule QtGui
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem)
This function draws the text item textItem at position p.
PolygonDrawMode
\value OddEvenMode The polygon should be drawn using OddEven fill rule.
@ ObjectBoundingModeGradients
QPaintEngineState * state
virtual Type type() const =0
Reimplement this function to return the paint engine \l{Type}.
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
void setMiterLimit(qreal length)
Sets the miter limit of the generated outlines to limit.
\inmodule QtGui
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision.
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation)
Definition qpainter.cpp:473
void updateEmulationSpecifier(QPainterState *s)
Definition qpainter.cpp:655
QTransform invMatrix
Definition qpainter_p.h:180
QPaintEngineEx * extended
Definition qpainter_p.h:243
QPaintDevice * helper_device
Definition qpainter_p.h:231
void initFrom(const QPaintDevice *device)
void updateMatrix()
Definition qpainter.cpp:626
void updateInvMatrix()
Definition qpainter.cpp:646
std::unique_ptr< QPaintEngine, QPaintEngineDestructor > engine
Definition qpainter_p.h:240
void updateState(QPainterState *state)
Definition qpainter.cpp:892
std::unique_ptr< QEmulationPaintEngine > emulationEngine
Definition qpainter_p.h:242
void draw_helper(const QPainterPath &path, DrawOperation operation=StrokeAndFillDraw)
Definition qpainter.cpp:317
QVarLengthArray< QPainterPrivate *, NDPtrs > d_ptrs
Definition qpainter_p.h:169
QPainterPrivate(QPainter *painter)
Definition qpainter.cpp:199
void drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine)
void drawStretchedGradient(const QPainterPath &path, DrawOperation operation)
Definition qpainter.cpp:511
QTransform hidpiScaleTransform() const
Definition qpainter.cpp:227
void detachPainterPrivate(QPainter *q)
Definition qpainter.cpp:290
QPaintDevice * device
Definition qpainter_p.h:229
QTransform viewTransform() const
Definition qpainter.cpp:207
qreal effectiveDevicePixelRatio() const
Definition qpainter.cpp:218
void checkEmulation()
Definition qpainter.cpp:171
std::unique_ptr< QPainterState > state
Definition qpainter_p.h:171
void updateStateImpl(QPainterState *state)
Definition qpainter.cpp:860
static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev)
Definition qpainter.cpp:237
void drawGlyphs(const QPointF &decorationPosition, const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, QFontEngine *fontEngine, bool overline=false, bool underline=false, bool strikeOut=false)
QRegion clipRegion
Definition qpainter_p.h:124
virtual ~QPainterState()
QPainter::CompositionMode composition_mode
Definition qpainter_p.h:143
QList< QPainterClipInfo > clipInfo
Definition qpainter_p.h:128
Qt::BGMode bgMode
Definition qpainter_p.h:140
uint emulationSpecifier
Definition qpainter_p.h:144
QTransform worldMatrix
Definition qpainter_p.h:129
QPainter::RenderHints renderHints
Definition qpainter_p.h:127
Qt::ClipOperation clipOperation
Definition qpainter_p.h:126
QTransform matrix
Definition qpainter_p.h:130
QPointF brushOrigin
Definition qpainter_p.h:118
void init(QPainter *p)
QPainterPath clipPath
Definition qpainter_p.h:125
Qt::LayoutDirection layoutDirection
Definition qpainter_p.h:142
QPainter * painter
Definition qpainter_p.h:141
This class is used in conjunction with the QPainter::drawPixmapFragments() function to specify how a ...
Definition qpainter.h:64
static PixmapFragment Q_GUI_EXPORT create(const QPointF &pos, const QRectF &sourceRect, qreal scaleX=1, qreal scaleY=1, qreal rotation=0, qreal opacity=1)
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
const QBrush & background() const
Returns the current background brush.
CompositionMode compositionMode() const
Returns the current composition mode.
const QPen & pen() const
Returns the painter's current pen.
void setBackground(const QBrush &bg)
Sets the background brush of the painter to the given brush.
void setClipping(bool enable)
Enables clipping if enable is true, or disables clipping if enable is false.
Qt::LayoutDirection layoutDirection() const
Returns the layout direction used by the painter when drawing text.
RenderHints renderHints() const
Returns a flag that specifies the rendering hints that are set for this painter.
void drawRect(const QRectF &rect)
Draws the current rectangle with the current pen and brush.
Definition qpainter.h:519
QPainter()
Constructs a painter.
void drawPath(const QPainterPath &path)
Draws the given painter path using the current pen for outline and the current brush for filling.
void drawConvexPolygon(const QPointF *points, int pointCount)
Draws the convex polygon defined by the first pointCount points in the array points using the current...
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
qreal opacity() const
void setWorldMatrixEnabled(bool enabled)
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation.
void drawPie(const QRectF &rect, int a, int alen)
Draws a pie defined by the given rectangle, startAngle and spanAngle.
void strokePath(const QPainterPath &path, const QPen &pen)
Draws the outline (strokes) the path path with the pen specified by pen.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, PixmapFragmentHints hints=PixmapFragmentHints())
void drawLine(const QLineF &line)
Draws a line defined by line.
Definition qpainter.h:442
void setViewport(const QRect &viewport)
Sets the painter's viewport rectangle to the given rectangle, and enables view transformations.
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
void drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
Draws the glyphs represented by glyphs at position.
QTransform combinedTransform() const
Returns the transformation matrix combining the current window/viewport and world transformation.
void drawTextItem(const QPointF &p, const QTextItem &ti)
void drawChord(const QRectF &rect, int a, int alen)
Draws the chord defined by the given rectangle, startAngle and spanAngle.
bool begin(QPaintDevice *)
Begins painting the paint device and returns true if successful; otherwise returns false.
void setBrushOrigin(int x, int y)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpainter.h:698
void drawRects(const QRectF *rects, int rectCount)
Draws the first rectCount of the given rectangles using the current pen and brush.
void setClipPath(const QPainterPath &path, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip path for the painter to the given path, with the clip operation.
void setBackgroundMode(Qt::BGMode mode)
Sets the background mode of the painter to the given mode.
const QFont & font() const
Returns the currently set font used for drawing text.
bool worldMatrixEnabled() const
void setLayoutDirection(Qt::LayoutDirection direction)
Sets the layout direction used by the painter when drawing text, to the specified direction.
~QPainter()
Destroys the painter.
void drawTiledPixmap(const QRectF &rect, const QPixmap &pm, const QPointF &offset=QPointF())
Draws a tiled pixmap, inside the given rectangle with its origin at the given position.
void restore()
Restores the current painter state (pops a saved state off the stack).
void rotate(qreal a)
Rotates the coordinate system clockwise.
void scale(qreal sx, qreal sy)
Scales the coordinate system by ({sx}, {sy}).
const QTransform & worldTransform() const
Returns the world transformation matrix.
const QBrush & brush() const
Returns the painter's current brush.
void setOpacity(qreal opacity)
QFontMetrics fontMetrics() const
Returns the font metrics for the painter if the painter is active.
void drawLines(const QLineF *lines, int lineCount)
Draws the first lineCount lines in the array lines using the current pen.
void beginNativePainting()
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
void save()
Saves the current painter state (pushes the state onto a stack).
void setWorldTransform(const QTransform &matrix, bool combine=false)
Sets the world transformation matrix.
void shear(qreal sh, qreal sv)
Shears the coordinate system by ({sh}, {sv}).
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Draws the rectangular portion source of the given image into the target rectangle in the paint device...
void setFont(const QFont &f)
Sets the painter's font to the given font.
QRegion clipRegion() const
Returns the currently set clip region.
void drawText(const QPointF &p, const QString &s)
Draws the given text with the currently defined text direction, beginning at the given position.
Qt::BGMode backgroundMode() const
Returns the current background mode.
QPainterPath clipPath() const
Returns the current clip path in logical coordinates.
void drawPolyline(const QPointF *points, int pointCount)
Draws the polyline defined by the first pointCount points in points using the current pen.
QRect viewport() const
Returns the viewport rectangle.
const QTransform & deviceTransform() const
Returns the matrix that transforms from logical coordinates to device coordinates of the platform dep...
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
void drawArc(const QRectF &rect, int a, int alen)
Draws the arc defined by the given rectangle, startAngle and spanAngle.
void eraseRect(const QRectF &)
Erases the area inside the given rectangle.
void fillPath(const QPainterPath &path, const QBrush &brush)
Fills the given path using the given brush.
QPoint brushOrigin() const
Returns the currently set brush origin.
void drawEllipse(const QRectF &r)
Draws the ellipse defined by the given rectangle.
void setBrush(const QBrush &brush)
Sets the painter's brush to the given brush.
RenderHint
Renderhints are used to specify flags to QPainter that may or may not be respected by any given engin...
Definition qpainter.h:51
@ SmoothPixmapTransform
Definition qpainter.h:54
@ Antialiasing
Definition qpainter.h:52
@ TextAntialiasing
Definition qpainter.h:53
bool end()
Ends painting.
void drawPicture(const QPointF &p, const QPicture &picture)
Replays the given picture at the given point.
void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
void drawPoints(const QPointF *points, int pointCount)
Draws the first pointCount points in the array points using the current pen's color.
bool viewTransformEnabled() const
Returns true if view transformation is enabled; otherwise returns false.
const QTransform & transform() const
Alias for worldTransform().
void resetTransform()
Resets any transformations that were made using translate(), scale(), shear(), rotate(),...
QRect window() const
Returns the window rectangle.
CompositionMode
Defines the modes supported for digital image compositing.
Definition qpainter.h:97
@ CompositionMode_Xor
Definition qpainter.h:109
@ CompositionMode_SourceOver
Definition qpainter.h:98
@ CompositionMode_SourceAtop
Definition qpainter.h:107
@ CompositionMode_Plus
Definition qpainter.h:112
@ RasterOp_SourceOrDestination
Definition qpainter.h:126
@ CompositionMode_Source
Definition qpainter.h:101
QRectF clipBoundingRect() const
Returns the bounding rectangle of the current clip if there is a clip; otherwise returns an empty rec...
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule=Qt::OddEvenFill)
Draws the polygon defined by the first pointCount points in the array points using the current pen an...
void setViewTransformEnabled(bool enable)
Enables view transformations if enable is true, or disables view transformations if enable is false.
void endNativePainting()
bool isActive() const
Returns true if begin() has been called and end() has not yet been called; otherwise returns false.
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
void setRenderHints(RenderHints hints, bool on=true)
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
bool hasClipping() const
Returns true if clipping has been set; otherwise returns false.
void setWindow(const QRect &window)
Sets the painter's window to the given rectangle, and enables view transformations.
QFontInfo fontInfo() const
Returns the font info for the painter if the painter is active.
void setRenderHint(RenderHint hint, bool on=true)
Sets the given render hint on the painter if on is true; otherwise clears the render hint.
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
void setClipRegion(const QRegion &, Qt::ClipOperation op=Qt::ReplaceClip)
Sets the clip region to the given region using the specified clip operation.
void setTransform(const QTransform &transform, bool combine=false)
QRectF boundingRect(const QRectF &rect, int flags, const QString &text)
Returns the bounding rectangle of the text as it will appear when drawn inside the given rectangle wi...
\inmodule QtGui
Definition qpen.h:28
void setCapStyle(Qt::PenCapStyle pcs)
Sets the pen's cap style to the given style.
Definition qpen.cpp:650
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:572
void setStyle(Qt::PenStyle)
[0]
QColor color() const
Returns the color of this pen's brush.
Definition qpen.cpp:692
void setWidthF(qreal width)
Sets the pen width to the given width in pixels with floating point precision.
Definition qpen.cpp:618
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
void setColor(const QColor &color)
Sets the color of this pen's brush to the given color.
Definition qpen.cpp:705
void setBrush(const QBrush &brush)
Sets the brush used to fill strokes generated with this pen to the given brush.
Definition qpen.cpp:726
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:663
qreal miterLimit() const
Returns the miter limit of the pen.
Definition qpen.cpp:524
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition qpen.cpp:715
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:366
The QPicture class is a paint device that records and replays QPainter commands.
Definition qpicture.h:19
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
int height() const
Returns the height of the pixmap.
Definition qpixmap.cpp:480
int depth() const
Returns the depth of the pixmap.
Definition qpixmap.cpp:521
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:456
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:468
QPixmap copy(int x, int y, int width, int height) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpixmap.h:153
QRect rect() const
Returns the pixmap's enclosing rectangle.
Definition qpixmap.cpp:505
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
Definition qpixmap.cpp:576
bool isQBitmap() const
Returns true if this is a QBitmap; otherwise returns false.
Definition qpixmap.cpp:443
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
virtual bool hasCapability(Capability cap) const
The QPlatformTheme class allows customizing the UI based on themes.
virtual QVariant themeHint(ThemeHint hint) const
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:404
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
static QRawFontPrivate * get(const QRawFont &font)
Definition qrawfont_p.h:104
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
\inmodule QtCore\reentrant
Definition qrect.h:484
QRect toAlignedRect() const noexcept
Definition qrect.cpp:2338
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
bool contains(const QRectF &r) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:1993
QRectF normalized() const noexcept
Returns a normalized rectangle; i.e., a rectangle that has a non-negative width and height.
Definition qrect.cpp:1522
QRectF intersected(const QRectF &other) const noexcept
Definition qrect.h:847
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:167
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
QRect intersected(const QRect &other) const noexcept
Definition qrect.h:415
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
static QStaticTextPrivate * get(const QStaticText *q)
The QStaticText class enables optimized drawing of text when the text and its layout is updated rarel...
Definition qstatictext.h:21
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLatin1() const &
Definition qstring.h:630
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
qsizetype length() const noexcept
Returns the number of characters in this string.
Definition qstring.h:191
UnderlineStyle
This enum describes the different ways drawing underlined text.
QColor underlineColor() const
Returns the color used to draw underlines, overlines and strikeouts on the characters with this forma...
QScriptLineArray lines
void enableDelayDecorations(bool enable=true)
QFixed leadingSpaceWidth(const QScriptLine &line)
void drawDecorations(QPainter *painter)
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
Internal QTextItem.
QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const
QFontEngine * fontEngine
\inmodule QtGui
\reentrant
Definition qtextlayout.h:70
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
void beginLayout()
Begins the layout process.
QTextEngine * engine() const
void setCacheEnabled(bool enable)
Enables caching of the complete layout information if enable is true; otherwise disables layout cachi...
void setFormats(const QList< FormatRange > &overrides)
int lineCount() const
Returns the number of lines in this text layout.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
void endLayout()
Ends the layout process.
\reentrant
qreal naturalTextWidth() const
Returns the width of the line that is occupied by text.
void setPosition(const QPointF &pos)
Moves the line to position pos.
bool isValid() const
Returns true if this text line is valid; otherwise returns false.
void setLineWidth(qreal width)
Lays out the line with the given width.
int lineNumber() const
Returns the position of the line in the text engine.
\reentrant
Definition qtextoption.h:18
@ IncludeTrailingSpaces
Definition qtextoption.h:76
static QThread * currentThread()
Definition qthread.cpp:1039
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
static QTransform fromScale(qreal dx, qreal dy)
Creates a matrix which corresponds to a scaling of sx horizontally and sy vertically.
qreal m11() const
Returns the horizontal scaling factor.
Definition qtransform.h:199
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis.
QTransform inverted(bool *invertible=nullptr) const
Returns an inverted copy of this matrix.
bool isAffine() const
Returns true if the matrix represent an affine transformation, otherwise returns false.
Definition qtransform.h:165
void reset()
Resets the matrix to an identity matrix, i.e.
bool isIdentity() const
Returns true if the matrix is the identity matrix, otherwise returns false.
Definition qtransform.h:169
#define this
Definition dialogs.cpp:9
QString str
[2]
QPixmap p2
QPixmap p1
[0]
QString text
rect
[4]
direction
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ AutoColor
Definition qnamespace.h:478
@ OrderedDither
Definition qnamespace.h:491
@ OrderedAlphaDither
Definition qnamespace.h:485
@ AlignRight
Definition qnamespace.h:146
@ AlignJustify
Definition qnamespace.h:149
@ AlignBottom
Definition qnamespace.h:154
@ AlignVCenter
Definition qnamespace.h:155
@ AlignHCenter
Definition qnamespace.h:148
@ AlignLeft
Definition qnamespace.h:144
ClipOperation
@ ReplaceClip
@ IntersectClip
@ NoClip
LayoutDirection
@ LeftToRight
@ LayoutDirectionAuto
@ RightToLeft
@ TextJustificationForced
Definition qnamespace.h:179
@ TextLongestVariant
Definition qnamespace.h:184
@ TextIncludeTrailingSpaces
Definition qnamespace.h:177
@ TextWrapAnywhere
Definition qnamespace.h:175
@ TextSingleLine
Definition qnamespace.h:170
@ TextWordWrap
Definition qnamespace.h:174
@ TextDontPrint
Definition qnamespace.h:176
@ TextDontClip
Definition qnamespace.h:171
@ TextHideMnemonic
Definition qnamespace.h:178
@ TextExpandTabs
Definition qnamespace.h:172
@ TextForceRightToLeft
Definition qnamespace.h:181
@ TextShowMnemonic
Definition qnamespace.h:173
@ TextForceLeftToRight
Definition qnamespace.h:180
@ OpaqueMode
Definition qnamespace.h:508
@ TransparentMode
Definition qnamespace.h:507
@ color1
Definition qnamespace.h:29
@ white
Definition qnamespace.h:31
@ transparent
Definition qnamespace.h:47
@ black
Definition qnamespace.h:30
@ color0
Definition qnamespace.h:28
@ SolidLine
@ NoPen
BrushStyle
@ DiagCrossPattern
@ SolidPattern
@ RadialGradientPattern
@ Dense1Pattern
@ TexturePattern
@ LinearGradientPattern
@ NoBrush
@ ConicalGradientPattern
@ WindingFill
@ SquareCap
@ FlatCap
Definition brush.cpp:5
Definition image.cpp:4
bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush &brush)
Definition qbrush.cpp:202
Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
Definition qbrush.cpp:801
#define qApp
static const QCssKnownValue positions[NumKnownPositionModes - 1]
#define QT_CATCH(A)
#define QT_TRY
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
static Q_CONSTINIT Qt::LayoutDirection layout_direction
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
int qFloor(T v)
Definition qmath.h:42
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLenum mode
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLfloat GLfloat f
GLsizei levels
GLsizei range
GLint GLsizei width
GLuint color
[2]
GLint GLint bottom
GLbitfield flags
GLboolean enable
GLenum GLuint texture
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint first
GLfloat n
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLfixed GLfixed GLint GLint GLfixed points
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
GLint void * img
Definition qopenglext.h:233
GLuint GLenum matrix
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
GLuint GLenum option
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLenum GLenum GLenum GLenum GLenum scale
GLboolean invert
Definition qopenglext.h:226
static const QRectF boundingRect(const QPointF *points, int pointCount)
const QVectorPath & qtVectorPathForPath(const QPainterPath &path)
bool qt_isExtendedRadialGradient(const QBrush &brush)
Definition qbrush.cpp:801
#define QPaintEngine_OpaqueBackground
Definition qpainter.cpp:52
static void qt_draw_decoration_for_glyphs(QPainter *painter, const QPointF &decorationPosition, const glyph_t *glyphArray, const QFixedPoint *positions, int glyphCount, QFontEngine *fontEngine, bool underline, bool overline, bool strikeOut)
static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine, QTextCharFormat::UnderlineStyle underlineStyle, QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat)
static bool needsEmulation(const QBrush &brush)
Definition qpainter.cpp:154
static bool needsResolving(const QBrush &brush)
void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString &str, QRectF *brect, int tabstops, int *tabarray, int tabarraylen, QPainter *painter)
static QPointF roundInDeviceCoordinates(const QPointF &p, const QTransform &m)
QPixmap qt_pixmapForBrush(int style, bool invert)
Definition qbrush.cpp:80
static bool is_brush_transparent(const QBrush &brush)
Definition qpainter.cpp:95
static QBrush stretchGradientToUserSpace(const QBrush &brush, const QRectF &boundingRect)
Definition qpainter.cpp:492
static bool qt_painter_thread_test(int devType, int engineType, const char *what)
Definition qpainter.cpp:127
static void qt_cleanup_painter_state(QPainterPrivate *d)
QPainterPath qt_regionToPath(const QRegion &region)
Definition qregion.cpp:1007
static QGradient::CoordinateMode coordinateMode(const QBrush &brush)
Definition qpainter.cpp:80
static uint line_emulation(uint emulation)
Definition qpainter.cpp:114
static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation)
#define QGradient_StretchToDevice
Definition qpainter.cpp:51
static bool is_pen_transparent(const QPen &pen)
Definition qpainter.cpp:107
bool qHasPixmapTexture(const QBrush &)
Definition qbrush.cpp:202
Qt::BrushStyle qbrush_style(const QBrush &b)
Definition qpainter_p.h:63
Qt::PenStyle qpen_style(const QPen &p)
Definition qpainter_p.h:56
QBrush qpen_brush(const QPen &p)
Definition qpainter_p.h:54
QT_BEGIN_NAMESPACE void qt_format_text(const QFont &fnt, const QRectF &_r, int tf, const QTextOption *opt, const QString &str, QRectF *brect, int tabstops, int *, int tabarraylen, QPainter *painter)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1531
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define sp
#define fp
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned int glyph_t
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
QObject::connect nullptr
QGraphicsItem * item
widget render & pixmap
QPainter painter(this)
[7]
QHostInfo info
[0]
QJSEngine engine
[0]
static constexpr QFixedPoint fromPointF(const QPointF &p)
Definition qfixed_p.h:167
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35
constexpr qreal toReal() const
Definition qfixed_p.h:42
glyph_t * glyphs
unsigned short flags
QScriptAnalysis analysis