244 QPainter *sp = pdev->sharedPainter();
251 ++sp->d_ptr->refcount;
252 sp->d_ptr->d_ptrs.push_back(std::move(q->d_ptr));
253 q->d_ptr.reset(sp->d_ptr.get());
255 Q_ASSERT(q->d_ptr->state);
258 q->d_ptr->initFrom(pdev);
260 pdev->redirected(&offset);
261 offset += q->d_ptr->engine->coordinateOffset();
264 q->d_ptr->state->ww = q->d_ptr->state->vw = pdev->width();
265 q->d_ptr->state->wh = q->d_ptr->state->vh = pdev->height();
268 if (q->d_ptr->state->WxF) {
269 q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
270 q->d_ptr->state->redirectionMatrix *= q->d_ptr->hidpiScaleTransform().inverted();
271 q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
272 q->d_ptr->state->worldMatrix = QTransform();
273 q->d_ptr->state->WxF =
false;
275 q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
277 q->d_ptr->updateMatrix();
279 QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
280 if (enginePrivate->currentClipDevice == pdev) {
281 enginePrivate->systemStateChanged();
286 enginePrivate->currentClipDevice = pdev;
287 enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
321 if constexpr (qt_show_painter_debug_output) {
322 printf(
"QPainter::drawHelper\n");
326 if (originalPath.isEmpty())
329 QPaintEngine::PaintEngineFeatures gradientStretch =
331 | QPaintEngine::ObjectBoundingModeGradients);
333 const bool mustEmulateObjectBoundingModeGradients = extended
334 || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
335 && !engine->hasFeature(QPaintEngine::PatternTransform));
337 if (!(state->emulationSpecifier & ~gradientStretch)
338 && !mustEmulateObjectBoundingModeGradients) {
348 qreal strokeOffsetX = 0, strokeOffsetY = 0;
350 QPainterPath path = originalPath * state->matrix;
351 QRectF pathBounds = path.boundingRect();
353 bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
355 qreal penWidth = state->pen.widthF();
361 if (state->matrix.type() > QTransform::TxScale) {
363 stroker.setWidth(penWidth);
364 stroker.setJoinStyle(state->pen.joinStyle());
365 stroker.setCapStyle(state->pen.capStyle());
366 QPainterPath stroke = stroker.createStroke(originalPath);
367 strokeBounds = (stroke * state->matrix).boundingRect();
369 strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
370 strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
376 if (!strokeBounds.isEmpty()) {
377 absPathRect = strokeBounds.intersected(QRectF(0, 0,
device->width(),
device->height())).toAlignedRect();
379 absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
380 .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
383 if (q->hasClipping()) {
384 bool hasPerspectiveTransform =
false;
385 for (
const QPainterClipInfo &info : std::as_const(state->clipInfo)) {
386 if (info.matrix.type() == QTransform::TxProject) {
387 hasPerspectiveTransform =
true;
392 if (!hasPerspectiveTransform) {
399 bool old_txinv =
txinv;
400 QTransform old_invMatrix = invMatrix;
402 invMatrix = QTransform();
403 QPainterPath clipPath = q->clipPath();
404 QRectF r = clipPath.boundingRect().intersected(absPathRect);
405 absPathRect = r.toAlignedRect();
407 invMatrix = old_invMatrix;
417 if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
420 QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
427 p.setOpacity(state->opacity);
428 p.translate(-absPathRect.x(), -absPathRect.y());
429 p.setTransform(state->matrix,
true);
430 p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
431 p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
432 p.setBackground(state->bgBrush);
433 p.setBackgroundMode(state->bgMode);
434 p.setBrushOrigin(state->brushOrigin);
436 p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
437 p.setRenderHint(QPainter::SmoothPixmapTransform,
438 state->renderHints & QPainter::SmoothPixmapTransform);
440 p.drawPath(originalPath);
443 static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty(
"QT_PAINT_FALLBACK_OVERLAY");
444 if (do_fallback_overlay) {
445 QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
447 pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
448 pt.drawLine(0, 0, 8, 8);
451 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
453 p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
460 state->matrix = QTransform();
464 state->dirtyFlags |= QPaintEngine::DirtyTransform;
467 engine->drawImage(absPathRect,
469 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
470 Qt::OrderedDither | Qt::OrderedAlphaDither);
519 bool changedPen =
false;
520 bool changedBrush =
false;
521 bool needsFill =
false;
523 const QPen pen = state->pen;
524 const QBrush brush = state->brush;
526 const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
527 const QGradient::CoordinateMode brushMode = coordinateMode(brush);
532 if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
533 if (brushMode == QGradient::StretchToDeviceMode) {
534 q->setPen(Qt::NoPen);
535 changedPen = pen.style() != Qt::NoPen;
539 const qreal isw = 1.0 / sw;
540 const qreal ish = 1.0 / sh;
541 QTransform inv(isw, 0, 0, ish, 0, 0);
542 engine->drawPath(path * inv);
547 if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
548 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
549 boundingRect = path.boundingRect();
550 q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
556 if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
558 if (penMode == QGradient::StretchToDeviceMode) {
559 q->setPen(Qt::NoPen);
564 engine->drawPath(path);
568 q->setBrush(pen.brush());
573 stroker.setDashPattern(pen.style());
574 stroker.setWidth(pen.widthF());
575 stroker.setJoinStyle(pen.joinStyle());
576 stroker.setCapStyle(pen.capStyle());
577 stroker.setMiterLimit(pen.miterLimit());
578 QPainterPath stroke = stroker.createStroke(path);
580 const qreal isw = 1.0 / sw;
581 const qreal ish = 1.0 / sh;
582 QTransform inv(isw, 0, 0, ish, 0, 0);
583 engine->drawPath(stroke * inv);
586 if (!needsFill && brush.style() != Qt::NoBrush) {
587 q->setBrush(Qt::NoBrush);
591 if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
592 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
595 if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
596 boundingRect = path.boundingRect();
599 p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
602 }
else if (changedPen) {
608 engine->drawPath(path);
610 }
else if (needsFill) {
611 if (pen.style() != Qt::NoPen) {
612 q->setPen(Qt::NoPen);
617 engine->drawPath(path);
659 bool linearGradient =
false;
660 bool radialGradient =
false;
661 bool extendedRadialGradient =
false;
662 bool conicalGradient =
false;
663 bool patternBrush =
false;
665 bool complexXform =
false;
671 if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
673 if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
674 s->emulationSpecifier |= QPaintEngine::BrushStroke;
676 s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
680 QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
681 Qt::BrushStyle brushStyle = qbrush_style(s->brush);
682 Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
683 alpha = (penBrushStyle != Qt::NoBrush
684 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
685 && !penBrush.isOpaque())
686 || (brushStyle != Qt::NoBrush
687 && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
688 && !s->brush.isOpaque());
689 linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
690 (brushStyle == Qt::LinearGradientPattern));
691 radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
692 (brushStyle == Qt::RadialGradientPattern));
693 extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
694 conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
695 (brushStyle == Qt::ConicalGradientPattern));
696 patternBrush = (((penBrushStyle > Qt::SolidPattern
697 && penBrushStyle < Qt::LinearGradientPattern)
698 || penBrushStyle == Qt::TexturePattern) ||
699 ((brushStyle > Qt::SolidPattern
700 && brushStyle < Qt::LinearGradientPattern)
701 || brushStyle == Qt::TexturePattern));
703 bool penTextureAlpha =
false;
704 if (penBrush.style() == Qt::TexturePattern)
705 penTextureAlpha = qHasPixmapTexture(penBrush)
706 ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
707 : penBrush.textureImage().hasAlphaChannel();
708 bool brushTextureAlpha =
false;
709 if (s->brush.style() == Qt::TexturePattern) {
710 brushTextureAlpha = qHasPixmapTexture(s->brush)
711 ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
712 : s->brush.textureImage().hasAlphaChannel();
714 if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
715 || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
716 && !engine->hasFeature(QPaintEngine::MaskedBrush))
717 s->emulationSpecifier |= QPaintEngine::MaskedBrush;
719 s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
722 if (s->state() & (QPaintEngine::DirtyHints
723 | QPaintEngine::DirtyOpacity
724 | QPaintEngine::DirtyBackgroundMode)) {
732 qDebug(
"QPainterPrivate::updateEmulationSpecifier, state=%p\n"
734 " - linearGradient: %d\n"
735 " - radialGradient: %d\n"
736 " - conicalGradient: %d\n"
737 " - patternBrush: %d\n"
746 uint(s->renderHints),
751 if (s->state() & QPaintEngine::DirtyTransform) {
752 xform = !s->matrix.isIdentity();
753 complexXform = !s->matrix.isAffine();
754 }
else if (s->matrix.type() >= QTransform::TxTranslate) {
756 complexXform = !s->matrix.isAffine();
759 const bool brushXform = (s->brush.transform().type() != QTransform::TxNone);
760 const bool penXform = (s->pen.brush().transform().type() != QTransform::TxNone);
762 const bool patternXform = patternBrush && (xform || brushXform || penXform);
765 if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
766 s->emulationSpecifier |= QPaintEngine::AlphaBlend;
768 s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
771 if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
772 s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
774 s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
777 if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
778 s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
780 s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
783 if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
784 s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
786 s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
789 if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
790 s->emulationSpecifier |= QPaintEngine::PatternBrush;
792 s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
795 if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
796 s->emulationSpecifier |= QPaintEngine::PatternTransform;
798 s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
801 if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
802 s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
804 s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
807 if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
808 s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
810 s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
813 if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
814 s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
816 s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
818 bool gradientStretch =
false;
819 bool objectBoundingMode =
false;
820 if (linearGradient || conicalGradient || radialGradient) {
821 QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
822 QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
824 gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
825 gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
827 objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
828 objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
835 if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
836 s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
838 s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
841 if (s->bgMode == Qt::OpaqueMode &&
842 (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
853 if (state->composition_mode > QPainter::CompositionMode_Xor &&
854 !engine->hasFeature(QPaintEngine::BlendModes))
855 s->emulationSpecifier |= QPaintEngine::BlendModes;
857 s->emulationSpecifier &= ~QPaintEngine::BlendModes;
1582void QPainter::restore()
1585 if constexpr (qt_show_painter_debug_output)
1586 printf(
"QPainter::restore()\n");
1589 if (d->savedStates.empty()) {
1590 qWarning(
"QPainter::restore: Unbalanced save/restore");
1592 }
else if (!d->engine) {
1593 qWarning(
"QPainter::restore: Painter not active");
1597 const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
1598 d->savedStates.pop();
1602 d->checkEmulation();
1603 d->extended->setState(d->state.get());
1609 if (!d->state->clipInfo.isEmpty()
1610 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1612 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1613 tmp->clipOperation = Qt::NoClip;
1614 tmp->clipPath = QPainterPath();
1615 d->engine->updateState(*tmp);
1617 for (
const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
1618 tmp->matrix = info.matrix;
1619 tmp->clipOperation = info.operation;
1620 if (info.clipType == QPainterClipInfo::RectClip) {
1621 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1622 tmp->clipRegion = info.rect;
1623 }
else if (info.clipType == QPainterClipInfo::RegionClip) {
1624 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1625 tmp->clipRegion = info.region;
1627 tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
1628 tmp->clipPath = info.path;
1630 d->engine->updateState(*tmp);
1635 d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1636 tmp->changeFlags &= ~uint(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1637 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1640 d->updateState(d->state.get());
1679bool QPainter::begin(QPaintDevice *pd)
1683 if (pd->painters > 0) {
1684 qWarning(
"QPainter::begin: A paint device can only be painted by one painter at a time.");
1688 if (d_ptr->engine) {
1689 qWarning(
"QPainter::begin: Painter already active");
1693 if (QPainterPrivate::attachPainterPrivate(
this, pd))
1698 d->helper_device = pd;
1699 d->original_device = pd;
1701 QPoint redirectionOffset;
1702 QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1707 if constexpr (qt_show_painter_debug_output)
1708 printf(
"QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1711 if (pd->devType() == QInternal::Pixmap)
1712 static_cast<QPixmap *>(pd)->detach();
1713 else if (pd->devType() == QInternal::Image)
1714 static_cast<QImage *>(pd)->detach();
1716 d->engine.reset(pd->paintEngine());
1719 qWarning(
"QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1725 d->extended = d->engine->isExtended() ?
static_cast<QPaintEngineEx *>(d->engine.get()) :
nullptr;
1726 if (d->emulationEngine)
1727 d->emulationEngine->real_engine = d->extended;
1730 Q_ASSERT(!d->state);
1731 d->state.reset(d->extended ? d->extended->createState(
nullptr) :
new QPainterState);
1732 d->state->painter =
this;
1734 d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1735 d->state->brushOrigin = QPointF();
1739 d->extended->setState(d->state.get());
1741 d->engine->state = d->state.get();
1743 switch (pd->devType()) {
1744 case QInternal::Pixmap:
1746 QPixmap *pm =
static_cast<QPixmap *>(pd);
1749 qWarning(
"QPainter::begin: Cannot paint on a null pixmap");
1750 qt_cleanup_painter_state(d);
1754 if (pm->depth() == 1) {
1755 d->state->pen = QPen(Qt::color1);
1756 d->state->brush = QBrush(Qt::color0);
1760 case QInternal::Image:
1762 QImage *img =
static_cast<QImage *>(pd);
1764 if (img->isNull()) {
1765 qWarning(
"QPainter::begin: Cannot paint on a null image");
1766 qt_cleanup_painter_state(d);
1768 }
else if (img->format() == QImage::Format_Indexed8 ||
1769 img->format() == QImage::Format_CMYK8888) {
1771 qWarning() <<
"QPainter::begin: Cannot paint on an image with the"
1774 qt_cleanup_painter_state(d);
1777 if (img->depth() == 1) {
1778 d->state->pen = QPen(Qt::color1);
1779 d->state->brush = QBrush(Qt::color0);
1786 if (d->state->ww == 0)
1787 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1789 d->engine->setPaintDevice(pd);
1791 bool begun = d->engine->begin(pd);
1793 qWarning(
"QPainter::begin(): Returned false");
1794 if (d->engine->isActive()) {
1797 qt_cleanup_painter_state(d);
1801 d->engine->setActive(begun);
1806 if (d->original_device->devType() == QInternal::Widget) {
1807 d->initFrom(d->original_device);
1809 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1811 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1814 QRect systemRect = d->engine->systemRect();
1815 if (!systemRect.isEmpty()) {
1816 d->state->ww = d->state->vw = systemRect.width();
1817 d->state->wh = d->state->vh = systemRect.height();
1819 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1820 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1823 const QPoint coordinateOffset = d->engine->coordinateOffset();
1824 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1826 Q_ASSERT(d->engine->isActive());
1828 if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
1831 Q_ASSERT(d->engine->isActive());
1832 d->state->renderHints = QPainter::TextAntialiasing;
1833 ++d->device->painters;
1835 d->state->emulationSpecifier = 0;
2491QRegion QPainter::clipRegion()
const
2493 Q_D(
const QPainter);
2495 qWarning(
"QPainter::clipRegion: Painter not active");
2500 bool lastWasNothing =
true;
2503 const_cast<QPainter *>(
this)->d_ptr->updateInvMatrix();
2506 for (
const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2507 switch (info.clipType) {
2509 case QPainterClipInfo::RegionClip: {
2510 QTransform matrix = (info.matrix * d->invMatrix);
2511 if (lastWasNothing) {
2512 region = info.region * matrix;
2513 lastWasNothing =
false;
2516 if (info.operation == Qt::IntersectClip)
2517 region &= info.region * matrix;
2518 else if (info.operation == Qt::NoClip) {
2519 lastWasNothing =
true;
2522 region = info.region * matrix;
2526 case QPainterClipInfo::PathClip: {
2527 QTransform matrix = (info.matrix * d->invMatrix);
2528 if (lastWasNothing) {
2529 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2530 info.path.fillRule());
2531 lastWasNothing =
false;
2534 if (info.operation == Qt::IntersectClip) {
2535 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2536 info.path.fillRule());
2537 }
else if (info.operation == Qt::NoClip) {
2538 lastWasNothing =
true;
2541 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2542 info.path.fillRule());
2547 case QPainterClipInfo::RectClip: {
2548 QTransform matrix = (info.matrix * d->invMatrix);
2549 if (lastWasNothing) {
2550 region = QRegion(info.rect) * matrix;
2551 lastWasNothing =
false;
2554 if (info.operation == Qt::IntersectClip) {
2556 if (matrix.type() <= QTransform::TxScale)
2557 region &= matrix.mapRect(info.rect);
2559 region &= matrix.map(QRegion(info.rect));
2560 }
else if (info.operation == Qt::NoClip) {
2561 lastWasNothing =
true;
2564 region = QRegion(info.rect) * matrix;
2569 case QPainterClipInfo::RectFClip: {
2570 QTransform matrix = (info.matrix * d->invMatrix);
2571 if (lastWasNothing) {
2572 region = QRegion(info.rectf.toRect()) * matrix;
2573 lastWasNothing =
false;
2576 if (info.operation == Qt::IntersectClip) {
2578 if (matrix.type() <= QTransform::TxScale)
2579 region &= matrix.mapRect(info.rectf.toRect());
2581 region &= matrix.map(QRegion(info.rectf.toRect()));
2582 }
else if (info.operation == Qt::NoClip) {
2583 lastWasNothing =
true;
2586 region = QRegion(info.rectf.toRect()) * matrix;
2715void QPainter::setClipRect(
const QRectF &rect, Qt::ClipOperation op)
2721 qWarning(
"QPainter::setClipRect: Painter not active");
2724 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2725 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2726 op = Qt::ReplaceClip;
2728 qreal right = rect.x() + rect.width();
2729 qreal bottom = rect.y() + rect.height();
2730 qreal pts[] = { rect.x(), rect.y(),
2734 QVectorPath vp(pts, 4,
nullptr, QVectorPath::RectangleHint);
2735 d->state->clipEnabled =
true;
2736 d->extended->clip(vp, op);
2737 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2738 d->state->clipInfo.clear();
2739 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2740 d->state->clipOperation = op;
2744 if (qreal(
int(rect.top())) == rect.top()
2745 && qreal(
int(rect.bottom())) == rect.bottom()
2746 && qreal(
int(rect.left())) == rect.left()
2747 && qreal(
int(rect.right())) == rect.right())
2749 setClipRect(rect.toRect(), op);
2753 if (rect.isEmpty()) {
2754 setClipRegion(QRegion(), op);
2760 setClipPath(path, op);
2770void QPainter::setClipRect(
const QRect &rect, Qt::ClipOperation op)
2775 qWarning(
"QPainter::setClipRect: Painter not active");
2778 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2780 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2781 op = Qt::ReplaceClip;
2784 d->state->clipEnabled =
true;
2785 d->extended->clip(rect, op);
2786 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2787 d->state->clipInfo.clear();
2788 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2789 d->state->clipOperation = op;
2793 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2794 op = Qt::ReplaceClip;
2796 d->state->clipRegion = rect;
2797 d->state->clipOperation = op;
2798 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2799 d->state->clipInfo.clear();
2800 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2801 d->state->clipEnabled =
true;
2802 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2803 d->updateState(d->state);
2824void QPainter::setClipRegion(
const QRegion &r, Qt::ClipOperation op)
2828 QRect rect = r.boundingRect();
2829 if constexpr (qt_show_painter_debug_output)
2830 printf(
"QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2831 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2834 qWarning(
"QPainter::setClipRegion: Painter not active");
2837 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2839 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2840 op = Qt::ReplaceClip;
2843 d->state->clipEnabled =
true;
2844 d->extended->clip(r, op);
2845 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2846 d->state->clipInfo.clear();
2847 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2848 d->state->clipOperation = op;
2852 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2853 op = Qt::ReplaceClip;
2855 d->state->clipRegion = r;
2856 d->state->clipOperation = op;
2857 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2858 d->state->clipInfo.clear();
2859 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2860 d->state->clipEnabled =
true;
2861 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2862 d->updateState(d->state);
3036void QPainter::setClipPath(
const QPainterPath &path, Qt::ClipOperation op)
3039 if constexpr (qt_show_painter_debug_output) {
3040 QRectF b = path.boundingRect();
3041 printf(
"QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3042 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3048 qWarning(
"QPainter::setClipPath: Painter not active");
3052 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3053 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3054 op = Qt::ReplaceClip;
3057 d->state->clipEnabled =
true;
3058 d->extended->clip(path, op);
3059 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3060 d->state->clipInfo.clear();
3061 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3062 d->state->clipOperation = op;
3066 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3067 op = Qt::ReplaceClip;
3069 d->state->clipPath = path;
3070 d->state->clipOperation = op;
3071 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3072 d->state->clipInfo.clear();
3073 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3074 d->state->clipEnabled =
true;
3075 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3076 d->updateState(d->state);
3285void QPainter::drawRects(
const QRectF *rects,
int rectCount)
3288 if constexpr (qt_show_painter_debug_output)
3289 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3294 qWarning(
"QPainter::drawRects: Painter not active");
3302 d->extended->drawRects(rects, rectCount);
3306 d->updateState(d->state);
3308 if (!d->state->emulationSpecifier) {
3309 d->engine->drawRects(rects, rectCount);
3313 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3314 && d->state->matrix.type() == QTransform::TxTranslate) {
3315 for (
int i=0; i<rectCount; ++i) {
3316 QRectF r(rects[i].x() + d->state->matrix.dx(),
3317 rects[i].y() + d->state->matrix.dy(),
3320 d->engine->drawRects(&r, 1);
3323 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3324 for (
int i=0; i<rectCount; ++i) {
3325 QPainterPath rectPath;
3326 rectPath.addRect(rects[i]);
3327 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3330 QPainterPath rectPath;
3331 for (
int i=0; i<rectCount; ++i)
3332 rectPath.addRect(rects[i]);
3333 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3345void QPainter::drawRects(
const QRect *rects,
int rectCount)
3348 if constexpr (qt_show_painter_debug_output)
3349 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3354 qWarning(
"QPainter::drawRects: Painter not active");
3362 d->extended->drawRects(rects, rectCount);
3366 d->updateState(d->state);
3368 if (!d->state->emulationSpecifier) {
3369 d->engine->drawRects(rects, rectCount);
3373 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3374 && d->state->matrix.type() == QTransform::TxTranslate) {
3375 for (
int i=0; i<rectCount; ++i) {
3376 QRectF r(rects[i].x() + d->state->matrix.dx(),
3377 rects[i].y() + d->state->matrix.dy(),
3381 d->engine->drawRects(&r, 1);
3384 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3385 for (
int i=0; i<rectCount; ++i) {
3386 QPainterPath rectPath;
3387 rectPath.addRect(rects[i]);
3388 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3391 QPainterPath rectPath;
3392 for (
int i=0; i<rectCount; ++i)
3393 rectPath.addRect(rects[i]);
3395 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3445void QPainter::drawPoints(
const QPointF *points,
int pointCount)
3448 if constexpr (qt_show_painter_debug_output)
3449 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3454 qWarning(
"QPainter::drawPoints: Painter not active");
3458 if (pointCount <= 0)
3462 d->extended->drawPoints(points, pointCount);
3466 d->updateState(d->state);
3468 if (!d->state->emulationSpecifier) {
3469 d->engine->drawPoints(points, pointCount);
3473 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3474 && d->state->matrix.type() == QTransform::TxTranslate) {
3476 for (
int i=0; i<pointCount; ++i) {
3477 QPointF pt(points[i].x() + d->state->matrix.dx(),
3478 points[i].y() + d->state->matrix.dy());
3479 d->engine->drawPoints(&pt, 1);
3482 QPen pen = d->state->pen;
3483 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3486 pen.setCapStyle(Qt::SquareCap);
3490 for (
int i=0; i<pointCount; ++i) {
3491 path.moveTo(points[i].x(), points[i].y());
3492 path.lineTo(points[i].x() + 0.0001, points[i].y());
3494 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3507void QPainter::drawPoints(
const QPoint *points,
int pointCount)
3510 if constexpr (qt_show_painter_debug_output)
3511 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3516 qWarning(
"QPainter::drawPoints: Painter not active");
3520 if (pointCount <= 0)
3524 d->extended->drawPoints(points, pointCount);
3528 d->updateState(d->state);
3530 if (!d->state->emulationSpecifier) {
3531 d->engine->drawPoints(points, pointCount);
3535 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3536 && d->state->matrix.type() == QTransform::TxTranslate) {
3538 for (
int i=0; i<pointCount; ++i) {
3539 QPointF pt(points[i].x() + d->state->matrix.dx(),
3540 points[i].y() + d->state->matrix.dy());
3541 d->engine->drawPoints(&pt, 1);
3544 QPen pen = d->state->pen;
3545 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3548 pen.setCapStyle(Qt::SquareCap);
3552 for (
int i=0; i<pointCount; ++i) {
3553 path.moveTo(points[i].x(), points[i].y());
3554 path.lineTo(points[i].x() + 0.0001, points[i].y());
3556 d->draw_helper(path, QPainterPrivate::StrokeDraw);
4868void QPainter::drawPixmap(
const QPointF &p,
const QPixmap &pm)
4870#if defined QT_DEBUG_DRAW
4871 if constexpr (qt_show_painter_debug_output)
4872 printf(
"QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4874 pm.width(), pm.height());
4879 if (!d->engine || pm.isNull())
4883 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4887 d->extended->drawPixmap(p, pm);
4895 int h = pm.height();
4901 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4902 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4905 d->updateState(d->state);
4907 if ((d->state->matrix.type() > QTransform::TxTranslate
4908 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4909 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4910 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4915 if (d->state->matrix.type() <= QTransform::TxScale) {
4916 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4921 setBackgroundMode(Qt::TransparentMode);
4922 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
4923 QBrush brush(d->state->pen.color(), pm);
4926 setBrushOrigin(QPointF(0, 0));
4928 drawRect(pm.rect());
4931 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4932 x += d->state->matrix.dx();
4933 y += d->state->matrix.dy();
4935 qreal scale = pm.devicePixelRatio();
4936 d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4940void QPainter::drawPixmap(
const QRectF &r,
const QPixmap &pm,
const QRectF &sr)
4942#if defined QT_DEBUG_DRAW
4943 if constexpr (qt_show_painter_debug_output)
4944 printf(
"QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4945 r.x(), r.y(), r.width(), r.height(),
4946 pm.width(), pm.height(),
4947 sr.x(), sr.y(), sr.width(), sr.height());
4951 if (!d->engine || pm.isNull())
4954 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4959 qreal w = r.width();
4960 qreal h = r.height();
4963 qreal sw = sr.width();
4964 qreal sh = sr.height();
4969 const qreal pmscale = pm.devicePixelRatio();
4973 sw = pm.width() - sx;
4976 sh = pm.height() - sy;
4984 qreal w_ratio = sx * w/sw;
4992 qreal h_ratio = sy * h/sh;
4999 if (sw + sx > pm.width()) {
5000 qreal delta = sw - (pm.width() - sx);
5001 qreal w_ratio = delta * w/sw;
5006 if (sh + sy > pm.height()) {
5007 qreal delta = sh - (pm.height() - sy);
5008 qreal h_ratio = delta * h/sh;
5013 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5017 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5022 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
5023 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
5025 d->updateState(d->state);
5027 if ((d->state->matrix.type() > QTransform::TxTranslate
5028 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5029 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5030 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
5031 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
5036 if (d->state->matrix.type() <= QTransform::TxScale) {
5037 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5042 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5050 scale(w / sw, h / sh);
5051 setBackgroundMode(Qt::TransparentMode);
5052 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5055 if (sw == pm.width() && sh == pm.height())
5056 brush = QBrush(d->state->pen.color(), pm);
5058 brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
5063 drawRect(QRectF(0, 0, sw, sh));
5066 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5067 x += d->state->matrix.dx();
5068 y += d->state->matrix.dy();
5070 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5177void QPainter::drawImage(
const QPointF &p,
const QImage &image)
5181 if (!d->engine || image.isNull())
5185 d->extended->drawImage(p, image);
5192 int w = image.width();
5193 int h = image.height();
5194 qreal scale = image.devicePixelRatio();
5196 d->updateState(d->state);
5198 if (((d->state->matrix.type() > QTransform::TxTranslate)
5199 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5200 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5201 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5206 if (d->state->matrix.type() <= QTransform::TxScale) {
5207 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5212 setBackgroundMode(Qt::TransparentMode);
5213 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5214 QBrush brush(image);
5217 setBrushOrigin(QPointF(0, 0));
5218 drawRect(QRect(QPoint(0, 0), image.size() / scale));
5223 if (d->state->matrix.type() == QTransform::TxTranslate
5224 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5225 x += d->state->matrix.dx();
5226 y += d->state->matrix.dy();
5229 d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5232void QPainter::drawImage(
const QRectF &targetRect,
const QImage &image,
const QRectF &sourceRect,
5233 Qt::ImageConversionFlags flags)
5237 if (!d->engine || image.isNull())
5240 qreal x = targetRect.x();
5241 qreal y = targetRect.y();
5242 qreal w = targetRect.width();
5243 qreal h = targetRect.height();
5244 qreal sx = sourceRect.x();
5245 qreal sy = sourceRect.y();
5246 qreal sw = sourceRect.width();
5247 qreal sh = sourceRect.height();
5248 qreal imageScale = image.devicePixelRatio();
5252 sw = image.width() - sx;
5255 sh = image.height() - sy;
5258 w = sw / imageScale;
5260 h = sh / imageScale;
5263 qreal w_ratio = sx * w/sw;
5271 qreal h_ratio = sy * h/sh;
5278 if (sw + sx > image.width()) {
5279 qreal delta = sw - (image.width() - sx);
5280 qreal w_ratio = delta * w/sw;
5285 if (sh + sy > image.height()) {
5286 qreal delta = sh - (image.height() - sy);
5287 qreal h_ratio = delta * h/sh;
5292 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5296 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5300 d->updateState(d->state);
5302 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5303 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5304 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5305 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5310 if (d->state->matrix.type() <= QTransform::TxScale) {
5311 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5316 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5323 scale(w / sw, h / sh);
5324 setBackgroundMode(Qt::TransparentMode);
5325 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5326 QBrush brush(image);
5329 setBrushOrigin(QPointF(-sx, -sy));
5331 drawRect(QRectF(0, 0, sw, sh));
5336 if (d->state->matrix.type() == QTransform::TxTranslate
5337 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5338 x += d->state->matrix.dx();
5339 y += d->state->matrix.dy();
5342 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5357void QPainter::drawGlyphRun(
const QPointF &position,
const QGlyphRun &glyphRun)
5362 qWarning(
"QPainter::drawGlyphRun: Painter not active");
5366 QRawFont font = glyphRun.rawFont();
5367 if (!font.isValid())
5370 QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5372 const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5373 const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5375 int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5376 QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5378 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
5379 bool engineRequiresPretransformedGlyphPositions = d->extended
5380 ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5381 : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5383 for (
int i=0; i<count; ++i) {
5384 QPointF processedPosition = position + glyphPositions[i];
5385 if (engineRequiresPretransformedGlyphPositions)
5386 processedPosition = d->state->transform().map(processedPosition);
5387 fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5390 d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5391 ? d->state->transform().map(position)
5394 fixedPointPositions.data(),
5397 glyphRun.overline(),
5398 glyphRun.underline(),
5399 glyphRun.strikeOut());
5403 const quint32 *glyphArray,
5415 if (extended !=
nullptr && state->matrix.isAffine()) {
5416 QStaticTextItem staticTextItem;
5417 staticTextItem.color = state->pen.color();
5418 staticTextItem.font = state->font;
5419 staticTextItem.setFontEngine(fontEngine);
5420 staticTextItem.numGlyphs = glyphCount;
5421 staticTextItem.glyphs =
reinterpret_cast<glyph_t *>(
const_cast<glyph_t *>(glyphArray));
5422 staticTextItem.glyphPositions = positions;
5424 staticTextItem.usesRawFont =
true;
5426 extended->drawStaticTextItem(&staticTextItem);
5429 textItem.fontEngine = fontEngine;
5431 QVarLengthArray<QFixed, 128> advances(glyphCount);
5432 QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5433 QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5434 memset(glyphAttributes.data(), 0, glyphAttributes.size() *
sizeof(QGlyphAttributes));
5435 memset(
static_cast<
void *>(advances.data()), 0, advances.size() *
sizeof(QFixed));
5436 memset(
static_cast<
void *>(glyphJustifications.data()), 0, glyphJustifications.size() *
sizeof(QGlyphJustification));
5438 textItem.glyphs.numGlyphs = glyphCount;
5439 textItem.glyphs.glyphs =
const_cast<glyph_t *>(glyphArray);
5440 textItem.glyphs.offsets = positions;
5441 textItem.glyphs.advances = advances.data();
5442 textItem.glyphs.justifications = glyphJustifications.data();
5443 textItem.glyphs.attributes = glyphAttributes.data();
5445 engine->drawTextItem(QPointF(0, 0), textItem);
5448 qt_draw_decoration_for_glyphs(q,
5527void QPainter::drawStaticText(
const QPointF &topLeftPosition,
const QStaticText &staticText)
5530 if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5533 QStaticTextPrivate *staticText_d =
5534 const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5536 QFontPrivate *fp = QFontPrivate::get(font());
5537 QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5538 if (font() != staticText_d->font || fp ==
nullptr || stfp ==
nullptr || fp->dpi != stfp->dpi) {
5539 staticText_d->font = font();
5540 staticText_d->needsRelayout =
true;
5541 }
else if (stfp->engineData ==
nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5542 staticText_d->needsRelayout =
true;
5545 QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5546 if (fe->type() == QFontEngine::Multi)
5547 fe =
static_cast<QFontEngineMulti *>(fe)->engine(0);
5552 if (d->extended ==
nullptr
5553 || !d->state->matrix.isAffine()
5554 || !fe->supportsTransformation(d->state->matrix)) {
5555 staticText_d->paintText(topLeftPosition,
this, pen().color());
5559 bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5560 if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5563 staticText_d->untransformedCoordinates =
false;
5564 staticText_d->needsRelayout =
true;
5565 }
else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5568 staticText_d->untransformedCoordinates =
true;
5569 staticText_d->needsRelayout =
true;
5574 QPointF transformedPosition = topLeftPosition;
5575 if (!staticText_d->untransformedCoordinates)
5576 transformedPosition = transformedPosition * d->state->matrix;
5577 QTransform oldMatrix;
5581 if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5582 qreal m11 = d->state->matrix.m11();
5583 qreal m12 = d->state->matrix.m12();
5584 qreal m13 = d->state->matrix.m13();
5585 qreal m21 = d->state->matrix.m21();
5586 qreal m22 = d->state->matrix.m22();
5587 qreal m23 = d->state->matrix.m23();
5588 qreal m33 = d->state->matrix.m33();
5590 oldMatrix = d->state->matrix;
5591 d->state->matrix.setMatrix(m11, m12, m13,
5598 bool staticTextNeedsReinit = staticText_d->needsRelayout;
5599 if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5600 staticText_d->matrix = d->state->matrix;
5601 staticTextNeedsReinit =
true;
5605 if (staticTextNeedsReinit)
5606 staticText_d->init();
5608 if (transformedPosition != staticText_d->position) {
5609 QFixed fx = QFixed::fromReal(transformedPosition.x());
5610 QFixed fy = QFixed::fromReal(transformedPosition.y());
5611 QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5612 QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5613 for (
int item=0; item<staticText_d->itemCount;++item) {
5614 QStaticTextItem *textItem = staticText_d->items + item;
5615 for (
int i=0; i<textItem->numGlyphs; ++i) {
5616 textItem->glyphPositions[i].x += fx - oldX;
5617 textItem->glyphPositions[i].y += fy - oldY;
5619 textItem->userDataNeedsUpdate =
true;
5622 staticText_d->position = transformedPosition;
5625 QPen oldPen = d->state->pen;
5626 QColor currentColor = oldPen.color();
5627 static const QColor bodyIndicator(0, 0, 0, 0);
5628 for (
int i=0; i<staticText_d->itemCount; ++i) {
5629 QStaticTextItem *item = staticText_d->items + i;
5630 if (item->color.isValid() && currentColor != item->color
5631 && item->color != bodyIndicator) {
5632 setPen(item->color);
5633 currentColor = item->color;
5634 }
else if (item->color == bodyIndicator) {
5636 currentColor = oldPen.color();
5638 d->extended->drawStaticTextItem(item);
5640 qt_draw_decoration_for_glyphs(
this,
5643 item->glyphPositions,
5646 staticText_d->font.underline(),
5647 staticText_d->font.overline(),
5648 staticText_d->font.strikeOut());
5650 if (currentColor != oldPen.color())
5653 if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5654 d->state->matrix = oldMatrix;
5660void QPainter::drawText(
const QPointF &p,
const QString &str,
int tf,
int justificationPadding)
5663 if constexpr (qt_show_painter_debug_output)
5664 printf(
"QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5669 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5672 Q_DECL_UNINITIALIZED QStackTextEngine engine(str, d->state->font);
5673 engine.option.setTextDirection(d->state->layoutDirection);
5674 if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
5675 engine.ignoreBidi =
true;
5676 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5680 line.length = str.size();
5681 engine.shapeLine(line);
5683 int nItems = engine.layoutData->items.size();
5684 QVarLengthArray<
int> visualOrder(nItems);
5685 QVarLengthArray<uchar> levels(nItems);
5686 for (
int i = 0; i < nItems; ++i)
5687 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5688 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5690 if (justificationPadding > 0) {
5691 engine.option.setAlignment(Qt::AlignJustify);
5692 engine.forceJustification =
true;
5694 line.width = justificationPadding;
5695 engine.justify(line);
5697 QFixed x = QFixed::fromReal(p.x());
5699 for (
int i = 0; i < nItems; ++i) {
5700 int item = visualOrder[i];
5701 const QScriptItem &si = engine.layoutData->items.at(item);
5702 if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
5706 QFont f = engine.font(si);
5707 QTextItemInt gf(si, &f);
5708 gf.glyphs = engine.shapedGlyphs(&si);
5709 gf.chars = engine.layoutData->string.unicode() + si.position;
5710 gf.num_chars = engine.length(item);
5711 if (engine.forceJustification) {
5712 for (
int j=0; j<gf.glyphs.numGlyphs; ++j)
5713 gf.width += gf.glyphs.effectiveAdvance(j);
5715 gf.width = si.width;
5717 gf.logClusters = engine.logClusters(&si);
5719 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5987 const qreal radiusBase = qMax(qreal(1), maxRadius);
5989 QString key =
"WaveUnderline-"_L1
5990 % pen.color().name()
5991 % HexString<qreal>(radiusBase)
5992 % HexString<qreal>(pen.widthF());
5995 if (QPixmapCache::find(key, &pixmap))
5998 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399));
5999 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
6000 const qreal radius = qFloor(radiusBase * 2) / 2.;
6007 while (xs < width) {
6010 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
6013 pixmap = QPixmap(width, radius * 2);
6014 pixmap.fill(Qt::transparent);
6017 wavePen.setCapStyle(Qt::SquareCap);
6021 const qreal maxPenWidth = .8 * radius;
6022 if (wavePen.widthF() > maxPenWidth)
6023 wavePen.setWidthF(maxPenWidth);
6026 imgPainter.setPen(wavePen);
6027 imgPainter.setRenderHint(QPainter::Antialiasing);
6028 imgPainter.translate(0, radius);
6029 imgPainter.drawPath(path);
6032 QPixmapCache::insert(key, pixmap);
6038 QTextCharFormat::UnderlineStyle underlineStyle,
6039 QTextItem::RenderFlags flags, qreal width,
6040 const QTextCharFormat &charFormat)
6042 if (underlineStyle == QTextCharFormat::NoUnderline
6043 && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
6046 const QPen oldPen = painter->pen();
6047 const QBrush oldBrush = painter->brush();
6048 painter->setBrush(Qt::NoBrush);
6050 pen.setStyle(Qt::SolidLine);
6051 pen.setWidthF(fe->lineThickness().toReal());
6052 pen.setCapStyle(Qt::FlatCap);
6054 QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
6056 const qreal underlineOffset = fe->underlinePosition().toReal();
6058 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
6059 QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
6061 underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt());
6062 if (underlineStyle == QTextCharFormat::SpellCheckUnderline)
6063 underlineStyle = QTextCharFormat::WaveUnderline;
6066 if (underlineStyle == QTextCharFormat::WaveUnderline) {
6068 painter->translate(0, pos.y() + 1);
6069 qreal maxHeight = fe->descent().toReal() - qreal(1);
6071 QColor uc = charFormat.underlineColor();
6076 const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
6077 const int descent = qFloor(maxHeight);
6079 painter->setBrushOrigin(painter->brushOrigin().x(), 0);
6080 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
6082 }
else if (underlineStyle != QTextCharFormat::NoUnderline) {
6083 const bool isAntialiasing = painter->renderHints().testFlag(QPainter::Antialiasing);
6084 if (!isAntialiasing)
6085 pen.setWidthF(qMax(fe->lineThickness().round(), QFixed(1)).toReal());
6086 const qreal lineThicknessOffset = pen.widthF() / 2.0;
6090 qreal adjustedUnderlineOffset =
std::ceil(underlineOffset) + lineThicknessOffset;
6091 if (underlineOffset <= fe->descent().toReal())
6092 adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - lineThicknessOffset);
6093 const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6094 QColor uc = charFormat.underlineColor();
6098 pen.setStyle((Qt::PenStyle)(underlineStyle));
6099 painter->setPen(pen);
6100 QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6102 textEngine->addUnderline(painter, underline);
6104 painter->drawLine(underline);
6106 if (!isAntialiasing)
6107 pen.setWidthF(fe->lineThickness().toReal());
6110 pen.setStyle(Qt::SolidLine);
6111 pen.setColor(oldPen.color());
6113 if (flags & QTextItem::StrikeOut) {
6114 QLineF strikeOutLine = line;
6115 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6116 QColor uc = charFormat.underlineColor();
6119 painter->setPen(pen);
6121 textEngine->addStrikeOut(painter, strikeOutLine);
6123 painter->drawLine(strikeOutLine);
6126 if (flags & QTextItem::Overline) {
6127 QLineF overline = line;
6128 overline.translate(0., - fe->ascent().toReal());
6129 QColor uc = charFormat.underlineColor();
6132 painter->setPen(pen);
6134 textEngine->addOverline(painter, overline);
6136 painter->drawLine(overline);
6139 painter->setPen(oldPen);
6140 painter->setBrush(oldBrush);
6193 if constexpr (qt_show_painter_debug_output)
6194 printf(
"QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6195 p.x(), p.y(), qPrintable(_ti.text()));
6203 QTextItemInt &ti =
const_cast<QTextItemInt &>(
static_cast<
const QTextItemInt &>(_ti));
6205 if (!extended && state->bgMode == Qt::OpaqueMode) {
6206 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6207 q->fillRect(rect, state->bgBrush);
6210 if (q->pen().style() == Qt::NoPen)
6213 const QPainter::RenderHints oldRenderHints = state->renderHints;
6214 if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6219 const QTransform &m = state->matrix;
6220 if (state->matrix.type() < QTransform::TxShear) {
6221 bool isPlain90DegreeRotation =
6222 (qFuzzyIsNull(m.m11())
6223 && qFuzzyIsNull(m.m12() - qreal(1))
6224 && qFuzzyIsNull(m.m21() + qreal(1))
6225 && qFuzzyIsNull(m.m22())
6228 (qFuzzyIsNull(m.m11() + qreal(1))
6229 && qFuzzyIsNull(m.m12())
6230 && qFuzzyIsNull(m.m21())
6231 && qFuzzyIsNull(m.m22() + qreal(1))
6234 (qFuzzyIsNull(m.m11())
6235 && qFuzzyIsNull(m.m12() + qreal(1))
6236 && qFuzzyIsNull(m.m21() - qreal(1))
6237 && qFuzzyIsNull(m.m22())
6240 aa = !isPlain90DegreeRotation;
6243 q->setRenderHint(QPainter::Antialiasing,
true);
6249 if (!ti.glyphs.numGlyphs) {
6250 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6251 ti.flags, ti.width.toReal(), ti.charFormat);
6252 }
else if (ti.fontEngine->type() == QFontEngine::Multi) {
6253 QFontEngineMulti *multi =
static_cast<QFontEngineMulti *>(ti.fontEngine);
6256 int which = glyphs.glyphs[0] >> 24;
6261 bool rtl = ti.flags & QTextItem::RightToLeft;
6263 x += ti.width.toReal();
6267 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6268 const int e = glyphs.glyphs[end] >> 24;
6273 multi->ensureEngineAt(which);
6274 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6277 for (i = start; i < end; ++i) {
6278 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6279 ti2.width += ti.glyphs.effectiveAdvance(i);
6283 x -= ti2.width.toReal();
6288 engine->drawTextItem(QPointF(x, y), ti2);
6289 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6290 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6293 x += ti2.width.toReal();
6296 const int hi = which << 24;
6297 for (i = start; i < end; ++i) {
6298 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6306 multi->ensureEngineAt(which);
6307 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6310 for (i = start; i < end; ++i) {
6311 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6312 ti2.width += ti.glyphs.effectiveAdvance(i);
6316 x -= ti2.width.toReal();
6321 engine->drawTextItem(QPointF(x,y), ti2);
6322 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6323 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6326 const int hi = which << 24;
6327 for (i = start; i < end; ++i)
6328 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6334 engine->drawTextItem(p, ti);
6335 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6336 ti.flags, ti.width.toReal(), ti.charFormat);
6339 if (state->renderHints != oldRenderHints) {
6340 state->renderHints = oldRenderHints;
6344 state->dirtyFlags |= QPaintEngine::DirtyHints;
6471void QPainter::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sp)
6474 if constexpr (qt_show_painter_debug_output)
6475 printf(
"QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6476 r.x(), r.y(), r.width(), r.height(),
6477 pixmap.width(), pixmap.height(),
6482 if (!d->engine || pixmap.isNull() || r.isEmpty())
6486 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawTiledPixmap()");
6489 qreal sw = pixmap.width();
6490 qreal sh = pixmap.height();
6494 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6496 sx = qRound(sx) % qRound(sw);
6498 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6500 sy = qRound(sy) % qRound(sh);
6504 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6508 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6509 fillRect(r, d->state->bgBrush);
6511 d->updateState(d->state);
6512 if ((d->state->matrix.type() > QTransform::TxTranslate
6513 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6514 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6517 setBackgroundMode(Qt::TransparentMode);
6518 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
6519 setBrush(QBrush(d->state->pen.color(), pixmap));
6524 if (d->state->matrix.type() <= QTransform::TxScale) {
6525 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6527 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6532 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6533 drawRect(QRectF(p, r.size()));
6535 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6544 if (d->state->matrix.type() == QTransform::TxTranslate
6545 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6546 x += d->state->matrix.dx();
6547 y += d->state->matrix.dy();
6550 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
7171 const QTextOption *option,
7179 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=
nullptr) );
7181 if (_r.isEmpty() && !(tf & Qt::TextDontClip)) {
7185 tf |= Qt::TextDontPrint;
7189 alignment |= option->alignment();
7190 if (option->wrapMode() != QTextOption::NoWrap)
7191 tf |= Qt::TextWordWrap;
7193 if (option->flags() & QTextOption::IncludeTrailingSpaces)
7194 tf |= Qt::TextIncludeTrailingSpaces;
7196 if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7197 tf |= Qt::TextExpandTabs;
7203 bool dontclip = (tf & Qt::TextDontClip);
7204 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7205 bool singleline = (tf & Qt::TextSingleLine);
7206 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7207 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7209 Qt::LayoutDirection layout_direction;
7210 if (tf & Qt::TextForceLeftToRight)
7211 layout_direction = Qt::LeftToRight;
7212 else if (tf & Qt::TextForceRightToLeft)
7213 layout_direction = Qt::RightToLeft;
7215 layout_direction = option->textDirection();
7217 layout_direction = painter->layoutDirection();
7219 layout_direction = Qt::LeftToRight;
7221 alignment = QGuiApplicationPrivate::visualAlignment(layout_direction, QFlag(alignment));
7223 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7224 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7225 (((alignment & Qt::AlignLeft) && !isRightToLeft) ||
7226 ((alignment & Qt::AlignRight) && isRightToLeft)));
7229 tf |= Qt::TextDontPrint;
7231 uint maxUnderlines = 0;
7233 QFontMetricsF fm(fnt);
7237 bool hasMoreLengthVariants =
false;
7240 int old_offset = offset;
7241 for (; offset < text.size(); offset++) {
7242 QChar chr = text.at(offset);
7243 if (chr == u'\r' || (singleline && chr == u'\n')) {
7244 text[offset] = u' ';
7245 }
else if (chr == u'\n') {
7246 text[offset] = QChar::LineSeparator;
7247 }
else if (chr == u'&') {
7249 }
else if (chr == u'\t') {
7251 text[offset] = u' ';
7252 }
else if (!tabarraylen && !tabstops) {
7253 tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7255 }
else if (chr == u'\x9c') {
7257 hasMoreLengthVariants =
true;
7262 QList<QTextLayout::FormatRange> underlineFormats;
7263 int length = offset - old_offset;
7264 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7265 QChar *cout = text.data() + old_offset;
7266 QChar *cout0 = cout;
7276 if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7277 QTextLayout::FormatRange range;
7278 range.start = cout - cout0;
7280 range.format.setFontUnderline(
true);
7281 underlineFormats.append(range);
7284 }
else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7285 cin[1] == u'&' && cin[2] != u'&' &&
7288 while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7307 QString finalText = text.mid(old_offset, length);
7308 Q_DECL_UNINITIALIZED QStackTextEngine engine(finalText, fnt);
7310 engine.option = *option;
7313 if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7314 engine.option.setTabStopDistance(tabstops);
7316 if (engine.option.tabs().isEmpty() && ta) {
7318 tabs.reserve(tabarraylen);
7319 for (
int i = 0; i < tabarraylen; i++)
7320 tabs.append(qreal(ta[i]));
7321 engine.option.setTabArray(tabs);
7324 engine.option.setTextDirection(layout_direction);
7325 if (alignment & Qt::AlignJustify)
7326 engine.option.setAlignment(Qt::AlignJustify);
7328 engine.option.setAlignment(Qt::AlignLeft);
7330 if (!option && (tf & Qt::TextWrapAnywhere))
7331 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7333 if (tf & Qt::TextJustificationForced)
7334 engine.forceJustification =
true;
7336 textLayout.setCacheEnabled(
true);
7337 textLayout.setFormats(underlineFormats);
7339 if (finalText.isEmpty()) {
7340 height = fm.height();
7342 tf |= Qt::TextDontPrint;
7344 qreal lineWidth = 0x01000000;
7345 if (wordwrap || (tf & Qt::TextJustificationForced))
7346 lineWidth = qMax<qreal>(0, r.width());
7348 tf |= Qt::TextIncludeTrailingSpaces;
7349 textLayout.beginLayout();
7351 qreal leading = fm.leading();
7355 QTextLine l = textLayout.createLine();
7359 l.setLineWidth(lineWidth);
7363 height = qCeil(height);
7365 if (alignment & Qt::AlignBaseline && l.lineNumber() == 0)
7366 height -= l.ascent();
7368 l.setPosition(
QPointF(0., height));
7369 height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7370 width = qMax(width, l.naturalTextWidth());
7371 if (!dontclip && !brect && height >= r.height())
7374 textLayout.endLayout();
7379 if (alignment & Qt::AlignBottom)
7380 yoff = r.height() - height;
7381 else if (alignment & Qt::AlignVCenter)
7382 yoff = (r.height() - height)/2;
7384 if (alignment & Qt::AlignRight)
7385 xoff = r.width() - width;
7386 else if (alignment & Qt::AlignHCenter)
7387 xoff = (r.width() - width)/2;
7389 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7391 if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7393 goto start_lengthVariant;
7398 if (!(tf & Qt::TextDontPrint)) {
7399 bool restore =
false;
7400 if (!dontclip && !r.contains(bounds)) {
7403 painter->setClipRect(r, Qt::IntersectClip);
7406 for (
int i = 0; i < textLayout.lineCount(); i++) {
7407 QTextLine line = textLayout.lineAt(i);
7409 eng->enableDelayDecorations();
7411 qreal advance = line.horizontalAdvance();
7413 if (alignment & Qt::AlignRight) {
7414 xoff = r.width() - advance -
7415 eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7416 }
else if (alignment & Qt::AlignHCenter) {
7417 xoff = (r.width() - advance) / 2;
7420 line.draw(painter,
QPointF(r.x() + xoff, r.y() + yoff));
7421 eng->drawDecorations(painter);
7499QPainterState::QPainterState(
const QPainterState *s)
7500 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7501 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7502 clipRegion(s->clipRegion), clipPath(s->clipPath),
7503 clipOperation(s->clipOperation),
7504 renderHints(s->renderHints), clipInfo(s->clipInfo),
7505 worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7506 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7507 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7508 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7509 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7510 layoutDirection(s->layoutDirection),
7511 composition_mode(s->composition_mode),
7512 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7514 dirtyFlags = s->dirtyFlags;
8135void QPainter::drawPixmapFragments(
const PixmapFragment *fragments,
int fragmentCount,
8136 const QPixmap &pixmap, PixmapFragmentHints hints)
8140 if (!d->engine || pixmap.isNull())
8144 for (
int i = 0; i < fragmentCount; ++i) {
8145 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8146 fragments[i].width, fragments[i].height);
8147 if (!(QRectF(pixmap.rect()).contains(sourceRect)))
8148 qWarning(
"QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
8152 if (d->engine->isExtended()) {
8153 d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8155 qreal oldOpacity = opacity();
8156 QTransform oldTransform = transform();
8158 for (
int i = 0; i < fragmentCount; ++i) {
8159 QTransform transform = oldTransform;
8162 if (fragments[i].rotation == 0) {
8163 xOffset = fragments[i].x;
8164 yOffset = fragments[i].y;
8166 transform.translate(fragments[i].x, fragments[i].y);
8167 transform.rotate(fragments[i].rotation);
8169 setOpacity(oldOpacity * fragments[i].opacity);
8170 setTransform(transform);
8172 qreal w = fragments[i].scaleX * fragments[i].width;
8173 qreal h = fragments[i].scaleY * fragments[i].height;
8174 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8175 fragments[i].width, fragments[i].height);
8176 drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8179 setOpacity(oldOpacity);
8180 setTransform(oldTransform);