Qt 6.x
The Qt SDK
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*/
114static inline uint line_emulation(uint emulation)
115{
116 return emulation & (QPaintEngine::PrimitiveTransform
124}
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 qMax(qreal(1), 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)
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(),
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) {
864 engine->state = newState;
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
1434 : d_ptr(new QPainterPrivate(this))
1435{
1436}
1437
1463 : d_ptr(nullptr)
1464{
1465 Q_ASSERT(pd != nullptr);
1467 d_ptr.reset(new QPainterPrivate(this));
1468 begin(pd);
1469 }
1470 Q_ASSERT(d_ptr);
1471}
1472
1477{
1478 d_ptr->inDestructor = true;
1479 QT_TRY {
1480 if (isActive())
1481 end();
1482 else if (d_ptr->refcount > 1)
1483 d_ptr->detachPainterPrivate(this);
1484 } QT_CATCH(...) {
1485 // don't throw anything in the destructor.
1486 }
1487 if (d_ptr) {
1488 // Make sure we haven't messed things up.
1489 Q_ASSERT(d_ptr->inDestructor);
1490 d_ptr->inDestructor = false;
1491 Q_ASSERT(d_ptr->refcount == 1);
1492 }
1493}
1494
1503{
1504 Q_D(const QPainter);
1505 if (isActive() && d->engine->d_func()->currentClipDevice)
1506 return d->engine->d_func()->currentClipDevice;
1507 return d->original_device;
1508}
1509
1518{
1519 Q_D(const QPainter);
1520 return d->engine != nullptr;
1521}
1522
1524{
1525 if (!engine) {
1526 qWarning("QPainter::initFrom: Painter not active, aborted");
1527 return;
1528 }
1529
1530 Q_Q(QPainter);
1532
1533 if (extended) {
1535 } else if (engine) {
1536 engine->setDirty(QPaintEngine::DirtyPen);
1539 }
1540}
1541
1551{
1552#ifdef QT_DEBUG_DRAW
1553 if (qt_show_painter_debug_output)
1554 printf("QPainter::save()\n");
1555#endif
1556 Q_D(QPainter);
1557 if (!d->engine) {
1558 qWarning("QPainter::save: Painter not active");
1559 return;
1560 }
1561
1562 std::unique_ptr<QPainterState> prev;
1563 if (d->extended) {
1564 // separate the creation of a new state from the update of d->state, since some
1565 // engines access d->state directly (not via createState()'s argument)
1566 std::unique_ptr<QPainterState> next(d->extended->createState(d->state.get()));
1567 prev = std::exchange(d->state, std::move(next));
1568 d->extended->setState(d->state.get());
1569 } else {
1570 d->updateState(d->state);
1571 prev = std::exchange(d->state, std::make_unique<QPainterState>(d->state.get()));
1572 d->engine->state = d->state.get();
1573 }
1574 d->savedStates.push(std::move(prev));
1575}
1576
1585{
1586#ifdef QT_DEBUG_DRAW
1587 if (qt_show_painter_debug_output)
1588 printf("QPainter::restore()\n");
1589#endif
1590 Q_D(QPainter);
1591 if (d->savedStates.empty()) {
1592 qWarning("QPainter::restore: Unbalanced save/restore");
1593 return;
1594 } else if (!d->engine) {
1595 qWarning("QPainter::restore: Painter not active");
1596 return;
1597 }
1598
1599 const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
1600 d->savedStates.pop();
1601 d->txinv = false;
1602
1603 if (d->extended) {
1604 d->checkEmulation();
1605 d->extended->setState(d->state.get());
1606 return;
1607 }
1608
1609 // trigger clip update if the clip path/region has changed since
1610 // last save
1611 if (!d->state->clipInfo.isEmpty()
1612 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1613 // reuse the tmp state to avoid any extra allocs...
1614 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1615 tmp->clipOperation = Qt::NoClip;
1616 tmp->clipPath = QPainterPath();
1617 d->engine->updateState(*tmp);
1618 // replay the list of clip states,
1619 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
1620 tmp->matrix = info.matrix;
1621 tmp->clipOperation = info.operation;
1622 if (info.clipType == QPainterClipInfo::RectClip) {
1624 tmp->clipRegion = info.rect;
1625 } else if (info.clipType == QPainterClipInfo::RegionClip) {
1627 tmp->clipRegion = info.region;
1628 } else { // clipType == QPainterClipInfo::PathClip
1630 tmp->clipPath = info.path;
1631 }
1632 d->engine->updateState(*tmp);
1633 }
1634
1635
1636 //Since we've updated the clip region anyway, pretend that the clip path hasn't changed:
1639 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1640 }
1641
1642 d->updateState(d->state.get());
1643}
1644
1645
1674{
1675 d->savedStates.clear();
1676 d->state = nullptr;
1677 d->engine = nullptr;
1678 d->device = nullptr;
1679}
1680
1682{
1683 Q_ASSERT(pd);
1684
1685 if (pd->painters > 0) {
1686 qWarning("QPainter::begin: A paint device can only be painted by one painter at a time.");
1687 return false;
1688 }
1689
1690 if (d_ptr->engine) {
1691 qWarning("QPainter::begin: Painter already active");
1692 return false;
1693 }
1694
1696 return true;
1697
1698 Q_D(QPainter);
1699
1700 d->helper_device = pd;
1701 d->original_device = pd;
1702
1703 QPoint redirectionOffset;
1704 QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1705 if (rpd)
1706 pd = rpd;
1707
1708#ifdef QT_DEBUG_DRAW
1709 if (qt_show_painter_debug_output)
1710 printf("QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1711#endif
1712
1713 if (pd->devType() == QInternal::Pixmap)
1714 static_cast<QPixmap *>(pd)->detach();
1715 else if (pd->devType() == QInternal::Image)
1716 static_cast<QImage *>(pd)->detach();
1717
1718 d->engine.reset(pd->paintEngine());
1719
1720 if (!d->engine) {
1721 qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1722 return false;
1723 }
1724
1725 d->device = pd;
1726
1727 d->extended = d->engine->isExtended() ? static_cast<QPaintEngineEx *>(d->engine.get()) : nullptr;
1728 if (d->emulationEngine)
1729 d->emulationEngine->real_engine = d->extended;
1730
1731 // Setup new state...
1732 Q_ASSERT(!d->state);
1733 d->state.reset(d->extended ? d->extended->createState(nullptr) : new QPainterState);
1734 d->state->painter = this;
1735
1736 d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1737 d->state->brushOrigin = QPointF();
1738
1739 // Slip a painter state into the engine before we do any other operations
1740 if (d->extended)
1741 d->extended->setState(d->state.get());
1742 else
1743 d->engine->state = d->state.get();
1744
1745 switch (pd->devType()) {
1746 case QInternal::Pixmap:
1747 {
1748 QPixmap *pm = static_cast<QPixmap *>(pd);
1749 Q_ASSERT(pm);
1750 if (pm->isNull()) {
1751 qWarning("QPainter::begin: Cannot paint on a null pixmap");
1753 return false;
1754 }
1755
1756 if (pm->depth() == 1) {
1757 d->state->pen = QPen(Qt::color1);
1758 d->state->brush = QBrush(Qt::color0);
1759 }
1760 break;
1761 }
1762 case QInternal::Image:
1763 {
1764 QImage *img = static_cast<QImage *>(pd);
1765 Q_ASSERT(img);
1766 if (img->isNull()) {
1767 qWarning("QPainter::begin: Cannot paint on a null image");
1769 return false;
1770 } else if (img->format() == QImage::Format_Indexed8) {
1771 // Painting on indexed8 images is not supported.
1772 qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format");
1774 return false;
1775 }
1776 if (img->depth() == 1) {
1777 d->state->pen = QPen(Qt::color1);
1778 d->state->brush = QBrush(Qt::color0);
1779 }
1780 break;
1781 }
1782 default:
1783 break;
1784 }
1785 if (d->state->ww == 0) // For compat with 3.x painter defaults
1786 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1787
1788 d->engine->setPaintDevice(pd);
1789
1790 bool begun = d->engine->begin(pd);
1791 if (!begun) {
1792 qWarning("QPainter::begin(): Returned false");
1793 if (d->engine->isActive()) {
1794 end();
1795 } else {
1797 }
1798 return false;
1799 } else {
1800 d->engine->setActive(begun);
1801 }
1802
1803 // Copy painter properties from original paint device,
1804 // required for QPixmap::grabWidget()
1805 if (d->original_device->devType() == QInternal::Widget) {
1806 d->initFrom(d->original_device);
1807 } else {
1808 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1809 // make sure we have a font compatible with the paintdevice
1810 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1811 }
1812
1813 QRect systemRect = d->engine->systemRect();
1814 if (!systemRect.isEmpty()) {
1815 d->state->ww = d->state->vw = systemRect.width();
1816 d->state->wh = d->state->vh = systemRect.height();
1817 } else {
1818 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1819 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1820 }
1821
1822 const QPoint coordinateOffset = d->engine->coordinateOffset();
1823 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1824
1825 Q_ASSERT(d->engine->isActive());
1826
1827 if (!d->state->redirectionMatrix.isIdentity() || d->effectiveDevicePixelRatio() > 1)
1828 d->updateMatrix();
1829
1830 Q_ASSERT(d->engine->isActive());
1831 d->state->renderHints = QPainter::TextAntialiasing;
1832 ++d->device->painters;
1833
1834 d->state->emulationSpecifier = 0;
1835
1836 return true;
1837}
1838
1850{
1851#ifdef QT_DEBUG_DRAW
1852 if (qt_show_painter_debug_output)
1853 printf("QPainter::end()\n");
1854#endif
1855 Q_D(QPainter);
1856
1857 if (!d->engine) {
1858 qWarning("QPainter::end: Painter not active, aborted");
1860 return false;
1861 }
1862
1863 if (d->refcount > 1) {
1864 d->detachPainterPrivate(this);
1865 return true;
1866 }
1867
1868 bool ended = true;
1869
1870 if (d->engine->isActive()) {
1871 ended = d->engine->end();
1872 d->updateState(nullptr);
1873
1874 --d->device->painters;
1875 if (d->device->painters == 0) {
1876 d->engine->setPaintDevice(nullptr);
1877 d->engine->setActive(false);
1878 }
1879 }
1880
1881 if (d->savedStates.size() > 0) {
1882 qWarning("QPainter::end: Painter ended with %d saved states", int(d->savedStates.size()));
1883 }
1884
1885 d->engine.reset();
1886 d->emulationEngine = nullptr;
1887 d->extended = nullptr;
1888
1890
1891 return ended;
1892}
1893
1894
1902{
1903 Q_D(const QPainter);
1904 return d->engine.get();
1905}
1906
1940{
1941 Q_D(QPainter);
1942 if (!d->engine) {
1943 qWarning("QPainter::beginNativePainting: Painter not active");
1944 return;
1945 }
1946
1947 if (d->extended)
1948 d->extended->beginNativePainting();
1949}
1950
1961{
1962 Q_D(const QPainter);
1963 if (!d->engine) {
1964 qWarning("QPainter::beginNativePainting: Painter not active");
1965 return;
1966 }
1967
1968 if (d->extended)
1969 d->extended->endNativePainting();
1970 else
1971 d->engine->syncState();
1972}
1973
1982{
1983 Q_D(const QPainter);
1984 if (!d->engine) {
1985 qWarning("QPainter::fontMetrics: Painter not active");
1986 return QFontMetrics(QFont());
1987 }
1988 return QFontMetrics(d->state->font);
1989}
1990
1991
2000{
2001 Q_D(const QPainter);
2002 if (!d->engine) {
2003 qWarning("QPainter::fontInfo: Painter not active");
2004 return QFontInfo(QFont());
2005 }
2006 return QFontInfo(d->state->font);
2007}
2008
2017{
2018 Q_D(const QPainter);
2019 if (!d->engine) {
2020 qWarning("QPainter::opacity: Painter not active");
2021 return 1.0;
2022 }
2023 return d->state->opacity;
2024}
2025
2038{
2039 Q_D(QPainter);
2040
2041 if (!d->engine) {
2042 qWarning("QPainter::setOpacity: Painter not active");
2043 return;
2044 }
2045
2046 opacity = qMin(qreal(1), qMax(qreal(0), opacity));
2047
2048 if (opacity == d->state->opacity)
2049 return;
2050
2051 d->state->opacity = opacity;
2052
2053 if (d->extended)
2054 d->extended->opacityChanged();
2055 else
2056 d->state->dirtyFlags |= QPaintEngine::DirtyOpacity;
2057}
2058
2059
2067{
2068 Q_D(const QPainter);
2069 if (!d->engine) {
2070 qWarning("QPainter::brushOrigin: Painter not active");
2071 return QPoint();
2072 }
2073 return QPointF(d->state->brushOrigin).toPoint();
2074}
2075
2095{
2096 Q_D(QPainter);
2097#ifdef QT_DEBUG_DRAW
2098 if (qt_show_painter_debug_output)
2099 printf("QPainter::setBrushOrigin(), (%.2f,%.2f)\n", p.x(), p.y());
2100#endif
2101
2102 if (!d->engine) {
2103 qWarning("QPainter::setBrushOrigin: Painter not active");
2104 return;
2105 }
2106
2107 d->state->brushOrigin = p;
2108
2109 if (d->extended) {
2110 d->extended->brushOriginChanged();
2111 return;
2112 }
2113
2114 d->state->dirtyFlags |= QPaintEngine::DirtyBrushOrigin;
2115}
2116
2326{
2327 Q_D(QPainter);
2328 if (!d->engine) {
2329 qWarning("QPainter::setCompositionMode: Painter not active");
2330 return;
2331 }
2332 if (d->state->composition_mode == mode)
2333 return;
2334 if (d->extended) {
2335 d->state->composition_mode = mode;
2336 d->extended->compositionModeChanged();
2337 return;
2338 }
2339
2341 if (!d->engine->hasFeature(QPaintEngine::RasterOpModes)) {
2342 qWarning("QPainter::setCompositionMode: "
2343 "Raster operation modes not supported on device");
2344 return;
2345 }
2346 } else if (mode >= QPainter::CompositionMode_Plus) {
2347 if (!d->engine->hasFeature(QPaintEngine::BlendModes)) {
2348 qWarning("QPainter::setCompositionMode: "
2349 "Blend modes not supported on device");
2350 return;
2351 }
2352 } else if (!d->engine->hasFeature(QPaintEngine::PorterDuff)) {
2354 qWarning("QPainter::setCompositionMode: "
2355 "PorterDuff modes not supported on device");
2356 return;
2357 }
2358 }
2359
2360 d->state->composition_mode = mode;
2361 d->state->dirtyFlags |= QPaintEngine::DirtyCompositionMode;
2362}
2363
2370{
2371 Q_D(const QPainter);
2372 if (!d->engine) {
2373 qWarning("QPainter::compositionMode: Painter not active");
2375 }
2376 return d->state->composition_mode;
2377}
2378
2386{
2387 Q_D(const QPainter);
2388 if (!d->engine) {
2389 qWarning("QPainter::background: Painter not active");
2390 return d->fakeState()->brush;
2391 }
2392 return d->state->bgBrush;
2393}
2394
2395
2403{
2404 Q_D(const QPainter);
2405 if (!d->engine) {
2406 qWarning("QPainter::hasClipping: Painter not active");
2407 return false;
2408 }
2409 return d->state->clipEnabled && d->state->clipOperation != Qt::NoClip;
2410}
2411
2412
2421{
2422 Q_D(QPainter);
2423#ifdef QT_DEBUG_DRAW
2424 if (qt_show_painter_debug_output)
2425 printf("QPainter::setClipping(), enable=%s, was=%s\n",
2426 enable ? "on" : "off",
2427 hasClipping() ? "on" : "off");
2428#endif
2429 if (!d->engine) {
2430 qWarning("QPainter::setClipping: Painter not active, state will be reset by begin");
2431 return;
2432 }
2433
2434 if (hasClipping() == enable)
2435 return;
2436
2437 // we can't enable clipping if we don't have a clip
2438 if (enable
2439 && (d->state->clipInfo.isEmpty() || d->state->clipInfo.constLast().operation == Qt::NoClip))
2440 return;
2441 d->state->clipEnabled = enable;
2442
2443 if (d->extended) {
2444 d->extended->clipEnabledChanged();
2445 return;
2446 }
2447
2448 d->state->dirtyFlags |= QPaintEngine::DirtyClipEnabled;
2449 d->updateState(d->state);
2450}
2451
2452
2466{
2467 Q_D(const QPainter);
2468 if (!d->engine) {
2469 qWarning("QPainter::clipRegion: Painter not active");
2470 return QRegion();
2471 }
2472
2473 QRegion region;
2474 bool lastWasNothing = true;
2475
2476 if (!d->txinv)
2477 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2478
2479 // ### Falcon: Use QPainterPath
2480 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2481 switch (info.clipType) {
2482
2484 QTransform matrix = (info.matrix * d->invMatrix);
2485 if (lastWasNothing) {
2486 region = info.region * matrix;
2487 lastWasNothing = false;
2488 continue;
2489 }
2490 if (info.operation == Qt::IntersectClip)
2491 region &= info.region * matrix;
2492 else if (info.operation == Qt::NoClip) {
2493 lastWasNothing = true;
2494 region = QRegion();
2495 } else
2496 region = info.region * matrix;
2497 break;
2498 }
2499
2501 QTransform matrix = (info.matrix * d->invMatrix);
2502 if (lastWasNothing) {
2503 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2504 info.path.fillRule());
2505 lastWasNothing = false;
2506 continue;
2507 }
2508 if (info.operation == Qt::IntersectClip) {
2509 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2510 info.path.fillRule());
2511 } else if (info.operation == Qt::NoClip) {
2512 lastWasNothing = true;
2513 region = QRegion();
2514 } else {
2515 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2516 info.path.fillRule());
2517 }
2518 break;
2519 }
2520
2522 QTransform matrix = (info.matrix * d->invMatrix);
2523 if (lastWasNothing) {
2524 region = QRegion(info.rect) * matrix;
2525 lastWasNothing = false;
2526 continue;
2527 }
2528 if (info.operation == Qt::IntersectClip) {
2529 // Use rect intersection if possible.
2530 if (matrix.type() <= QTransform::TxScale)
2531 region &= matrix.mapRect(info.rect);
2532 else
2533 region &= matrix.map(QRegion(info.rect));
2534 } else if (info.operation == Qt::NoClip) {
2535 lastWasNothing = true;
2536 region = QRegion();
2537 } else {
2538 region = QRegion(info.rect) * matrix;
2539 }
2540 break;
2541 }
2542
2544 QTransform matrix = (info.matrix * d->invMatrix);
2545 if (lastWasNothing) {
2546 region = QRegion(info.rectf.toRect()) * matrix;
2547 lastWasNothing = false;
2548 continue;
2549 }
2550 if (info.operation == Qt::IntersectClip) {
2551 // Use rect intersection if possible.
2552 if (matrix.type() <= QTransform::TxScale)
2553 region &= matrix.mapRect(info.rectf.toRect());
2554 else
2555 region &= matrix.map(QRegion(info.rectf.toRect()));
2556 } else if (info.operation == Qt::NoClip) {
2557 lastWasNothing = true;
2558 region = QRegion();
2559 } else {
2560 region = QRegion(info.rectf.toRect()) * matrix;
2561 }
2562 break;
2563 }
2564 }
2565 }
2566
2567 return region;
2568}
2569
2570extern QPainterPath qt_regionToPath(const QRegion &region);
2571
2583{
2584 Q_D(const QPainter);
2585
2586 // ### Since we do not support path intersections and path unions yet,
2587 // we just use clipRegion() here...
2588 if (!d->engine) {
2589 qWarning("QPainter::clipPath: Painter not active");
2590 return QPainterPath();
2591 }
2592
2593 // No clip, return empty
2594 if (d->state->clipInfo.isEmpty()) {
2595 return QPainterPath();
2596 } else {
2597
2598 // Update inverse matrix, used below.
2599 if (!d->txinv)
2600 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2601
2602 // For the simple case avoid conversion.
2603 if (d->state->clipInfo.size() == 1
2604 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::PathClip) {
2605 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2606 return d->state->clipInfo.at(0).path * matrix;
2607
2608 } else if (d->state->clipInfo.size() == 1
2609 && d->state->clipInfo.at(0).clipType == QPainterClipInfo::RectClip) {
2610 QTransform matrix = (d->state->clipInfo.at(0).matrix * d->invMatrix);
2612 path.addRect(d->state->clipInfo.at(0).rect);
2613 return path * matrix;
2614 } else {
2615 // Fallback to clipRegion() for now, since we don't have isect/unite for paths
2616 return qt_regionToPath(clipRegion());
2617 }
2618 }
2619}
2620
2634{
2635 Q_D(const QPainter);
2636
2637 if (!d->engine) {
2638 qWarning("QPainter::clipBoundingRect: Painter not active");
2639 return QRectF();
2640 }
2641
2642 // Accumulate the bounding box in device space. This is not 100%
2643 // precise, but it fits within the guarantee and it is reasonably
2644 // fast.
2645 QRectF bounds;
2646 bool first = true;
2647 for (const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2648 QRectF r;
2649
2650 if (info.clipType == QPainterClipInfo::RectClip)
2651 r = info.rect;
2652 else if (info.clipType == QPainterClipInfo::RectFClip)
2653 r = info.rectf;
2654 else if (info.clipType == QPainterClipInfo::RegionClip)
2655 r = info.region.boundingRect();
2656 else
2657 r = info.path.boundingRect();
2658
2659 r = info.matrix.mapRect(r);
2660
2661 if (first)
2662 bounds = r;
2663 else if (info.operation == Qt::IntersectClip)
2664 bounds &= r;
2665 first = false;
2666 }
2667
2668
2669 // Map the rectangle back into logical space using the inverse
2670 // matrix.
2671 if (!d->txinv)
2672 const_cast<QPainter *>(this)->d_ptr->updateInvMatrix();
2673
2674 return d->invMatrix.mapRect(bounds);
2675}
2676
2690{
2691 Q_D(QPainter);
2692
2693 if (d->extended) {
2694 if (!d->engine) {
2695 qWarning("QPainter::setClipRect: Painter not active");
2696 return;
2697 }
2698 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2699 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2700 op = Qt::ReplaceClip;
2701
2702 qreal right = rect.x() + rect.width();
2703 qreal bottom = rect.y() + rect.height();
2704 qreal pts[] = { rect.x(), rect.y(),
2705 right, rect.y(),
2706 right, bottom,
2707 rect.x(), bottom };
2708 QVectorPath vp(pts, 4, nullptr, QVectorPath::RectangleHint);
2709 d->state->clipEnabled = true;
2710 d->extended->clip(vp, op);
2711 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2712 d->state->clipInfo.clear();
2713 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2714 d->state->clipOperation = op;
2715 return;
2716 }
2717
2718 if (qreal(int(rect.top())) == rect.top()
2719 && qreal(int(rect.bottom())) == rect.bottom()
2720 && qreal(int(rect.left())) == rect.left()
2721 && qreal(int(rect.right())) == rect.right())
2722 {
2723 setClipRect(rect.toRect(), op);
2724 return;
2725 }
2726
2727 if (rect.isEmpty()) {
2728 setClipRegion(QRegion(), op);
2729 return;
2730 }
2731
2733 path.addRect(rect);
2734 setClipPath(path, op);
2735}
2736
2745{
2746 Q_D(QPainter);
2747
2748 if (!d->engine) {
2749 qWarning("QPainter::setClipRect: Painter not active");
2750 return;
2751 }
2752 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2753
2754 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2755 op = Qt::ReplaceClip;
2756
2757 if (d->extended) {
2758 d->state->clipEnabled = true;
2759 d->extended->clip(rect, op);
2760 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2761 d->state->clipInfo.clear();
2762 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2763 d->state->clipOperation = op;
2764 return;
2765 }
2766
2767 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2768 op = Qt::ReplaceClip;
2769
2770 d->state->clipRegion = rect;
2771 d->state->clipOperation = op;
2772 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2773 d->state->clipInfo.clear();
2774 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2775 d->state->clipEnabled = true;
2777 d->updateState(d->state);
2778}
2779
2799{
2800 Q_D(QPainter);
2801#ifdef QT_DEBUG_DRAW
2802 QRect rect = r.boundingRect();
2803 if (qt_show_painter_debug_output)
2804 printf("QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2805 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2806#endif
2807 if (!d->engine) {
2808 qWarning("QPainter::setClipRegion: Painter not active");
2809 return;
2810 }
2811 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2812
2813 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2814 op = Qt::ReplaceClip;
2815
2816 if (d->extended) {
2817 d->state->clipEnabled = true;
2818 d->extended->clip(r, op);
2819 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2820 d->state->clipInfo.clear();
2821 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2822 d->state->clipOperation = op;
2823 return;
2824 }
2825
2826 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2827 op = Qt::ReplaceClip;
2828
2829 d->state->clipRegion = r;
2830 d->state->clipOperation = op;
2831 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2832 d->state->clipInfo.clear();
2833 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2834 d->state->clipEnabled = true;
2836 d->updateState(d->state);
2837}
2838
2851{
2852 Q_D(QPainter);
2853#ifdef QT_DEBUG_DRAW
2854 if (qt_show_painter_debug_output)
2855 printf("QPainter::setMatrixEnabled(), enable=%d\n", enable);
2856#endif
2857
2858 if (!d->engine) {
2859 qWarning("QPainter::setMatrixEnabled: Painter not active");
2860 return;
2861 }
2862 if (enable == d->state->WxF)
2863 return;
2864
2865 d->state->WxF = enable;
2866 d->updateMatrix();
2867}
2868
2879{
2880 Q_D(const QPainter);
2881 if (!d->engine) {
2882 qWarning("QPainter::worldMatrixEnabled: Painter not active");
2883 return false;
2884 }
2885 return d->state->WxF;
2886}
2887
2895{
2896#ifdef QT_DEBUG_DRAW
2897 if (qt_show_painter_debug_output)
2898 printf("QPainter::scale(), sx=%f, sy=%f\n", sx, sy);
2899#endif
2900 Q_D(QPainter);
2901 if (!d->engine) {
2902 qWarning("QPainter::scale: Painter not active");
2903 return;
2904 }
2905
2906 d->state->worldMatrix.scale(sx,sy);
2907 d->state->WxF = true;
2908 d->updateMatrix();
2909}
2910
2918{
2919#ifdef QT_DEBUG_DRAW
2920 if (qt_show_painter_debug_output)
2921 printf("QPainter::shear(), sh=%f, sv=%f\n", sh, sv);
2922#endif
2923 Q_D(QPainter);
2924 if (!d->engine) {
2925 qWarning("QPainter::shear: Painter not active");
2926 return;
2927 }
2928
2929 d->state->worldMatrix.shear(sh, sv);
2930 d->state->WxF = true;
2931 d->updateMatrix();
2932}
2933
2943{
2944#ifdef QT_DEBUG_DRAW
2945 if (qt_show_painter_debug_output)
2946 printf("QPainter::rotate(), angle=%f\n", a);
2947#endif
2948 Q_D(QPainter);
2949 if (!d->engine) {
2950 qWarning("QPainter::rotate: Painter not active");
2951 return;
2952 }
2953
2954 d->state->worldMatrix.rotate(a);
2955 d->state->WxF = true;
2956 d->updateMatrix();
2957}
2958
2966{
2967 qreal dx = offset.x();
2968 qreal dy = offset.y();
2969#ifdef QT_DEBUG_DRAW
2970 if (qt_show_painter_debug_output)
2971 printf("QPainter::translate(), dx=%f, dy=%f\n", dx, dy);
2972#endif
2973 Q_D(QPainter);
2974 if (!d->engine) {
2975 qWarning("QPainter::translate: Painter not active");
2976 return;
2977 }
2978
2979 d->state->worldMatrix.translate(dx, dy);
2980 d->state->WxF = true;
2981 d->updateMatrix();
2982}
2983
3011{
3012#ifdef QT_DEBUG_DRAW
3013 if (qt_show_painter_debug_output) {
3014 QRectF b = path.boundingRect();
3015 printf("QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3016 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3017 }
3018#endif
3019 Q_D(QPainter);
3020
3021 if (!d->engine) {
3022 qWarning("QPainter::setClipPath: Painter not active");
3023 return;
3024 }
3025
3026 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3027 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3028 op = Qt::ReplaceClip;
3029
3030 if (d->extended) {
3031 d->state->clipEnabled = true;
3032 d->extended->clip(path, op);
3033 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3034 d->state->clipInfo.clear();
3035 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3036 d->state->clipOperation = op;
3037 return;
3038 }
3039
3040 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3041 op = Qt::ReplaceClip;
3042
3043 d->state->clipPath = path;
3044 d->state->clipOperation = op;
3045 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3046 d->state->clipInfo.clear();
3047 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3048 d->state->clipEnabled = true;
3050 d->updateState(d->state);
3051}
3052
3060{
3061 Q_D(QPainter);
3062
3063 if (!d->engine) {
3064 qWarning("QPainter::strokePath: Painter not active");
3065 return;
3066 }
3067
3068 if (path.isEmpty())
3069 return;
3070
3071 if (d->extended && !needsEmulation(pen.brush())) {
3072 d->extended->stroke(qtVectorPathForPath(path), pen);
3073 return;
3074 }
3075
3076 QBrush oldBrush = d->state->brush;
3077 QPen oldPen = d->state->pen;
3078
3079 setPen(pen);
3081
3082 drawPath(path);
3083
3084 // Reset old state
3085 setPen(oldPen);
3086 setBrush(oldBrush);
3087}
3088
3100{
3101 Q_D(QPainter);
3102
3103 if (!d->engine) {
3104 qWarning("QPainter::fillPath: Painter not active");
3105 return;
3106 }
3107
3108 if (path.isEmpty())
3109 return;
3110
3111 if (d->extended && !needsEmulation(brush)) {
3112 d->extended->fill(qtVectorPathForPath(path), brush);
3113 return;
3114 }
3115
3116 QBrush oldBrush = d->state->brush;
3117 QPen oldPen = d->state->pen;
3118
3120 setBrush(brush);
3121
3122 drawPath(path);
3123
3124 // Reset old state
3125 setPen(oldPen);
3126 setBrush(oldBrush);
3127}
3128
3144{
3145#ifdef QT_DEBUG_DRAW
3146 QRectF pathBounds = path.boundingRect();
3147 if (qt_show_painter_debug_output)
3148 printf("QPainter::drawPath(), size=%d, [%.2f,%.2f,%.2f,%.2f]\n",
3149 path.elementCount(),
3150 pathBounds.x(), pathBounds.y(), pathBounds.width(), pathBounds.height());
3151#endif
3152
3153 Q_D(QPainter);
3154
3155 if (!d->engine) {
3156 qWarning("QPainter::drawPath: Painter not active");
3157 return;
3158 }
3159
3160 if (d->extended) {
3161 d->extended->drawPath(path);
3162 return;
3163 }
3164 d->updateState(d->state);
3165
3166 if (d->engine->hasFeature(QPaintEngine::PainterPaths) && d->state->emulationSpecifier == 0) {
3167 d->engine->drawPath(path);
3168 } else {
3169 d->draw_helper(path);
3170 }
3171}
3172
3259void QPainter::drawRects(const QRectF *rects, int rectCount)
3260{
3261#ifdef QT_DEBUG_DRAW
3262 if (qt_show_painter_debug_output)
3263 printf("QPainter::drawRects(), count=%d\n", rectCount);
3264#endif
3265 Q_D(QPainter);
3266
3267 if (!d->engine) {
3268 qWarning("QPainter::drawRects: Painter not active");
3269 return;
3270 }
3271
3272 if (rectCount <= 0)
3273 return;
3274
3275 if (d->extended) {
3276 d->extended->drawRects(rects, rectCount);
3277 return;
3278 }
3279
3280 d->updateState(d->state);
3281
3282 if (!d->state->emulationSpecifier) {
3283 d->engine->drawRects(rects, rectCount);
3284 return;
3285 }
3286
3287 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3288 && d->state->matrix.type() == QTransform::TxTranslate) {
3289 for (int i=0; i<rectCount; ++i) {
3290 QRectF r(rects[i].x() + d->state->matrix.dx(),
3291 rects[i].y() + d->state->matrix.dy(),
3292 rects[i].width(),
3293 rects[i].height());
3294 d->engine->drawRects(&r, 1);
3295 }
3296 } else {
3297 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3298 for (int i=0; i<rectCount; ++i) {
3299 QPainterPath rectPath;
3300 rectPath.addRect(rects[i]);
3301 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3302 }
3303 } else {
3304 QPainterPath rectPath;
3305 for (int i=0; i<rectCount; ++i)
3306 rectPath.addRect(rects[i]);
3307 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3308 }
3309 }
3310}
3311
3319void QPainter::drawRects(const QRect *rects, int rectCount)
3320{
3321#ifdef QT_DEBUG_DRAW
3322 if (qt_show_painter_debug_output)
3323 printf("QPainter::drawRects(), count=%d\n", rectCount);
3324#endif
3325 Q_D(QPainter);
3326
3327 if (!d->engine) {
3328 qWarning("QPainter::drawRects: Painter not active");
3329 return;
3330 }
3331
3332 if (rectCount <= 0)
3333 return;
3334
3335 if (d->extended) {
3336 d->extended->drawRects(rects, rectCount);
3337 return;
3338 }
3339
3340 d->updateState(d->state);
3341
3342 if (!d->state->emulationSpecifier) {
3343 d->engine->drawRects(rects, rectCount);
3344 return;
3345 }
3346
3347 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3348 && d->state->matrix.type() == QTransform::TxTranslate) {
3349 for (int i=0; i<rectCount; ++i) {
3350 QRectF r(rects[i].x() + d->state->matrix.dx(),
3351 rects[i].y() + d->state->matrix.dy(),
3352 rects[i].width(),
3353 rects[i].height());
3354
3355 d->engine->drawRects(&r, 1);
3356 }
3357 } else {
3358 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3359 for (int i=0; i<rectCount; ++i) {
3360 QPainterPath rectPath;
3361 rectPath.addRect(rects[i]);
3362 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3363 }
3364 } else {
3365 QPainterPath rectPath;
3366 for (int i=0; i<rectCount; ++i)
3367 rectPath.addRect(rects[i]);
3368
3369 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3370 }
3371 }
3372}
3373
3419void QPainter::drawPoints(const QPointF *points, int pointCount)
3420{
3421#ifdef QT_DEBUG_DRAW
3422 if (qt_show_painter_debug_output)
3423 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3424#endif
3425 Q_D(QPainter);
3426
3427 if (!d->engine) {
3428 qWarning("QPainter::drawPoints: Painter not active");
3429 return;
3430 }
3431
3432 if (pointCount <= 0)
3433 return;
3434
3435 if (d->extended) {
3436 d->extended->drawPoints(points, pointCount);
3437 return;
3438 }
3439
3440 d->updateState(d->state);
3441
3442 if (!d->state->emulationSpecifier) {
3443 d->engine->drawPoints(points, pointCount);
3444 return;
3445 }
3446
3447 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3448 && d->state->matrix.type() == QTransform::TxTranslate) {
3449 // ### use drawPoints function
3450 for (int i=0; i<pointCount; ++i) {
3451 QPointF pt(points[i].x() + d->state->matrix.dx(),
3452 points[i].y() + d->state->matrix.dy());
3453 d->engine->drawPoints(&pt, 1);
3454 }
3455 } else {
3456 QPen pen = d->state->pen;
3457 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3458 if (flat_pen) {
3459 save();
3461 setPen(pen);
3462 }
3464 for (int i=0; i<pointCount; ++i) {
3465 path.moveTo(points[i].x(), points[i].y());
3466 path.lineTo(points[i].x() + 0.0001, points[i].y());
3467 }
3468 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3469 if (flat_pen)
3470 restore();
3471 }
3472}
3473
3481void QPainter::drawPoints(const QPoint *points, int pointCount)
3482{
3483#ifdef QT_DEBUG_DRAW
3484 if (qt_show_painter_debug_output)
3485 printf("QPainter::drawPoints(), count=%d\n", pointCount);
3486#endif
3487 Q_D(QPainter);
3488
3489 if (!d->engine) {
3490 qWarning("QPainter::drawPoints: Painter not active");
3491 return;
3492 }
3493
3494 if (pointCount <= 0)
3495 return;
3496
3497 if (d->extended) {
3498 d->extended->drawPoints(points, pointCount);
3499 return;
3500 }
3501
3502 d->updateState(d->state);
3503
3504 if (!d->state->emulationSpecifier) {
3505 d->engine->drawPoints(points, pointCount);
3506 return;
3507 }
3508
3509 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3510 && d->state->matrix.type() == QTransform::TxTranslate) {
3511 // ### use drawPoints function
3512 for (int i=0; i<pointCount; ++i) {
3513 QPointF pt(points[i].x() + d->state->matrix.dx(),
3514 points[i].y() + d->state->matrix.dy());
3515 d->engine->drawPoints(&pt, 1);
3516 }
3517 } else {
3518 QPen pen = d->state->pen;
3519 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3520 if (flat_pen) {
3521 save();
3523 setPen(pen);
3524 }
3526 for (int i=0; i<pointCount; ++i) {
3527 path.moveTo(points[i].x(), points[i].y());
3528 path.lineTo(points[i].x() + 0.0001, points[i].y());
3529 }
3530 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3531 if (flat_pen)
3532 restore();
3533 }
3534}
3535
3567{
3568#ifdef QT_DEBUG_DRAW
3569 if (qt_show_painter_debug_output)
3570 printf("QPainter::setBackgroundMode(), mode=%d\n", mode);
3571#endif
3572
3573 Q_D(QPainter);
3574 if (!d->engine) {
3575 qWarning("QPainter::setBackgroundMode: Painter not active");
3576 return;
3577 }
3578 if (d->state->bgMode == mode)
3579 return;
3580
3581 d->state->bgMode = mode;
3582 if (d->extended) {
3583 d->checkEmulation();
3584 } else {
3585 d->state->dirtyFlags |= QPaintEngine::DirtyBackgroundMode;
3586 }
3587}
3588
3595{
3596 Q_D(const QPainter);
3597 if (!d->engine) {
3598 qWarning("QPainter::backgroundMode: Painter not active");
3599 return Qt::TransparentMode;
3600 }
3601 return d->state->bgMode;
3602}
3603
3604
3613{
3614#ifdef QT_DEBUG_DRAW
3615 if (qt_show_painter_debug_output)
3616 printf("QPainter::setPen(), color=%04x\n", color.rgb());
3617#endif
3618 Q_D(QPainter);
3619 if (!d->engine) {
3620 qWarning("QPainter::setPen: Painter not active");
3621 return;
3622 }
3623
3624 QPen pen(color.isValid() ? color : QColor(Qt::black));
3625
3626 if (d->state->pen == pen)
3627 return;
3628
3629 d->state->pen = pen;
3630 if (d->extended)
3631 d->extended->penChanged();
3632 else
3633 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3634}
3635
3645void QPainter::setPen(const QPen &pen)
3646{
3647
3648#ifdef QT_DEBUG_DRAW
3649 if (qt_show_painter_debug_output)
3650 printf("QPainter::setPen(), color=%04x, (brushStyle=%d) style=%d, cap=%d, join=%d\n",
3651 pen.color().rgb(), pen.brush().style(), pen.style(), pen.capStyle(), pen.joinStyle());
3652#endif
3653 Q_D(QPainter);
3654 if (!d->engine) {
3655 qWarning("QPainter::setPen: Painter not active");
3656 return;
3657 }
3658
3659 if (d->state->pen == pen)
3660 return;
3661
3662 d->state->pen = pen;
3663
3664 if (d->extended) {
3665 d->checkEmulation();
3666 d->extended->penChanged();
3667 return;
3668 }
3669
3670 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3671}
3672
3681{
3682 Q_D(QPainter);
3683 if (!d->engine) {
3684 qWarning("QPainter::setPen: Painter not active");
3685 return;
3686 }
3687
3688 QPen pen = QPen(style);
3689
3690 if (d->state->pen == pen)
3691 return;
3692
3693 d->state->pen = pen;
3694
3695 if (d->extended)
3696 d->extended->penChanged();
3697 else
3698 d->state->dirtyFlags |= QPaintEngine::DirtyPen;
3699
3700}
3701
3708const QPen &QPainter::pen() const
3709{
3710 Q_D(const QPainter);
3711 if (!d->engine) {
3712 qWarning("QPainter::pen: Painter not active");
3713 return d->fakeState()->pen;
3714 }
3715 return d->state->pen;
3716}
3717
3718
3728{
3729#ifdef QT_DEBUG_DRAW
3730 if (qt_show_painter_debug_output)
3731 printf("QPainter::setBrush(), color=%04x, style=%d\n", brush.color().rgb(), brush.style());
3732#endif
3733 Q_D(QPainter);
3734 if (!d->engine) {
3735 qWarning("QPainter::setBrush: Painter not active");
3736 return;
3737 }
3738
3739 if (d->state->brush.d == brush.d)
3740 return;
3741
3742 if (d->extended) {
3743 d->state->brush = brush;
3744 d->checkEmulation();
3745 d->extended->brushChanged();
3746 return;
3747 }
3748
3749 d->state->brush = brush;
3750 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3751}
3752
3753
3762{
3763 Q_D(QPainter);
3764 if (!d->engine) {
3765 qWarning("QPainter::setBrush: Painter not active");
3766 return;
3767 }
3768 if (d->state->brush.style() == style &&
3769 (style == Qt::NoBrush
3770 || (style == Qt::SolidPattern && d->state->brush.color() == QColor(0, 0, 0))))
3771 return;
3772 d->state->brush = QBrush(Qt::black, style);
3773 if (d->extended)
3774 d->extended->brushChanged();
3775 else
3776 d->state->dirtyFlags |= QPaintEngine::DirtyBrush;
3777}
3778
3786{
3787 Q_D(const QPainter);
3788 if (!d->engine) {
3789 qWarning("QPainter::brush: Painter not active");
3790 return d->fakeState()->brush;
3791 }
3792 return d->state->brush;
3793}
3794
3809{
3810#ifdef QT_DEBUG_DRAW
3811 if (qt_show_painter_debug_output)
3812 printf("QPainter::setBackground(), color=%04x, style=%d\n", bg.color().rgb(), bg.style());
3813#endif
3814
3815 Q_D(QPainter);
3816 if (!d->engine) {
3817 qWarning("QPainter::setBackground: Painter not active");
3818 return;
3819 }
3820 d->state->bgBrush = bg;
3821 if (!d->extended)
3822 d->state->dirtyFlags |= QPaintEngine::DirtyBackground;
3823}
3824
3839{
3840 Q_D(QPainter);
3841
3842#ifdef QT_DEBUG_DRAW
3843 if (qt_show_painter_debug_output)
3844 printf("QPainter::setFont(), family=%s, pointSize=%d\n", font.families().first().toLatin1().constData(), font.pointSize());
3845#endif
3846
3847 if (!d->engine) {
3848 qWarning("QPainter::setFont: Painter not active");
3849 return;
3850 }
3851
3852 d->state->font = QFont(font.resolve(d->state->deviceFont), device());
3853 if (!d->extended)
3854 d->state->dirtyFlags |= QPaintEngine::DirtyFont;
3855}
3856
3862const QFont &QPainter::font() const
3863{
3864 Q_D(const QPainter);
3865 if (!d->engine) {
3866 qWarning("QPainter::font: Painter not active");
3867 return d->fakeState()->font;
3868 }
3869 return d->state->font;
3870}
3871
3897{
3898#ifdef QT_DEBUG_DRAW
3899 if (qt_show_painter_debug_output)
3900 printf("QPainter::drawRoundedRect(), [%.2f,%.2f,%.2f,%.2f]\n", rect.x(), rect.y(), rect.width(), rect.height());
3901#endif
3902 Q_D(QPainter);
3903
3904 if (!d->engine)
3905 return;
3906
3907 if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
3908 drawRect(rect);
3909 return;
3910 }
3911
3912 if (d->extended) {
3913 d->extended->drawRoundedRect(rect, xRadius, yRadius, mode);
3914 return;
3915 }
3916
3918 path.addRoundedRect(rect, xRadius, yRadius, mode);
3919 drawPath(path);
3920}
3921
3959{
3960#ifdef QT_DEBUG_DRAW
3961 if (qt_show_painter_debug_output)
3962 printf("QPainter::drawEllipse(), [%.2f,%.2f,%.2f,%.2f]\n", r.x(), r.y(), r.width(), r.height());
3963#endif
3964 Q_D(QPainter);
3965
3966 if (!d->engine)
3967 return;
3968
3969 QRectF rect(r.normalized());
3970
3971 if (d->extended) {
3972 d->extended->drawEllipse(rect);
3973 return;
3974 }
3975
3976 d->updateState(d->state);
3977 if (d->state->emulationSpecifier) {
3978 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3979 && d->state->matrix.type() == QTransform::TxTranslate) {
3980 rect.translate(QPointF(d->state->matrix.dx(), d->state->matrix.dy()));
3981 } else {
3983 path.addEllipse(rect);
3985 return;
3986 }
3987 }
3988
3989 d->engine->drawEllipse(rect);
3990}
3991
4000{
4001#ifdef QT_DEBUG_DRAW
4002 if (qt_show_painter_debug_output)
4003 printf("QPainter::drawEllipse(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
4004#endif
4005 Q_D(QPainter);
4006
4007 if (!d->engine)
4008 return;
4009
4010 QRect rect(r.normalized());
4011
4012 if (d->extended) {
4013 d->extended->drawEllipse(rect);
4014 return;
4015 }
4016
4017 d->updateState(d->state);
4018
4019 if (d->state->emulationSpecifier) {
4020 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
4021 && d->state->matrix.type() == QTransform::TxTranslate) {
4022 rect.translate(QPoint(qRound(d->state->matrix.dx()), qRound(d->state->matrix.dy())));
4023 } else {
4025 path.addEllipse(rect);
4027 return;
4028 }
4029 }
4030
4031 d->engine->drawEllipse(rect);
4032}
4033
4085void QPainter::drawArc(const QRectF &r, int a, int alen)
4086{
4087#ifdef QT_DEBUG_DRAW
4088 if (qt_show_painter_debug_output)
4089 printf("QPainter::drawArc(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4090 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4091#endif
4092 Q_D(QPainter);
4093
4094 if (!d->engine)
4095 return;
4096
4097 QRectF rect = r.normalized();
4098
4100 path.arcMoveTo(rect, a/16.0);
4101 path.arcTo(rect, a/16.0, alen/16.0);
4102 strokePath(path, d->state->pen);
4103}
4104
4147void QPainter::drawPie(const QRectF &r, int a, int alen)
4148{
4149#ifdef QT_DEBUG_DRAW
4150 if (qt_show_painter_debug_output)
4151 printf("QPainter::drawPie(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4152 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4153#endif
4154 Q_D(QPainter);
4155
4156 if (!d->engine)
4157 return;
4158
4159 if (a > (360*16)) {
4160 a = a % (360*16);
4161 } else if (a < 0) {
4162 a = a % (360*16);
4163 if (a < 0) a += (360*16);
4164 }
4165
4166 QRectF rect = r.normalized();
4167
4169 path.moveTo(rect.center());
4170 path.arcTo(rect.x(), rect.y(), rect.width(), rect.height(), a/16.0, alen/16.0);
4171 path.closeSubpath();
4172 drawPath(path);
4173
4174}
4175
4216void QPainter::drawChord(const QRectF &r, int a, int alen)
4217{
4218#ifdef QT_DEBUG_DRAW
4219 if (qt_show_painter_debug_output)
4220 printf("QPainter::drawChord(), [%.2f,%.2f,%.2f,%.2f], angle=%d, sweep=%d\n",
4221 r.x(), r.y(), r.width(), r.height(), a/16, alen/16);
4222#endif
4223 Q_D(QPainter);
4224
4225 if (!d->engine)
4226 return;
4227
4228 QRectF rect = r.normalized();
4229
4231 path.arcMoveTo(rect, a/16.0);
4232 path.arcTo(rect, a/16.0, alen/16.0);
4233 path.closeSubpath();
4234 drawPath(path);
4235}
4263void QPainter::drawLines(const QLineF *lines, int lineCount)
4264{
4265#ifdef QT_DEBUG_DRAW
4266 if (qt_show_painter_debug_output)
4267 printf("QPainter::drawLines(), line count=%d\n", lineCount);
4268#endif
4269
4270 Q_D(QPainter);
4271
4272 if (!d->engine || lineCount < 1)
4273 return;
4274
4275 if (d->extended) {
4276 d->extended->drawLines(lines, lineCount);
4277 return;
4278 }
4279
4280 d->updateState(d->state);
4281
4282 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4283
4284 if (lineEmulation) {
4285 if (lineEmulation == QPaintEngine::PrimitiveTransform
4286 && d->state->matrix.type() == QTransform::TxTranslate) {
4287 for (int i = 0; i < lineCount; ++i) {
4288 QLineF line = lines[i];
4289 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4290 d->engine->drawLines(&line, 1);
4291 }
4292 } else {
4293 QPainterPath linePath;
4294 for (int i = 0; i < lineCount; ++i) {
4295 linePath.moveTo(lines[i].p1());
4296 linePath.lineTo(lines[i].p2());
4297 }
4298 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4299 }
4300 return;
4301 }
4302 d->engine->drawLines(lines, lineCount);
4303}
4304
4312void QPainter::drawLines(const QLine *lines, int lineCount)
4313{
4314#ifdef QT_DEBUG_DRAW
4315 if (qt_show_painter_debug_output)
4316 printf("QPainter::drawLine(), line count=%d\n", lineCount);
4317#endif
4318
4319 Q_D(QPainter);
4320
4321 if (!d->engine || lineCount < 1)
4322 return;
4323
4324 if (d->extended) {
4325 d->extended->drawLines(lines, lineCount);
4326 return;
4327 }
4328
4329 d->updateState(d->state);
4330
4331 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4332
4333 if (lineEmulation) {
4334 if (lineEmulation == QPaintEngine::PrimitiveTransform
4335 && d->state->matrix.type() == QTransform::TxTranslate) {
4336 for (int i = 0; i < lineCount; ++i) {
4337 QLineF line = lines[i];
4338 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4339 d->engine->drawLines(&line, 1);
4340 }
4341 } else {
4342 QPainterPath linePath;
4343 for (int i = 0; i < lineCount; ++i) {
4344 linePath.moveTo(lines[i].p1());
4345 linePath.lineTo(lines[i].p2());
4346 }
4347 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4348 }
4349 return;
4350 }
4351 d->engine->drawLines(lines, lineCount);
4352}
4353
4362void QPainter::drawLines(const QPointF *pointPairs, int lineCount)
4363{
4364 Q_ASSERT(sizeof(QLineF) == 2*sizeof(QPointF));
4365
4366 drawLines((const QLineF*)pointPairs, lineCount);
4367}
4368
4375void QPainter::drawLines(const QPoint *pointPairs, int lineCount)
4376{
4377 Q_ASSERT(sizeof(QLine) == 2*sizeof(QPoint));
4378
4379 drawLines((const QLine*)pointPairs, lineCount);
4380}
4381
4382
4431void QPainter::drawPolyline(const QPointF *points, int pointCount)
4432{
4433#ifdef QT_DEBUG_DRAW
4434 if (qt_show_painter_debug_output)
4435 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4436#endif
4437 Q_D(QPainter);
4438
4439 if (!d->engine || pointCount < 2)
4440 return;
4441
4442 if (d->extended) {
4443 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4444 return;
4445 }
4446
4447 d->updateState(d->state);
4448
4449 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4450
4451 if (lineEmulation) {
4452 // ###
4453// if (lineEmulation == QPaintEngine::PrimitiveTransform
4454// && d->state->matrix.type() == QTransform::TxTranslate) {
4455// } else {
4456 QPainterPath polylinePath(points[0]);
4457 for (int i=1; i<pointCount; ++i)
4458 polylinePath.lineTo(points[i]);
4459 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4460// }
4461 } else {
4462 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4463 }
4464}
4465
4472void QPainter::drawPolyline(const QPoint *points, int pointCount)
4473{
4474#ifdef QT_DEBUG_DRAW
4475 if (qt_show_painter_debug_output)
4476 printf("QPainter::drawPolyline(), count=%d\n", pointCount);
4477#endif
4478 Q_D(QPainter);
4479
4480 if (!d->engine || pointCount < 2)
4481 return;
4482
4483 if (d->extended) {
4484 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4485 return;
4486 }
4487
4488 d->updateState(d->state);
4489
4490 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4491
4492 if (lineEmulation) {
4493 // ###
4494// if (lineEmulation == QPaintEngine::PrimitiveTransform
4495// && d->state->matrix.type() == QTransform::TxTranslate) {
4496// } else {
4497 QPainterPath polylinePath(points[0]);
4498 for (int i=1; i<pointCount; ++i)
4499 polylinePath.lineTo(points[i]);
4500 d->draw_helper(polylinePath, QPainterPrivate::StrokeDraw);
4501// }
4502 } else {
4503 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolylineMode);
4504 }
4505}
4506
4547void QPainter::drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
4548{
4549#ifdef QT_DEBUG_DRAW
4550 if (qt_show_painter_debug_output)
4551 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4552#endif
4553
4554 Q_D(QPainter);
4555
4556 if (!d->engine || pointCount < 2)
4557 return;
4558
4559 if (d->extended) {
4560 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4561 return;
4562 }
4563
4564 d->updateState(d->state);
4565
4566 uint emulationSpecifier = d->state->emulationSpecifier;
4567
4568 if (emulationSpecifier) {
4569 QPainterPath polygonPath(points[0]);
4570 for (int i=1; i<pointCount; ++i)
4571 polygonPath.lineTo(points[i]);
4572 polygonPath.closeSubpath();
4573 polygonPath.setFillRule(fillRule);
4574 d->draw_helper(polygonPath);
4575 return;
4576 }
4577
4578 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4579}
4580
4586void QPainter::drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule)
4587{
4588#ifdef QT_DEBUG_DRAW
4589 if (qt_show_painter_debug_output)
4590 printf("QPainter::drawPolygon(), count=%d\n", pointCount);
4591#endif
4592
4593 Q_D(QPainter);
4594
4595 if (!d->engine || pointCount < 2)
4596 return;
4597
4598 if (d->extended) {
4599 d->extended->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4600 return;
4601 }
4602
4603 d->updateState(d->state);
4604
4605 uint emulationSpecifier = d->state->emulationSpecifier;
4606
4607 if (emulationSpecifier) {
4608 QPainterPath polygonPath(points[0]);
4609 for (int i=1; i<pointCount; ++i)
4610 polygonPath.lineTo(points[i]);
4611 polygonPath.closeSubpath();
4612 polygonPath.setFillRule(fillRule);
4613 d->draw_helper(polygonPath);
4614 return;
4615 }
4616
4617 d->engine->drawPolygon(points, pointCount, QPaintEngine::PolygonDrawMode(fillRule));
4618}
4619
4685void QPainter::drawConvexPolygon(const QPoint *points, int pointCount)
4686{
4687#ifdef QT_DEBUG_DRAW
4688 if (qt_show_painter_debug_output)
4689 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4690#endif
4691
4692 Q_D(QPainter);
4693
4694 if (!d->engine || pointCount < 2)
4695 return;
4696
4697 if (d->extended) {
4698 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4699 return;
4700 }
4701
4702 d->updateState(d->state);
4703
4704 uint emulationSpecifier = d->state->emulationSpecifier;
4705
4706 if (emulationSpecifier) {
4707 QPainterPath polygonPath(points[0]);
4708 for (int i=1; i<pointCount; ++i)
4709 polygonPath.lineTo(points[i]);
4710 polygonPath.closeSubpath();
4711 polygonPath.setFillRule(Qt::WindingFill);
4712 d->draw_helper(polygonPath);
4713 return;
4714 }
4715
4716 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4717}
4718
4719void QPainter::drawConvexPolygon(const QPointF *points, int pointCount)
4720{
4721#ifdef QT_DEBUG_DRAW
4722 if (qt_show_painter_debug_output)
4723 printf("QPainter::drawConvexPolygon(), count=%d\n", pointCount);
4724#endif
4725
4726 Q_D(QPainter);
4727
4728 if (!d->engine || pointCount < 2)
4729 return;
4730
4731 if (d->extended) {
4732 d->extended->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4733 return;
4734 }
4735
4736 d->updateState(d->state);
4737
4738 uint emulationSpecifier = d->state->emulationSpecifier;
4739
4740 if (emulationSpecifier) {
4741 QPainterPath polygonPath(points[0]);
4742 for (int i=1; i<pointCount; ++i)
4743 polygonPath.lineTo(points[i]);
4744 polygonPath.closeSubpath();
4745 polygonPath.setFillRule(Qt::WindingFill);
4746 d->draw_helper(polygonPath);
4747 return;
4748 }
4749
4750 d->engine->drawPolygon(points, pointCount, QPaintEngine::ConvexMode);
4751}
4752
4754{
4755 return m.inverted().map(QPointF(m.map(p).toPoint()));
4756}
4757
4783void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
4784{
4785#if defined QT_DEBUG_DRAW
4786 if (qt_show_painter_debug_output)
4787 printf("QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4788 p.x(), p.y(),
4789 pm.width(), pm.height());
4790#endif
4791
4792 Q_D(QPainter);
4793
4794 if (!d->engine || pm.isNull())
4795 return;
4796
4797#ifndef QT_NO_DEBUG
4798 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4799#endif
4800
4801 if (d->extended) {
4802 d->extended->drawPixmap(p, pm);
4803 return;
4804 }
4805
4806 qreal x = p.x();
4807 qreal y = p.y();
4808
4809 int w = pm.width();
4810 int h = pm.height();
4811
4812 if (w <= 0)
4813 return;
4814
4815 // Emulate opaque background for bitmaps
4816 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4817 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4818 }
4819
4820 d->updateState(d->state);
4821
4822 if ((d->state->matrix.type() > QTransform::TxTranslate
4823 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4824 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4825 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4826 {
4827 save();
4828 // If there is no rotation involved we have to make sure we use the
4829 // antialiased and not the aliased coordinate system by rounding the coordinates.
4830 if (d->state->matrix.type() <= QTransform::TxScale) {
4831 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4832 x = p.x();
4833 y = p.y();
4834 }
4835 translate(x, y);
4838 QBrush brush(d->state->pen.color(), pm);
4839 setBrush(brush);
4841 setBrushOrigin(QPointF(0, 0));
4842
4843 drawRect(pm.rect());
4844 restore();
4845 } else {
4846 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4847 x += d->state->matrix.dx();
4848 y += d->state->matrix.dy();
4849 }
4851 d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4852 }
4853}
4854
4855void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
4856{
4857#if defined QT_DEBUG_DRAW
4858 if (qt_show_painter_debug_output)
4859 printf("QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4860 r.x(), r.y(), r.width(), r.height(),
4861 pm.width(), pm.height(),
4862 sr.x(), sr.y(), sr.width(), sr.height());
4863#endif
4864
4865 Q_D(QPainter);
4866 if (!d->engine || pm.isNull())
4867 return;
4868#ifndef QT_NO_DEBUG
4869 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawPixmap()");
4870#endif
4871
4872 qreal x = r.x();
4873 qreal y = r.y();
4874 qreal w = r.width();
4875 qreal h = r.height();
4876 qreal sx = sr.x();
4877 qreal sy = sr.y();
4878 qreal sw = sr.width();
4879 qreal sh = sr.height();
4880
4881 // Get pixmap scale. Use it when calculating the target
4882 // rect size from pixmap size. For example, a 2X 64x64 pixel
4883 // pixmap should result in a 32x32 point target rect.
4884 const qreal pmscale = pm.devicePixelRatio();
4885
4886 // Sanity-check clipping
4887 if (sw <= 0)
4888 sw = pm.width() - sx;
4889
4890 if (sh <= 0)
4891 sh = pm.height() - sy;
4892
4893 if (w < 0)
4894 w = sw / pmscale;
4895 if (h < 0)
4896 h = sh / pmscale;
4897
4898 if (sx < 0) {
4899 qreal w_ratio = sx * w/sw;
4900 x -= w_ratio;
4901 w += w_ratio;
4902 sw += sx;
4903 sx = 0;
4904 }
4905
4906 if (sy < 0) {
4907 qreal h_ratio = sy * h/sh;
4908 y -= h_ratio;
4909 h += h_ratio;
4910 sh += sy;
4911 sy = 0;
4912 }
4913
4914 if (sw + sx > pm.width()) {
4915 qreal delta = sw - (pm.width() - sx);
4916 qreal w_ratio = delta * w/sw;
4917 sw -= delta;
4918 w -= w_ratio;
4919 }
4920
4921 if (sh + sy > pm.height()) {
4922 qreal delta = sh - (pm.height() - sy);
4923 qreal h_ratio = delta * h/sh;
4924 sh -= delta;
4925 h -= h_ratio;
4926 }
4927
4928 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
4929 return;
4930
4931 if (d->extended) {
4932 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
4933 return;
4934 }
4935
4936 // Emulate opaque background for bitmaps
4937 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
4938 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4939
4940 d->updateState(d->state);
4941
4942 if ((d->state->matrix.type() > QTransform::TxTranslate
4943 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4944 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4945 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
4946 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
4947 {
4948 save();
4949 // If there is no rotation involved we have to make sure we use the
4950 // antialiased and not the aliased coordinate system by rounding the coordinates.
4951 if (d->state->matrix.type() <= QTransform::TxScale) {
4952 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4953 x = p.x();
4954 y = p.y();
4955 }
4956
4957 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
4958 sx = qRound(sx);
4959 sy = qRound(sy);
4960 sw = qRound(sw);
4961 sh = qRound(sh);
4962 }
4963
4964 translate(x, y);
4965 scale(w / sw, h / sh);
4968 QBrush brush;
4969
4970 if (sw == pm.width() && sh == pm.height())
4971 brush = QBrush(d->state->pen.color(), pm);
4972 else
4973 brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
4974
4975 setBrush(brush);
4977
4978 drawRect(QRectF(0, 0, sw, sh));
4979 restore();
4980 } else {
4981 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4982 x += d->state->matrix.dx();
4983 y += d->state->matrix.dy();
4984 }
4985 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
4986 }
4987}
4988
4989
5093{
5094 Q_D(QPainter);
5095
5096 if (!d->engine || image.isNull())
5097 return;
5098
5099 if (d->extended) {
5100 d->extended->drawImage(p, image);
5101 return;
5102 }
5103
5104 qreal x = p.x();
5105 qreal y = p.y();
5106
5107 int w = image.width();
5108 int h = image.height();
5109 qreal scale = image.devicePixelRatio();
5110
5111 d->updateState(d->state);
5112
5113 if (((d->state->matrix.type() > QTransform::TxTranslate)
5114 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5115 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5116 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5117 {
5118 save();
5119 // If there is no rotation involved we have to make sure we use the
5120 // antialiased and not the aliased coordinate system by rounding the coordinates.
5121 if (d->state->matrix.type() <= QTransform::TxScale) {
5122 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5123 x = p.x();
5124 y = p.y();
5125 }
5126 translate(x, y);
5130 setBrush(brush);
5132 setBrushOrigin(QPointF(0, 0));
5133 drawRect(QRect(QPoint(0, 0), image.size() / scale));
5134 restore();
5135 return;
5136 }
5137
5138 if (d->state->matrix.type() == QTransform::TxTranslate
5139 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5140 x += d->state->matrix.dx();
5141 y += d->state->matrix.dy();
5142 }
5143
5144 d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5145}
5146
5147void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect,
5148 Qt::ImageConversionFlags flags)
5149{
5150 Q_D(QPainter);
5151
5152 if (!d->engine || image.isNull())
5153 return;
5154
5155 qreal x = targetRect.x();
5156 qreal y = targetRect.y();
5157 qreal w = targetRect.width();
5158 qreal h = targetRect.height();
5159 qreal sx = sourceRect.x();
5160 qreal sy = sourceRect.y();
5161 qreal sw = sourceRect.width();
5162 qreal sh = sourceRect.height();
5163 qreal imageScale = image.devicePixelRatio();
5164
5165 // Sanity-check clipping
5166 if (sw <= 0)
5167 sw = image.width() - sx;
5168
5169 if (sh <= 0)
5170 sh = image.height() - sy;
5171
5172 if (w < 0)
5173 w = sw / imageScale;
5174 if (h < 0)
5175 h = sh / imageScale;
5176
5177 if (sx < 0) {
5178 qreal w_ratio = sx * w/sw;
5179 x -= w_ratio;
5180 w += w_ratio;
5181 sw += sx;
5182 sx = 0;
5183 }
5184
5185 if (sy < 0) {
5186 qreal h_ratio = sy * h/sh;
5187 y -= h_ratio;
5188 h += h_ratio;
5189 sh += sy;
5190 sy = 0;
5191 }
5192
5193 if (sw + sx > image.width()) {
5194 qreal delta = sw - (image.width() - sx);
5195 qreal w_ratio = delta * w/sw;
5196 sw -= delta;
5197 w -= w_ratio;
5198 }
5199
5200 if (sh + sy > image.height()) {
5201 qreal delta = sh - (image.height() - sy);
5202 qreal h_ratio = delta * h/sh;
5203 sh -= delta;
5204 h -= h_ratio;
5205 }
5206
5207 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5208 return;
5209
5210 if (d->extended) {
5211 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5212 return;
5213 }
5214
5215 d->updateState(d->state);
5216
5217 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5218 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5219 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5220 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5221 {
5222 save();
5223 // If there is no rotation involved we have to make sure we use the
5224 // antialiased and not the aliased coordinate system by rounding the coordinates.
5225 if (d->state->matrix.type() <= QTransform::TxScale) {
5226 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5227 x = p.x();
5228 y = p.y();
5229 }
5230
5231 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5232 sx = qRound(sx);
5233 sy = qRound(sy);
5234 sw = qRound(sw);
5235 sh = qRound(sh);
5236 }
5237 translate(x, y);
5238 scale(w / sw, h / sh);
5242 setBrush(brush);
5244 setBrushOrigin(QPointF(-sx, -sy));
5245
5246 drawRect(QRectF(0, 0, sw, sh));
5247 restore();
5248 return;
5249 }
5250
5251 if (d->state->matrix.type() == QTransform::TxTranslate
5252 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5253 x += d->state->matrix.dx();
5254 y += d->state->matrix.dy();
5255 }
5256
5257 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5258}
5259
5271#if !defined(QT_NO_RAWFONT)
5273{
5274 Q_D(QPainter);
5275
5276 if (!d->engine) {
5277 qWarning("QPainter::drawGlyphRun: Painter not active");
5278 return;
5279 }
5280
5281 QRawFont font = glyphRun.rawFont();
5282 if (!font.isValid())
5283 return;
5284
5285 QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5286
5287 const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5288 const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5289
5290 int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5291 QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5292
5294 bool engineRequiresPretransformedGlyphPositions = d->extended
5295 ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5296 : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5297
5298 for (int i=0; i<count; ++i) {
5299 QPointF processedPosition = position + glyphPositions[i];
5300 if (engineRequiresPretransformedGlyphPositions)
5301 processedPosition = d->state->transform().map(processedPosition);
5302 fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5303 }
5304
5305 d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5306 ? d->state->transform().map(position)
5307 : position,
5308 glyphIndexes,
5309 fixedPointPositions.data(),
5310 count,
5311 fontD->fontEngine,
5312 glyphRun.overline(),
5313 glyphRun.underline(),
5314 glyphRun.strikeOut());
5315}
5316
5317void QPainterPrivate::drawGlyphs(const QPointF &decorationPosition,
5318 const quint32 *glyphArray,
5320 int glyphCount,
5321 QFontEngine *fontEngine,
5322 bool overline,
5323 bool underline,
5324 bool strikeOut)
5325{
5326 Q_Q(QPainter);
5327
5329
5330 if (extended != nullptr && state->matrix.isAffine()) {
5331 QStaticTextItem staticTextItem;
5332 staticTextItem.color = state->pen.color();
5333 staticTextItem.font = state->font;
5334 staticTextItem.setFontEngine(fontEngine);
5335 staticTextItem.numGlyphs = glyphCount;
5336 staticTextItem.glyphs = reinterpret_cast<glyph_t *>(const_cast<glyph_t *>(glyphArray));
5337 staticTextItem.glyphPositions = positions;
5338 // The font property is meaningless, the fontengine must be used directly:
5339 staticTextItem.usesRawFont = true;
5340
5341 extended->drawStaticTextItem(&staticTextItem);
5342 } else {
5343 QTextItemInt textItem;
5344 textItem.fontEngine = fontEngine;
5345
5346 QVarLengthArray<QFixed, 128> advances(glyphCount);
5347 QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5348 QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5349 memset(glyphAttributes.data(), 0, glyphAttributes.size() * sizeof(QGlyphAttributes));
5350 memset(static_cast<void *>(advances.data()), 0, advances.size() * sizeof(QFixed));
5351 memset(static_cast<void *>(glyphJustifications.data()), 0, glyphJustifications.size() * sizeof(QGlyphJustification));
5352
5353 textItem.glyphs.numGlyphs = glyphCount;
5354 textItem.glyphs.glyphs = const_cast<glyph_t *>(glyphArray);
5355 textItem.glyphs.offsets = positions;
5356 textItem.glyphs.advances = advances.data();
5357 textItem.glyphs.justifications = glyphJustifications.data();
5358 textItem.glyphs.attributes = glyphAttributes.data();
5359
5360 engine->drawTextItem(QPointF(0, 0), textItem);
5361 }
5362
5364 decorationPosition,
5365 glyphArray,
5366 positions,
5367 glyphCount,
5368 fontEngine,
5369 underline,
5370 overline,
5371 strikeOut);
5372}
5373#endif // QT_NO_RAWFONT
5374
5417{
5418 drawText(p, str, 0, 0);
5419}
5420
5442void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText)
5443{
5444 Q_D(QPainter);
5445 if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5446 return;
5447
5448 QStaticTextPrivate *staticText_d =
5449 const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5450
5452 QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5453 if (font() != staticText_d->font || fp == nullptr || stfp == nullptr || fp->dpi != stfp->dpi) {
5454 staticText_d->font = font();
5455 staticText_d->needsRelayout = true;
5456 } else if (stfp->engineData == nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5457 staticText_d->needsRelayout = true;
5458 }
5459
5460 QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5461 if (fe->type() == QFontEngine::Multi)
5462 fe = static_cast<QFontEngineMulti *>(fe)->engine(0);
5463
5464 // If we don't have an extended paint engine, if the painter is projected,
5465 // or if the font engine does not support the matrix, we go through standard
5466 // code path
5467 if (d->extended == nullptr
5468 || !d->state->matrix.isAffine()
5469 || !fe->supportsTransformation(d->state->matrix)) {
5470 staticText_d->paintText(topLeftPosition, this, pen().color());
5471 return;
5472 }
5473
5474 bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5475 if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5476 // The coordinates are untransformed, and the engine can't deal with that
5477 // nativly, so we have to pre-transform the static text.
5478 staticText_d->untransformedCoordinates = false;
5479 staticText_d->needsRelayout = true;
5480 } else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5481 // The coordinates are already transformed, but the engine can handle that
5482 // nativly, so undo the transform of the static text.
5483 staticText_d->untransformedCoordinates = true;
5484 staticText_d->needsRelayout = true;
5485 }
5486
5487 // Don't recalculate entire layout because of translation, rather add the dx and dy
5488 // into the position to move each text item the correct distance.
5489 QPointF transformedPosition = topLeftPosition;
5490 if (!staticText_d->untransformedCoordinates)
5491 transformedPosition = transformedPosition * d->state->matrix;
5492 QTransform oldMatrix;
5493
5494 // The translation has been applied to transformedPosition. Remove translation
5495 // component from matrix.
5496 if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5497 qreal m11 = d->state->matrix.m11();
5498 qreal m12 = d->state->matrix.m12();
5499 qreal m13 = d->state->matrix.m13();
5500 qreal m21 = d->state->matrix.m21();
5501 qreal m22 = d->state->matrix.m22();
5502 qreal m23 = d->state->matrix.m23();
5503 qreal m33 = d->state->matrix.m33();
5504
5505 oldMatrix = d->state->matrix;
5506 d->state->matrix.setMatrix(m11, m12, m13,
5507 m21, m22, m23,
5508 0.0, 0.0, m33);
5509 }
5510
5511 // If the transform is not identical to the text transform,
5512 // we have to relayout the text (for other transformations than plain translation)
5513 bool staticTextNeedsReinit = staticText_d->needsRelayout;
5514 if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5515 staticText_d->matrix = d->state->matrix;
5516 staticTextNeedsReinit = true;
5517 }
5518
5519 // Recreate the layout of the static text because the matrix or font has changed
5520 if (staticTextNeedsReinit)
5521 staticText_d->init();
5522
5523 if (transformedPosition != staticText_d->position) { // Translate to actual position
5524 QFixed fx = QFixed::fromReal(transformedPosition.x());
5525 QFixed fy = QFixed::fromReal(transformedPosition.y());
5526 QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5527 QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5528 for (int item=0; item<staticText_d->itemCount;++item) {
5529 QStaticTextItem *textItem = staticText_d->items + item;
5530 for (int i=0; i<textItem->numGlyphs; ++i) {
5531 textItem->glyphPositions[i].x += fx - oldX;
5532 textItem->glyphPositions[i].y += fy - oldY;
5533 }
5534 textItem->userDataNeedsUpdate = true;
5535 }
5536
5537 staticText_d->position = transformedPosition;
5538 }
5539
5540 QPen oldPen = d->state->pen;
5541 QColor currentColor = oldPen.color();
5542 static const QColor bodyIndicator(0, 0, 0, 0);
5543 for (int i=0; i<staticText_d->itemCount; ++i) {
5544 QStaticTextItem *item = staticText_d->items + i;
5545 if (item->color.isValid() && currentColor != item->color
5546 && item->color != bodyIndicator) {
5547 setPen(item->color);
5548 currentColor = item->color;
5549 } else if (item->color == bodyIndicator) {
5550 setPen(oldPen);
5551 currentColor = oldPen.color();
5552 }
5553 d->extended->drawStaticTextItem(item);
5554
5556 topLeftPosition,
5557 item->glyphs,
5558 item->glyphPositions,
5559 item->numGlyphs,
5560 item->fontEngine(),
5561 staticText_d->font.underline(),
5562 staticText_d->font.overline(),
5563 staticText_d->font.strikeOut());
5564 }
5565 if (currentColor != oldPen.color())
5566 setPen(oldPen);
5567
5568 if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5569 d->state->matrix = oldMatrix;
5570}
5571
5575void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding)
5576{
5577#ifdef QT_DEBUG_DRAW
5578 if (qt_show_painter_debug_output)
5579 printf("QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5580#endif
5581
5582 Q_D(QPainter);
5583
5584 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5585 return;
5586
5587 QStackTextEngine engine(str, d->state->font);
5588 engine.option.setTextDirection(d->state->layoutDirection);
5590 engine.ignoreBidi = true;
5591 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5592 }
5593 engine.itemize();
5595 line.length = str.size();
5596 engine.shapeLine(line);
5597
5598 int nItems = engine.layoutData->items.size();
5599 QVarLengthArray<int> visualOrder(nItems);
5601 for (int i = 0; i < nItems; ++i)
5602 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5603 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5604
5605 if (justificationPadding > 0) {
5606 engine.option.setAlignment(Qt::AlignJustify);
5607 engine.forceJustification = true;
5608 // this works because justify() is only interested in the difference between width and textWidth
5609 line.width = justificationPadding;
5610 engine.justify(line);
5611 }
5612 QFixed x = QFixed::fromReal(p.x());
5613
5614 for (int i = 0; i < nItems; ++i) {
5615 int item = visualOrder[i];
5616 const QScriptItem &si = engine.layoutData->items.at(item);
5618 x += si.width;
5619 continue;
5620 }
5621 QFont f = engine.font(si);
5622 QTextItemInt gf(si, &f);
5623 gf.glyphs = engine.shapedGlyphs(&si);
5624 gf.chars = engine.layoutData->string.unicode() + si.position;
5625 gf.num_chars = engine.length(item);
5626 if (engine.forceJustification) {
5627 for (int j=0; j<gf.glyphs.numGlyphs; ++j)
5628 gf.width += gf.glyphs.effectiveAdvance(j);
5629 } else {
5630 gf.width = si.width;
5631 }
5632 gf.logClusters = engine.logClusters(&si);
5633
5634 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5635
5636 x += gf.width;
5637 }
5638}
5639
5640void QPainter::drawText(const QRect &r, int flags, const QString &str, QRect *br)
5641{
5642#ifdef QT_DEBUG_DRAW
5643 if (qt_show_painter_debug_output)
5644 printf("QPainter::drawText(), r=[%d,%d,%d,%d], flags=%d, str='%s'\n",
5645 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5646#endif
5647
5648 Q_D(QPainter);
5649
5650 if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5651 return;
5652
5653 if (!d->extended)
5654 d->updateState(d->state);
5655
5656 QRectF bounds;
5657 qt_format_text(d->state->font, r, flags, nullptr, str, br ? &bounds : nullptr, 0, nullptr, 0, this);
5658 if (br)
5659 *br = bounds.toAlignedRect();
5660}
5661
5727void QPainter::drawText(const QRectF &r, int flags, const QString &str, QRectF *br)
5728{
5729#ifdef QT_DEBUG_DRAW
5730 if (qt_show_painter_debug_output)
5731 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], flags=%d, str='%s'\n",
5732 r.x(), r.y(), r.width(), r.height(), flags, str.toLatin1().constData());
5733#endif
5734
5735 Q_D(QPainter);
5736
5737 if (!d->engine || str.size() == 0 || pen().style() == Qt::NoPen)
5738 return;
5739
5740 if (!d->extended)
5741 d->updateState(d->state);
5742
5743 qt_format_text(d->state->font, r, flags, nullptr, str, br, 0, nullptr, 0, this);
5744}
5745
5847{
5848#ifdef QT_DEBUG_DRAW
5849 if (qt_show_painter_debug_output)
5850 printf("QPainter::drawText(), r=[%.2f,%.2f,%.2f,%.2f], str='%s'\n",
5851 r.x(), r.y(), r.width(), r.height(), text.toLatin1().constData());
5852#endif
5853
5854 Q_D(QPainter);
5855
5856 if (!d->engine || text.size() == 0 || pen().style() == Qt::NoPen)
5857 return;
5858
5859 if (!d->extended)
5860 d->updateState(d->state);
5861
5862 qt_format_text(d->state->font, r, 0, &o, text, nullptr, 0, nullptr, 0, this);
5863}
5864
5900static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen)
5901{
5902 const qreal radiusBase = qMax(qreal(1), maxRadius);
5903
5904 QString key = "WaveUnderline-"_L1
5905 % pen.color().name()
5906 % HexString<qreal>(radiusBase)
5907 % HexString<qreal>(pen.widthF());
5908
5911 return pixmap;
5912
5913 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399)); // the golden ratio
5914 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
5915 const qreal radius = qFloor(radiusBase * 2) / 2.;
5916
5918
5919 qreal xs = 0;
5920 qreal ys = radius;
5921
5922 while (xs < width) {
5923 xs += halfPeriod;
5924 ys = -ys;
5925 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
5926 }
5927
5928 pixmap = QPixmap(width, radius * 2);
5929 pixmap.fill(Qt::transparent);
5930 {
5931 QPen wavePen = pen;
5932 wavePen.setCapStyle(Qt::SquareCap);
5933
5934 // This is to protect against making the line too fat, as happens on OS X
5935 // due to it having a rather thick width for the regular underline.
5936 const qreal maxPenWidth = .8 * radius;
5937 if (wavePen.widthF() > maxPenWidth)
5938 wavePen.setWidthF(maxPenWidth);
5939
5940 QPainter imgPainter(&pixmap);
5941 imgPainter.setPen(wavePen);
5943 imgPainter.translate(0, radius);
5944 imgPainter.drawPath(path);
5945 }
5946
5948
5949 return pixmap;
5950}
5951
5952static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine,
5953 QTextCharFormat::UnderlineStyle underlineStyle,
5954 QTextItem::RenderFlags flags, qreal width,
5955 const QTextCharFormat &charFormat)
5956{
5957 if (underlineStyle == QTextCharFormat::NoUnderline
5959 return;
5960
5961 const QPen oldPen = painter->pen();
5962 const QBrush oldBrush = painter->brush();
5964 QPen pen = oldPen;
5966 pen.setWidthF(fe->lineThickness().toReal());
5968
5969 QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
5970
5971 const qreal underlineOffset = fe->underlinePosition().toReal();
5972
5973 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
5975 if (theme)
5977 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved
5978 underlineStyle = QTextCharFormat::WaveUnderline;
5979 }
5980
5981 if (underlineStyle == QTextCharFormat::WaveUnderline) {
5982 painter->save();
5983 painter->translate(0, pos.y() + 1);
5984 qreal maxHeight = fe->descent().toReal() - qreal(1);
5985
5986 QColor uc = charFormat.underlineColor();
5987 if (uc.isValid())
5988 pen.setColor(uc);
5989
5990 // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
5991 const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
5992 const int descent = qFloor(maxHeight);
5993
5995 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
5996 painter->restore();
5997 } else if (underlineStyle != QTextCharFormat::NoUnderline) {
5998 // Deliberately ceil the offset to avoid the underline coming too close to
5999 // the text above it, but limit it to stay within descent.
6000 qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + 0.5;
6001 if (underlineOffset <= fe->descent().toReal())
6002 adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - qreal(0.5));
6003 const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6004 QColor uc = charFormat.underlineColor();
6005 if (uc.isValid())
6006 pen.setColor(uc);
6007
6008 pen.setStyle((Qt::PenStyle)(underlineStyle));
6009 painter->setPen(pen);
6010 QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6011 if (textEngine)
6012 textEngine->addUnderline(painter, underline);
6013 else
6014 painter->drawLine(underline);
6015 }
6016
6018 pen.setColor(oldPen.color());
6019
6021 QLineF strikeOutLine = line;
6022 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6023 QColor uc = charFormat.underlineColor();
6024 if (uc.isValid())
6025 pen.setColor(uc);
6026 painter->setPen(pen);
6027 if (textEngine)
6028 textEngine->addStrikeOut(painter, strikeOutLine);
6029 else
6030 painter->drawLine(strikeOutLine);
6031 }
6032
6033 if (flags & QTextItem::Overline) {
6034 QLineF overline = line;
6035 overline.translate(0., - fe->ascent().toReal());
6036 QColor uc = charFormat.underlineColor();
6037 if (uc.isValid())
6038 pen.setColor(uc);
6039 painter->setPen(pen);
6040 if (textEngine)
6041 textEngine->addOverline(painter, overline);
6042 else
6043 painter->drawLine(overline);
6044 }
6045
6046 painter->setPen(oldPen);
6047 painter->setBrush(oldBrush);
6048}
6049
6051 const QPointF &decorationPosition,
6052 const glyph_t *glyphArray,
6053 const QFixedPoint *positions,
6054 int glyphCount,
6055 QFontEngine *fontEngine,
6056 bool underline,
6057 bool overline,
6058 bool strikeOut)
6059{
6060 if (!underline && !overline && !strikeOut)
6061 return;
6062
6063 QTextItem::RenderFlags flags;
6064 if (underline)
6066 if (overline)
6068 if (strikeOut)
6070
6071 bool rtl = positions[glyphCount - 1].x < positions[0].x;
6072 QFixed baseline = positions[0].y;
6073 glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[rtl ? 0 : glyphCount - 1]);
6074
6075 qreal width = rtl
6076 ? (positions[0].x + gm.xoff - positions[glyphCount - 1].x).toReal()
6077 : (positions[glyphCount - 1].x + gm.xoff - positions[0].x).toReal();
6078
6080 QPointF(decorationPosition.x(), baseline.toReal()),
6081 fontEngine,
6082 nullptr, // textEngine
6085 flags,
6086 width,
6087 QTextCharFormat());
6088}
6089
6091{
6092 Q_D(QPainter);
6093
6094 d->drawTextItem(p, ti, static_cast<QTextEngine *>(nullptr));
6095}
6096
6097void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine)
6098{
6099#ifdef QT_DEBUG_DRAW
6100 if (qt_show_painter_debug_output)
6101 printf("QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6102 p.x(), p.y(), qPrintable(_ti.text()));
6103#endif
6104
6105 Q_Q(QPainter);
6106
6107 if (!engine)
6108 return;
6109
6110 QTextItemInt &ti = const_cast<QTextItemInt &>(static_cast<const QTextItemInt &>(_ti));
6111
6112 if (!extended && state->bgMode == Qt::OpaqueMode) {
6113 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6114 q->fillRect(rect, state->bgBrush);
6115 }
6116
6117 if (q->pen().style() == Qt::NoPen)
6118 return;
6119
6120 const QPainter::RenderHints oldRenderHints = state->renderHints;
6121 if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6122 // draw antialias decoration (underline/overline/strikeout) with
6123 // transformed text
6124
6125 bool aa = true;
6126 const QTransform &m = state->matrix;
6127 if (state->matrix.type() < QTransform::TxShear) {
6128 bool isPlain90DegreeRotation =
6129 (qFuzzyIsNull(m.m11())
6130 && qFuzzyIsNull(m.m12() - qreal(1))
6131 && qFuzzyIsNull(m.m21() + qreal(1))
6132 && qFuzzyIsNull(m.m22())
6133 )
6134 ||
6135 (qFuzzyIsNull(m.m11() + qreal(1))
6136 && qFuzzyIsNull(m.m12())
6137 && qFuzzyIsNull(m.m21())
6138 && qFuzzyIsNull(m.m22() + qreal(1))
6139 )
6140 ||
6141 (qFuzzyIsNull(m.m11())
6142 && qFuzzyIsNull(m.m12() + qreal(1))
6143 && qFuzzyIsNull(m.m21() - qreal(1))
6144 && qFuzzyIsNull(m.m22())
6145 )
6146 ;
6147 aa = !isPlain90DegreeRotation;
6148 }
6149 if (aa)
6150 q->setRenderHint(QPainter::Antialiasing, true);
6151 }
6152
6153 if (!extended)
6155
6156 if (!ti.glyphs.numGlyphs) {
6157 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6158 ti.flags, ti.width.toReal(), ti.charFormat);
6159 } else if (ti.fontEngine->type() == QFontEngine::Multi) {
6160 QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
6161
6162 const QGlyphLayout &glyphs = ti.glyphs;
6163 int which = glyphs.glyphs[0] >> 24;
6164
6165 qreal x = p.x();
6166 qreal y = p.y();
6167
6168 bool rtl = ti.flags & QTextItem::RightToLeft;
6169 if (rtl)
6170 x += ti.width.toReal();
6171
6172 int start = 0;
6173 int end, i;
6174 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6175 const int e = glyphs.glyphs[end] >> 24;
6176 if (e == which)
6177 continue;
6178
6179
6180 multi->ensureEngineAt(which);
6181 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6182 ti2.width = 0;
6183 // set the high byte to zero and calc the width
6184 for (i = start; i < end; ++i) {
6185 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6186 ti2.width += ti.glyphs.effectiveAdvance(i);
6187 }
6188
6189 if (rtl)
6190 x -= ti2.width.toReal();
6191
6192 if (extended)
6193 extended->drawTextItem(QPointF(x, y), ti2);
6194 else
6195 engine->drawTextItem(QPointF(x, y), ti2);
6196 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6197 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6198
6199 if (!rtl)
6200 x += ti2.width.toReal();
6201
6202 // reset the high byte for all glyphs and advance to the next sub-string
6203 const int hi = which << 24;
6204 for (i = start; i < end; ++i) {
6205 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6206 }
6207
6208 // change engine
6209 start = end;
6210 which = e;
6211 }
6212
6213 multi->ensureEngineAt(which);
6214 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6215 ti2.width = 0;
6216 // set the high byte to zero and calc the width
6217 for (i = start; i < end; ++i) {
6218 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6219 ti2.width += ti.glyphs.effectiveAdvance(i);
6220 }
6221
6222 if (rtl)
6223 x -= ti2.width.toReal();
6224
6225 if (extended)
6226 extended->drawTextItem(QPointF(x, y), ti2);
6227 else
6228 engine->drawTextItem(QPointF(x,y), ti2);
6229 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6230 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6231
6232 // reset the high byte for all glyphs
6233 const int hi = which << 24;
6234 for (i = start; i < end; ++i)
6235 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6236
6237 } else {
6238 if (extended)
6239 extended->drawTextItem(p, ti);
6240 else
6241 engine->drawTextItem(p, ti);
6242 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6243 ti.flags, ti.width.toReal(), ti.charFormat);
6244 }
6245
6246 if (state->renderHints != oldRenderHints) {
6247 state->renderHints = oldRenderHints;
6248 if (extended)
6250 else
6251 state->dirtyFlags |= QPaintEngine::DirtyHints;
6252 }
6253}
6254
6311{
6312 if (str.isEmpty())
6313 return QRect(rect.x(),rect.y(), 0,0);
6314 QRect brect;
6316 return brect;
6317}
6318
6319
6320
6322{
6323 if (str.isEmpty())
6324 return QRectF(rect.x(),rect.y(), 0,0);
6325 QRectF brect;
6327 return brect;
6328}
6329
6344{
6345 Q_D(QPainter);
6346
6347 if (!d->engine || text.size() == 0)
6348 return QRectF(r.x(),r.y(), 0,0);
6349
6350 QRectF br;
6351 qt_format_text(d->state->font, r, Qt::TextDontPrint, &o, text, &br, 0, nullptr, 0, this);
6352 return br;
6353}
6354
6379{
6380#ifdef QT_DEBUG_DRAW
6381 if (qt_show_painter_debug_output)
6382 printf("QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6383 r.x(), r.y(), r.width(), r.height(),
6384 pixmap.width(), pixmap.height(),
6385 sp.x(), sp.y());
6386#endif
6387
6388 Q_D(QPainter);
6389 if (!d->engine || pixmap.isNull() || r.isEmpty())
6390 return;
6391
6392#ifndef QT_NO_DEBUG
6393 qt_painter_thread_test(d->device->devType(), d->engine->type(), "drawTiledPixmap()");
6394#endif
6395
6396 qreal sw = pixmap.width();
6397 qreal sh = pixmap.height();
6398 qreal sx = sp.x();
6399 qreal sy = sp.y();
6400 if (sx < 0)
6401 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6402 else
6403 sx = qRound(sx) % qRound(sw);
6404 if (sy < 0)
6405 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6406 else
6407 sy = qRound(sy) % qRound(sh);
6408
6409
6410 if (d->extended) {
6411 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6412 return;
6413 }
6414
6415 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6416 fillRect(r, d->state->bgBrush);
6417
6418 d->updateState(d->state);
6419 if ((d->state->matrix.type() > QTransform::TxTranslate
6420 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6421 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6422 {
6423 save();
6426 setBrush(QBrush(d->state->pen.color(), pixmap));
6428
6429 // If there is no rotation involved we have to make sure we use the
6430 // antialiased and not the aliased coordinate system by rounding the coordinates.
6431 if (d->state->matrix.type() <= QTransform::TxScale) {
6432 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6433
6434 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6435 sx = qRound(sx);
6436 sy = qRound(sy);
6437 }
6438
6439 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6440 drawRect(QRectF(p, r.size()));
6441 } else {
6442 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6443 drawRect(r);
6444 }
6445 restore();
6446 return;
6447 }
6448
6449 qreal x = r.x();
6450 qreal y = r.y();
6451 if (d->state->matrix.type() == QTransform::TxTranslate
6452 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6453 x += d->state->matrix.dx();
6454 y += d->state->matrix.dy();
6455 }
6456
6457 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
6458}
6459
6482#ifndef QT_NO_PICTURE
6483
6509{
6510 Q_D(QPainter);
6511
6512 if (!d->engine)
6513 return;
6514
6515 if (!d->extended)
6516 d->updateState(d->state);
6517
6518 save();
6519 translate(p);
6520 const_cast<QPicture *>(&picture)->play(this);
6521 restore();
6522}
6523
6538#endif // QT_NO_PICTURE
6539
6550{
6551 Q_D(QPainter);
6552
6553 fillRect(r, d->state->bgBrush);
6554}
6555
6556static inline bool needsResolving(const QBrush &brush)
6557{
6558 Qt::BrushStyle s = brush.style();
6561 (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ||
6562 brush.gradient()->coordinateMode() == QGradient::ObjectMode));
6563}
6564
6621{
6622 Q_D(QPainter);
6623
6624 if (!d->engine)
6625 return;
6626
6627 if (d->extended && !needsEmulation(brush)) {
6628 d->extended->fillRect(r, brush);
6629 return;
6630 }
6631
6632 QPen oldPen = pen();
6633 QBrush oldBrush = this->brush();
6635 if (brush.style() == Qt::SolidPattern) {
6636 d->colorBrush.setStyle(Qt::SolidPattern);
6637 d->colorBrush.setColor(brush.color());
6638 setBrush(d->colorBrush);
6639 } else {
6640 setBrush(brush);
6641 }
6642
6643 drawRect(r);
6644 setBrush(oldBrush);
6645 setPen(oldPen);
6646}
6647
6656{
6657 Q_D(QPainter);
6658
6659 if (!d->engine)
6660 return;
6661
6662 if (d->extended && !needsEmulation(brush)) {
6663 d->extended->fillRect(r, brush);
6664 return;
6665 }
6666
6667 QPen oldPen = pen();
6668 QBrush oldBrush = this->brush();
6670 if (brush.style() == Qt::SolidPattern) {
6671 d->colorBrush.setStyle(Qt::SolidPattern);
6672 d->colorBrush.setColor(brush.color());
6673 setBrush(d->colorBrush);
6674 } else {
6675 setBrush(brush);
6676 }
6677
6678 drawRect(r);
6679 setBrush(oldBrush);
6680 setPen(oldPen);
6681}
6682
6683
6684
6694{
6695 Q_D(QPainter);
6696
6697 if (!d->engine)
6698 return;
6699
6700 if (d->extended) {
6701 d->extended->fillRect(r, color);
6702 return;
6703 }
6704
6706}
6707
6708
6718{
6719 Q_D(QPainter);
6720
6721 if (!d->engine)
6722 return;
6723
6724 if (d->extended) {
6725 d->extended->fillRect(r, color);
6726 return;
6727 }
6728
6730}
6731
6822{
6823#ifdef QT_DEBUG_DRAW
6824 if (qt_show_painter_debug_output)
6825 printf("QPainter::setRenderHint: hint=%x, %s\n", hint, on ? "on" : "off");
6826#endif
6827
6828#ifndef QT_NO_DEBUG
6829 static const bool antialiasingDisabled = qEnvironmentVariableIntValue("QT_NO_ANTIALIASING");
6830 if (hint == QPainter::Antialiasing && antialiasingDisabled)
6831 return;
6832#endif
6833
6834 setRenderHints(hint, on);
6835}
6836
6847void QPainter::setRenderHints(RenderHints hints, bool on)
6848{
6849 Q_D(QPainter);
6850
6851 if (!d->engine) {
6852 qWarning("QPainter::setRenderHint: Painter must be active to set rendering hints");
6853 return;
6854 }
6855
6856 if (on)
6857 d->state->renderHints |= hints;
6858 else
6859 d->state->renderHints &= ~hints;
6860
6861 if (d->extended)
6862 d->extended->renderHintsChanged();
6863 else
6864 d->state->dirtyFlags |= QPaintEngine::DirtyHints;
6865}
6866
6873QPainter::RenderHints QPainter::renderHints() const
6874{
6875 Q_D(const QPainter);
6876
6877 if (!d->engine)
6878 return { };
6879
6880 return d->state->renderHints;
6881}
6882
6900{
6901 Q_D(const QPainter);
6902 if (!d->engine) {
6903 qWarning("QPainter::viewTransformEnabled: Painter not active");
6904 return false;
6905 }
6906 return d->state->VxF;
6907}
6908
6935{
6936#ifdef QT_DEBUG_DRAW
6937 if (qt_show_painter_debug_output)
6938 printf("QPainter::setWindow(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
6939#endif
6940
6941 Q_D(QPainter);
6942
6943 if (!d->engine) {
6944 qWarning("QPainter::setWindow: Painter not active");
6945 return;
6946 }
6947
6948 d->state->wx = r.x();
6949 d->state->wy = r.y();
6950 d->state->ww = r.width();
6951 d->state->wh = r.height();
6952
6953 d->state->VxF = true;
6954 d->updateMatrix();
6955}
6956
6964{
6965 Q_D(const QPainter);
6966 if (!d->engine) {
6967 qWarning("QPainter::window: Painter not active");
6968 return QRect();
6969 }
6970 return QRect(d->state->wx, d->state->wy, d->state->ww, d->state->wh);
6971}
6972
6999{
7000#ifdef QT_DEBUG_DRAW
7001 if (qt_show_painter_debug_output)
7002 printf("QPainter::setViewport(), [%d,%d,%d,%d]\n", r.x(), r.y(), r.width(), r.height());
7003#endif
7004
7005 Q_D(QPainter);
7006
7007 if (!d->engine) {
7008 qWarning("QPainter::setViewport: Painter not active");
7009 return;
7010 }
7011
7012 d->state->vx = r.x();
7013 d->state->vy = r.y();
7014 d->state->vw = r.width();
7015 d->state->vh = r.height();
7016
7017 d->state->VxF = true;
7018 d->updateMatrix();
7019}
7020
7028{
7029 Q_D(const QPainter);
7030 if (!d->engine) {
7031 qWarning("QPainter::viewport: Painter not active");
7032 return QRect();
7033 }
7034 return QRect(d->state->vx, d->state->vy, d->state->vw, d->state->vh);
7035}
7036
7046{
7047#ifdef QT_DEBUG_DRAW
7048 if (qt_show_painter_debug_output)
7049 printf("QPainter::setViewTransformEnabled(), enable=%d\n", enable);
7050#endif
7051
7052 Q_D(QPainter);
7053
7054 if (!d->engine) {
7055 qWarning("QPainter::setViewTransformEnabled: Painter not active");
7056 return;
7057 }
7058
7059 if (enable == d->state->VxF)
7060 return;
7061
7062 d->state->VxF = enable;
7063 d->updateMatrix();
7064}
7065
7066void qt_format_text(const QFont &fnt, const QRectF &_r,
7067 int tf, const QString& str, QRectF *brect,
7068 int tabstops, int *ta, int tabarraylen,
7070{
7071 qt_format_text(fnt, _r,
7072 tf, nullptr, str, brect,
7073 tabstops, ta, tabarraylen,
7074 painter);
7075}
7076void qt_format_text(const QFont &fnt, const QRectF &_r,
7077 int tf, const QTextOption *option, const QString& str, QRectF *brect,
7078 int tabstops, int *ta, int tabarraylen,
7080{
7081
7082 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=nullptr) ); // we either have an option or flags
7083
7084 if (option) {
7085 tf |= option->alignment();
7086 if (option->wrapMode() != QTextOption::NoWrap)
7087 tf |= Qt::TextWordWrap;
7088
7091
7092 if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7093 tf |= Qt::TextExpandTabs;
7094 }
7095
7096 // we need to copy r here to protect against the case (&r == brect).
7097 QRectF r(_r);
7098
7099 bool dontclip = (tf & Qt::TextDontClip);
7100 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7101 bool singleline = (tf & Qt::TextSingleLine);
7102 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7103 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7104
7106 if (tf & Qt::TextForceLeftToRight)
7108 else if (tf & Qt::TextForceRightToLeft)
7110 else if (option)
7111 layout_direction = option->textDirection();
7112 else if (painter)
7114 else
7116
7118
7119 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7120 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7121 (((tf & Qt::AlignLeft) && !isRightToLeft) ||
7122 ((tf & Qt::AlignRight) && isRightToLeft)));
7123
7124 if (!painter)
7125 tf |= Qt::TextDontPrint;
7126
7127 uint maxUnderlines = 0;
7128
7129 QFontMetricsF fm(fnt);
7130 QString text = str;
7131 int offset = 0;
7132start_lengthVariant:
7133 bool hasMoreLengthVariants = false;
7134 // compatible behaviour to the old implementation. Replace
7135 // tabs by spaces
7136 int old_offset = offset;
7137 for (; offset < text.size(); offset++) {
7138 QChar chr = text.at(offset);
7139 if (chr == u'\r' || (singleline && chr == u'\n')) {
7140 text[offset] = u' ';
7141 } else if (chr == u'\n') {
7143 } else if (chr == u'&') {
7144 ++maxUnderlines;
7145 } else if (chr == u'\t') {
7146 if (!expandtabs) {
7147 text[offset] = u' ';
7148 } else if (!tabarraylen && !tabstops) {
7149 tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7150 }
7151 } else if (chr == u'\x9c') {
7152 // string with multiple length variants
7153 hasMoreLengthVariants = true;
7154 break;
7155 }
7156 }
7157
7158 QList<QTextLayout::FormatRange> underlineFormats;
7159 int length = offset - old_offset;
7160 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7161 QChar *cout = text.data() + old_offset;
7162 QChar *cout0 = cout;
7163 QChar *cin = cout;
7164 int l = length;
7165 while (l) {
7166 if (*cin == u'&') {
7167 ++cin;
7168 --length;
7169 --l;
7170 if (!l)
7171 break;
7172 if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7174 range.start = cout - cout0;
7175 range.length = 1;
7176 range.format.setFontUnderline(true);
7177 underlineFormats.append(range);
7178 }
7179#ifdef Q_OS_MAC
7180 } else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7181 cin[1] == u'&' && cin[2] != u'&' &&
7182 cin[3] == u')') {
7183 int n = 0;
7184 while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7185 ++n;
7186 cout -= n;
7187 cin += 4;
7188 length -= n + 4;
7189 l -= 4;
7190 continue;
7191#endif //Q_OS_MAC
7192 }
7193 *cout = *cin;
7194 ++cout;
7195 ++cin;
7196 --l;
7197 }
7198 }
7199
7200 qreal height = 0;
7201 qreal width = 0;
7202
7203 QString finalText = text.mid(old_offset, length);
7204 QStackTextEngine engine(finalText, fnt);
7205 if (option) {
7206 engine.option = *option;
7207 }
7208
7209 if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7210 engine.option.setTabStopDistance(tabstops);
7211
7212 if (engine.option.tabs().isEmpty() && ta) {
7213 QList<qreal> tabs;
7214 tabs.reserve(tabarraylen);
7215 for (int i = 0; i < tabarraylen; i++)
7216 tabs.append(qreal(ta[i]));
7217 engine.option.setTabArray(tabs);
7218 }
7219
7220 engine.option.setTextDirection(layout_direction);
7221 if (tf & Qt::AlignJustify)
7222 engine.option.setAlignment(Qt::AlignJustify);
7223 else
7224 engine.option.setAlignment(Qt::AlignLeft); // do not do alignment twice
7225
7226 if (!option && (tf & Qt::TextWrapAnywhere))
7227 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7228
7230 engine.forceJustification = true;
7231 QTextLayout textLayout(&engine);
7232 textLayout.setCacheEnabled(true);
7233 textLayout.setFormats(underlineFormats);
7234
7235 if (finalText.isEmpty()) {
7236 height = fm.height();
7237 width = 0;
7238 tf |= Qt::TextDontPrint;
7239 } else {
7240 qreal lineWidth = 0x01000000;
7241 if (wordwrap || (tf & Qt::TextJustificationForced))
7242 lineWidth = qMax<qreal>(0, r.width());
7243 if (!wordwrap)
7245 textLayout.beginLayout();
7246
7247 qreal leading = fm.leading();
7248 height = -leading;
7249
7250 while (1) {
7251 QTextLine l = textLayout.createLine();
7252 if (!l.isValid())
7253 break;
7254
7255 l.setLineWidth(lineWidth);
7256 height += leading;
7257
7258 // Make sure lines are positioned on whole pixels
7259 height = qCeil(height);
7260 l.setPosition(QPointF(0., height));
7261 height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7263 if (!dontclip && !brect && height >= r.height())
7264 break;
7265 }
7266 textLayout.endLayout();
7267 }
7268
7269 qreal yoff = 0;
7270 qreal xoff = 0;
7271 if (tf & Qt::AlignBottom)
7272 yoff = r.height() - height;
7273 else if (tf & Qt::AlignVCenter)
7274 yoff = (r.height() - height)/2;
7275
7276 if (tf & Qt::AlignRight)
7277 xoff = r.width() - width;
7278 else if (tf & Qt::AlignHCenter)
7279 xoff = (r.width() - width)/2;
7280
7281 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7282
7283 if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7284 offset++;
7285 goto start_lengthVariant;
7286 }
7287 if (brect)
7288 *brect = bounds;
7289
7290 if (!(tf & Qt::TextDontPrint)) {
7291 bool restore = false;
7292 if (!dontclip && !r.contains(bounds)) {
7293 restore = true;
7294 painter->save();
7296 }
7297
7298 for (int i = 0; i < textLayout.lineCount(); i++) {
7299 QTextLine line = textLayout.lineAt(i);
7300 QTextEngine *eng = textLayout.engine();
7302
7303 qreal advance = line.horizontalAdvance();
7304 xoff = 0;
7305 if (tf & Qt::AlignRight) {
7306 xoff = r.width() - advance -
7307 eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7308 }
7309 else if (tf & Qt::AlignHCenter)
7310 xoff = (r.width() - advance) / 2;
7311
7312 line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff));
7314 }
7315
7316 if (restore) {
7317 painter->restore();
7318 }
7319 }
7320}
7321
7332{
7333 Q_D(QPainter);
7334 if (d->state)
7335 d->state->layoutDirection = direction;
7336}
7337
7344{
7345 Q_D(const QPainter);
7346 return d->state ? d->state->layoutDirection : Qt::LayoutDirectionAuto;
7347}
7348
7350 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7351 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7352 clipRegion(s->clipRegion), clipPath(s->clipPath),
7353 clipOperation(s->clipOperation),
7354 renderHints(s->renderHints), clipInfo(s->clipInfo),
7355 worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7356 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7357 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7358 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7359 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7360 layoutDirection(s->layoutDirection),
7361 composition_mode(s->composition_mode),
7362 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7363{
7364 dirtyFlags = s->dirtyFlags;
7365}
7366
7368 : brushOrigin(0, 0), WxF(false), VxF(false), clipEnabled(true),
7369 layoutDirection(QGuiApplication::layoutDirection())
7370{
7371}
7372
7374{
7375}
7376
7380 WxF = false;
7381 VxF = false;
7382 clipEnabled = true;
7383 wx = wy = ww = wh = 0;
7384 vx = vy = vw = vh = 0;
7385 painter = p;
7386 pen = QPen();
7387 brushOrigin = QPointF(0, 0);
7388 brush = QBrush();
7389 font = deviceFont = QFont();
7390 clipRegion = QRegion();
7393 clipInfo.clear();
7395 matrix.reset();
7399 dirtyFlags = { };
7400 changeFlags = 0;
7401 renderHints = { };
7402 opacity = 1;
7403}
7404
7591{
7592 return static_cast<const QPainterState *>(this)->pen;
7593}
7594
7605{
7606 return static_cast<const QPainterState *>(this)->brush;
7607}
7608
7619{
7620 return static_cast<const QPainterState *>(this)->brushOrigin;
7621}
7622
7633{
7634 return static_cast<const QPainterState *>(this)->bgBrush;
7635}
7636
7648{
7649 return static_cast<const QPainterState *>(this)->bgMode;
7650}
7651
7663{
7664 return static_cast<const QPainterState *>(this)->font;
7665}
7666
7680{
7681 const QPainterState *st = static_cast<const QPainterState *>(this);
7682
7683 return st->matrix;
7684}
7685
7686
7699{
7700 return static_cast<const QPainterState *>(this)->clipOperation;
7701}
7702
7711{
7712 const QBrush &brush = static_cast<const QPainterState *>(this)->brush;
7713 return needsResolving(brush);
7714}
7715
7716
7725{
7726 const QPen &pen = static_cast<const QPainterState *>(this)->pen;
7727 return needsResolving(pen.brush());
7728}
7729
7740{
7741 return static_cast<const QPainterState *>(this)->clipRegion;
7742}
7743
7754{
7755 return static_cast<const QPainterState *>(this)->clipPath;
7756}
7757
7770{
7771 return static_cast<const QPainterState *>(this)->clipEnabled;
7772}
7773
7784QPainter::RenderHints QPaintEngineState::renderHints() const
7785{
7786 return static_cast<const QPainterState *>(this)->renderHints;
7787}
7788
7800{
7801 return static_cast<const QPainterState *>(this)->composition_mode;
7802}
7803
7804
7811{
7812 return static_cast<const QPainterState *>(this)->painter;
7813}
7814
7815
7823{
7824 return static_cast<const QPainterState *>(this)->opacity;
7825}
7826
7838{
7839 setWorldTransform(transform, combine);
7840}
7841
7850{
7851 return worldTransform();
7852}
7853
7854
7871{
7872 Q_D(const QPainter);
7873 if (!d->engine) {
7874 qWarning("QPainter::deviceTransform: Painter not active");
7875 return d->fakeState()->transform;
7876 }
7877 return d->state->matrix;
7878}
7879
7880
7890{
7891 Q_D(QPainter);
7892#ifdef QT_DEBUG_DRAW
7893 if (qt_show_painter_debug_output)
7894 printf("QPainter::resetMatrix()\n");
7895#endif
7896 if (!d->engine) {
7897 qWarning("QPainter::resetMatrix: Painter not active");
7898 return;
7899 }
7900
7901 d->state->wx = d->state->wy = d->state->vx = d->state->vy = 0; // default view origins
7902 d->state->ww = d->state->vw = d->device->metric(QPaintDevice::PdmWidth);
7903 d->state->wh = d->state->vh = d->device->metric(QPaintDevice::PdmHeight);
7904 d->state->worldMatrix = QTransform();
7905 setWorldMatrixEnabled(false);
7907 if (d->extended)
7908 d->extended->transformChanged();
7909 else
7910 d->state->dirtyFlags |= QPaintEngine::DirtyTransform;
7911}
7912
7922{
7923 Q_D(QPainter);
7924
7925 if (!d->engine) {
7926 qWarning("QPainter::setWorldTransform: Painter not active");
7927 return;
7928 }
7929
7930 if (combine)
7931 d->state->worldMatrix = matrix * d->state->worldMatrix; // combines
7932 else
7933 d->state->worldMatrix = matrix; // set new matrix
7934
7935 d->state->WxF = true;
7936 d->updateMatrix();
7937}
7938
7944{
7945 Q_D(const QPainter);
7946 if (!d->engine) {
7947 qWarning("QPainter::worldTransform: Painter not active");
7948 return d->fakeState()->transform;
7949 }
7950 return d->state->worldMatrix;
7951}
7952
7961{
7962 Q_D(const QPainter);
7963 if (!d->engine) {
7964 qWarning("QPainter::combinedTransform: Painter not active");
7965 return QTransform();
7966 }
7967 return d->state->worldMatrix * d->viewTransform() * d->hidpiScaleTransform();
7968}
7969
7985void QPainter::drawPixmapFragments(const PixmapFragment *fragments, int fragmentCount,
7986 const QPixmap &pixmap, PixmapFragmentHints hints)
7987{
7988 Q_D(QPainter);
7989
7990 if (!d->engine || pixmap.isNull())
7991 return;
7992
7993#ifndef QT_NO_DEBUG
7994 for (int i = 0; i < fragmentCount; ++i) {
7995 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
7996 fragments[i].width, fragments[i].height);
7997 if (!(QRectF(pixmap.rect()).contains(sourceRect)))
7998 qWarning("QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
7999 }
8000#endif
8001
8002 if (d->engine->isExtended()) {
8003 d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8004 } else {
8005 qreal oldOpacity = opacity();
8006 QTransform oldTransform = transform();
8007
8008 for (int i = 0; i < fragmentCount; ++i) {
8009 QTransform transform = oldTransform;
8010 qreal xOffset = 0;
8011 qreal yOffset = 0;
8012 if (fragments[i].rotation == 0) {
8013 xOffset = fragments[i].x;
8014 yOffset = fragments[i].y;
8015 } else {
8016 transform.translate(fragments[i].x, fragments[i].y);
8017 transform.rotate(fragments[i].rotation);
8018 }
8019 setOpacity(oldOpacity * fragments[i].opacity);
8021
8022 qreal w = fragments[i].scaleX * fragments[i].width;
8023 qreal h = fragments[i].scaleY * fragments[i].height;
8024 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8025 fragments[i].width, fragments[i].height);
8026 drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8027 }
8028
8029 setOpacity(oldOpacity);
8030 setTransform(oldTransform);
8031 }
8032}
8033
8064 qreal scaleX, qreal scaleY, qreal rotation,
8065 qreal opacity)
8066{
8067 PixmapFragment fragment = {pos.x(), pos.y(), sourceRect.x(), sourceRect.y(), sourceRect.width(),
8068 sourceRect.height(), scaleX, scaleY, rotation, opacity};
8069 return fragment;
8070}
8071
8142{
8143 p->draw_helper(path, operation);
8144}
8145
8147
8148#include "moc_qpainter.cpp"
IOBluetoothDevice * device
\inmodule QtGui
Definition qbrush.h:30
bool isOpaque() const
Returns true if the brush is fully opaque otherwise false.
Definition qbrush.cpp:830
QImage textureImage() const
Definition qbrush.cpp:752
QPixmap texture() const
Returns the custom brush pattern, or a null pixmap if no custom brush pattern has been set.
Definition qbrush.cpp:711
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:122
\inmodule QtCore
Definition qchar.h:48
@ LineSeparator
Definition qchar.h:64
@ Script_Common
Definition qchar.h:147
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
int alpha() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1466
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
QString path() const
Returns the file's path.
Definition qflags.h:17
static QFontCache * instance()
Definition qfont.cpp:3052
int id() const
Definition qfont_p.h:200
const int fontCacheId
Definition qfont_p.h:133
void ensureEngineAt(int at)
QFontEngine * engine(int at) const
virtual QFixed descent() const
virtual QFixed ascent() const
Type type() const
virtual QFixed lineThickness() const
virtual QFixed underlinePosition() const
virtual bool supportsTransformation(const QTransform &transform) const
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)
\reentrant
Definition qfontinfo.h:14
\reentrant \inmodule QtGui
qreal height() const
Returns the height of the font.
qreal leading() const
Returns the leading of the font.
qreal horizontalAdvance(const QString &string, int length=-1) const
Returns the horizontal advance in pixels of the first length characters of text.
\reentrant \inmodule QtGui
static QFontPrivate * get(const QFont &font)
Definition qfont_p.h:173
QFontEngine * engineForScript(int script) const
Definition qfont.cpp:238
QFontEngineData * engineData
Definition qfont_p.h:155
\reentrant
Definition qfont.h:20
bool strikeOut() const
Returns true if strikeout has been set; otherwise returns false.
Definition qfont.cpp:1289
bool underline() const
Returns true if underline has been set; otherwise returns false.
Definition qfont.cpp:1236
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:1854
QStringList families() const
Definition qfont.cpp:2469
int pointSize() const
Returns the point size of the font.
Definition qfont.cpp:863
bool overline() const
Returns true if overline has been set; otherwise returns false.
Definition qfont.cpp:1263
static QGlyphRunPrivate * get(const QGlyphRun &glyphRun)
Definition qglyphrun_p.h:78
const quint32 * glyphIndexData
Definition qglyphrun_p.h:69
const QPointF * glyphPositionData
Definition qglyphrun_p.h:72
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
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
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false.
Definition qimage.cpp:4571
@ Format_Indexed8
Definition qimage.h:45
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
void detach()
Definition qimage.cpp:1104
\inmodule QtCore
Definition qline.h:182
void translate(const QPointF &p)
Translates this line by the given offset.
Definition qline.h:314
\inmodule QtCore
Definition qline.h:18
Definition qlist.h:74
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
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
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...
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
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 closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
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:25
void setCapStyle(Qt::PenCapStyle pcs)
Sets the pen's cap style to the given style.
Definition qpen.cpp:676
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:598
void setStyle(Qt::PenStyle)
[0]
QColor color() const
Returns the color of this pen's brush.
Definition qpen.cpp:718
void setWidthF(qreal width)
Sets the pen width to the given width in pixels with floating point precision.
Definition qpen.cpp:644
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:662
void setColor(const QColor &color)
Sets the color of this pen's brush to the given color.
Definition qpen.cpp:731
void setBrush(const QBrush &brush)
Sets the brush used to fill strokes generated with this pen to the given brush.
Definition qpen.cpp:752
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:689
qreal miterLimit() const
Returns the miter limit of the pen.
Definition qpen.cpp:548
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition qpen.cpp:741
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:385
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:484
int depth() const
Returns the depth of the pixmap.
Definition qpixmap.cpp:525
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:460
int width() const
Returns the width of the pixmap.
Definition qpixmap.cpp:472
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:509
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
Definition qpixmap.cpp:580
bool hasAlpha() const
bool isQBitmap() const
Returns true if this is a QBitmap; otherwise returns false.
Definition qpixmap.cpp:447
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:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
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:394
\inmodule QtCore\reentrant
Definition qpoint.h:23
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:127
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:132
static QRawFontPrivate * get(const QRawFont &font)
Definition qrawfont_p.h:104
QFontEngine * fontEngine
Definition qrawfont_p.h:106
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:647
QRect toAlignedRect() const noexcept
Definition qrect.cpp:2330
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:658
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:655
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:1985
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:799
QRectF intersected(const QRectF &other) const noexcept
Definition qrect.h:833
\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:166
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:184
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
\inmodule QtCore
QFixedPoint * glyphPositions
void setFontEngine(QFontEngine *fe)
void paintText(const QPointF &pos, QPainter *p, const QColor &pen)
static QStaticTextPrivate * get(const QStaticText *q)
unsigned char needsRelayout
QStaticTextItem * items
unsigned char untransformedCoordinates
The QStaticText class enables optimized drawing of text when the text and its layout is updated rarel...
Definition qstatictext.h:21
QString text() const
Returns the text of the QStaticText.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QByteArray toLatin1() const &
Definition qstring.h:559
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
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)
void addOverline(QPainter *painter, const QLineF &line)
QFixed leadingSpaceWidth(const QScriptLine &line)
void drawDecorations(QPainter *painter)
void addStrikeOut(QPainter *painter, const QLineF &line)
void addUnderline(QPainter *painter, const QLineF &line)
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
Internal QTextItem.
RenderFlags flags
const QTextCharFormat charFormat
QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const
const QChar * chars
QGlyphLayout glyphs
const unsigned short * logClusters
QTextCharFormat::UnderlineStyle underlineStyle
QFontEngine * fontEngine
\inmodule QtGui
QString text() const
Returns the text that should be drawn.
\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:966
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.
bool isTranslating() const
Returns true if the matrix represents a translating transformation, otherwise returns false.
Definition qtransform.h:188
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.
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
constexpr size_type size() const noexcept
T * data() noexcept
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
#define this
Definition dialogs.cpp:9
QString str
[2]
QPixmap p2
QPixmap p1
[0]
QString text
double e
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:477
@ OrderedDither
Definition qnamespace.h:490
@ OrderedAlphaDither
Definition qnamespace.h:484
@ AlignRight
Definition qnamespace.h:145
@ AlignJustify
Definition qnamespace.h:148
@ AlignBottom
Definition qnamespace.h:153
@ AlignVCenter
Definition qnamespace.h:154
@ AlignHCenter
Definition qnamespace.h:147
@ AlignLeft
Definition qnamespace.h:143
ClipOperation
@ ReplaceClip
@ IntersectClip
@ NoClip
LayoutDirection
@ LeftToRight
@ LayoutDirectionAuto
@ RightToLeft
@ TextJustificationForced
Definition qnamespace.h:178
@ TextLongestVariant
Definition qnamespace.h:183
@ TextIncludeTrailingSpaces
Definition qnamespace.h:176
@ TextWrapAnywhere
Definition qnamespace.h:174
@ TextSingleLine
Definition qnamespace.h:169
@ TextWordWrap
Definition qnamespace.h:173
@ TextDontPrint
Definition qnamespace.h:175
@ TextDontClip
Definition qnamespace.h:170
@ TextHideMnemonic
Definition qnamespace.h:177
@ TextExpandTabs
Definition qnamespace.h:171
@ TextForceRightToLeft
Definition qnamespace.h:180
@ TextShowMnemonic
Definition qnamespace.h:172
@ TextForceLeftToRight
Definition qnamespace.h:179
@ OpaqueMode
Definition qnamespace.h:507
@ TransparentMode
Definition qnamespace.h:506
@ color1
Definition qnamespace.h:28
@ white
Definition qnamespace.h:30
@ transparent
Definition qnamespace.h:46
@ black
Definition qnamespace.h:29
@ color0
Definition qnamespace.h:27
@ 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:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
static Q_CONSTINIT Qt::LayoutDirection layout_direction
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
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
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
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
GLdouble s
[6]
Definition qopenglext.h:235
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:1391
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:45
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
QFileInfo info(fileName)
[8]
QObject::connect nullptr
QGraphicsItem * item
widget render & pixmap
QPainter painter(this)
[7]
QJSEngine engine
[0]
QFixed y
Definition qfixed_p.h:163
static constexpr QFixedPoint fromPointF(const QPointF &p)
Definition qfixed_p.h:167
QFixed x
Definition qfixed_p.h:162
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35
constexpr qreal toReal() const
Definition qfixed_p.h:42
QGlyphJustification * justifications
QFixed effectiveAdvance(int item) const
QGlyphAttributes * attributes
glyph_t * glyphs
QFixedPoint * offsets
QFixed * advances
unsigned short flags
QScriptAnalysis analysis