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);
1804 switch (d->original_device->devType()) {
1805 case QInternal::Widget:
1806 d->initFrom(d->original_device);
1810 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1812 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1816 QRect systemRect = d->engine->systemRect();
1817 if (!systemRect.isEmpty()) {
1818 d->state->ww = d->state->vw = systemRect.width();
1819 d->state->wh = d->state->vh = systemRect.height();
1821 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1822 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1825 const QPoint coordinateOffset = d->engine->coordinateOffset();
1826 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1828 Q_ASSERT(d->engine->isActive());
1830 if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
1833 Q_ASSERT(d->engine->isActive());
1834 d->state->renderHints = QPainter::TextAntialiasing;
1835 ++d->device->painters;
1837 d->state->emulationSpecifier = 0;
1839 switch (d->original_device->devType()) {
1840 case QInternal::Widget:
1844 d->initFrom(d->original_device);
2502QRegion QPainter::clipRegion()
const
2504 Q_D(
const QPainter);
2506 qWarning(
"QPainter::clipRegion: Painter not active");
2511 bool lastWasNothing =
true;
2514 const_cast<QPainter *>(
this)->d_ptr->updateInvMatrix();
2517 for (
const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2518 switch (info.clipType) {
2520 case QPainterClipInfo::RegionClip: {
2521 QTransform matrix = (info.matrix * d->invMatrix);
2522 if (lastWasNothing) {
2523 region = info.region * matrix;
2524 lastWasNothing =
false;
2527 if (info.operation == Qt::IntersectClip)
2528 region &= info.region * matrix;
2529 else if (info.operation == Qt::NoClip) {
2530 lastWasNothing =
true;
2533 region = info.region * matrix;
2537 case QPainterClipInfo::PathClip: {
2538 QTransform matrix = (info.matrix * d->invMatrix);
2539 if (lastWasNothing) {
2540 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2541 info.path.fillRule());
2542 lastWasNothing =
false;
2545 if (info.operation == Qt::IntersectClip) {
2546 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2547 info.path.fillRule());
2548 }
else if (info.operation == Qt::NoClip) {
2549 lastWasNothing =
true;
2552 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2553 info.path.fillRule());
2558 case QPainterClipInfo::RectClip: {
2559 QTransform matrix = (info.matrix * d->invMatrix);
2560 if (lastWasNothing) {
2561 region = QRegion(info.rect) * matrix;
2562 lastWasNothing =
false;
2565 if (info.operation == Qt::IntersectClip) {
2567 if (matrix.type() <= QTransform::TxScale)
2568 region &= matrix.mapRect(info.rect);
2570 region &= matrix.map(QRegion(info.rect));
2571 }
else if (info.operation == Qt::NoClip) {
2572 lastWasNothing =
true;
2575 region = QRegion(info.rect) * matrix;
2580 case QPainterClipInfo::RectFClip: {
2581 QTransform matrix = (info.matrix * d->invMatrix);
2582 if (lastWasNothing) {
2583 region = QRegion(info.rectf.toRect()) * matrix;
2584 lastWasNothing =
false;
2587 if (info.operation == Qt::IntersectClip) {
2589 if (matrix.type() <= QTransform::TxScale)
2590 region &= matrix.mapRect(info.rectf.toRect());
2592 region &= matrix.map(QRegion(info.rectf.toRect()));
2593 }
else if (info.operation == Qt::NoClip) {
2594 lastWasNothing =
true;
2597 region = QRegion(info.rectf.toRect()) * matrix;
2726void QPainter::setClipRect(
const QRectF &rect, Qt::ClipOperation op)
2732 qWarning(
"QPainter::setClipRect: Painter not active");
2735 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2736 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2737 op = Qt::ReplaceClip;
2739 qreal right = rect.x() + rect.width();
2740 qreal bottom = rect.y() + rect.height();
2741 qreal pts[] = { rect.x(), rect.y(),
2745 QVectorPath vp(pts, 4,
nullptr, QVectorPath::RectangleHint);
2746 d->state->clipEnabled =
true;
2747 d->extended->clip(vp, op);
2748 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2749 d->state->clipInfo.clear();
2750 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2751 d->state->clipOperation = op;
2755 if (qreal(
int(rect.top())) == rect.top()
2756 && qreal(
int(rect.bottom())) == rect.bottom()
2757 && qreal(
int(rect.left())) == rect.left()
2758 && qreal(
int(rect.right())) == rect.right())
2760 setClipRect(rect.toRect(), op);
2764 if (rect.isEmpty()) {
2765 setClipRegion(QRegion(), op);
2771 setClipPath(path, op);
2781void QPainter::setClipRect(
const QRect &rect, Qt::ClipOperation op)
2786 qWarning(
"QPainter::setClipRect: Painter not active");
2789 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2791 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2792 op = Qt::ReplaceClip;
2795 d->state->clipEnabled =
true;
2796 d->extended->clip(rect, op);
2797 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2798 d->state->clipInfo.clear();
2799 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2800 d->state->clipOperation = op;
2804 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2805 op = Qt::ReplaceClip;
2807 d->state->clipRegion = rect;
2808 d->state->clipOperation = op;
2809 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2810 d->state->clipInfo.clear();
2811 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2812 d->state->clipEnabled =
true;
2813 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2814 d->updateState(d->state);
2835void QPainter::setClipRegion(
const QRegion &r, Qt::ClipOperation op)
2839 QRect rect = r.boundingRect();
2840 if constexpr (qt_show_painter_debug_output)
2841 printf(
"QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2842 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2845 qWarning(
"QPainter::setClipRegion: Painter not active");
2848 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2850 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2851 op = Qt::ReplaceClip;
2854 d->state->clipEnabled =
true;
2855 d->extended->clip(r, op);
2856 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2857 d->state->clipInfo.clear();
2858 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2859 d->state->clipOperation = op;
2863 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2864 op = Qt::ReplaceClip;
2866 d->state->clipRegion = r;
2867 d->state->clipOperation = op;
2868 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2869 d->state->clipInfo.clear();
2870 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2871 d->state->clipEnabled =
true;
2872 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2873 d->updateState(d->state);
3047void QPainter::setClipPath(
const QPainterPath &path, Qt::ClipOperation op)
3050 if constexpr (qt_show_painter_debug_output) {
3051 QRectF b = path.boundingRect();
3052 printf(
"QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3053 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3059 qWarning(
"QPainter::setClipPath: Painter not active");
3063 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3064 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3065 op = Qt::ReplaceClip;
3068 d->state->clipEnabled =
true;
3069 d->extended->clip(path, op);
3070 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3071 d->state->clipInfo.clear();
3072 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3073 d->state->clipOperation = op;
3077 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3078 op = Qt::ReplaceClip;
3080 d->state->clipPath = path;
3081 d->state->clipOperation = op;
3082 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3083 d->state->clipInfo.clear();
3084 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3085 d->state->clipEnabled =
true;
3086 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3087 d->updateState(d->state);
3296void QPainter::drawRects(
const QRectF *rects,
int rectCount)
3299 if constexpr (qt_show_painter_debug_output)
3300 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3305 qWarning(
"QPainter::drawRects: Painter not active");
3313 d->extended->drawRects(rects, rectCount);
3317 d->updateState(d->state);
3319 if (!d->state->emulationSpecifier) {
3320 d->engine->drawRects(rects, rectCount);
3324 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3325 && d->state->matrix.type() == QTransform::TxTranslate) {
3326 for (
int i=0; i<rectCount; ++i) {
3327 QRectF r(rects[i].x() + d->state->matrix.dx(),
3328 rects[i].y() + d->state->matrix.dy(),
3331 d->engine->drawRects(&r, 1);
3334 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3335 for (
int i=0; i<rectCount; ++i) {
3336 QPainterPath rectPath;
3337 rectPath.addRect(rects[i]);
3338 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3341 QPainterPath rectPath;
3342 for (
int i=0; i<rectCount; ++i)
3343 rectPath.addRect(rects[i]);
3344 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3356void QPainter::drawRects(
const QRect *rects,
int rectCount)
3359 if constexpr (qt_show_painter_debug_output)
3360 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3365 qWarning(
"QPainter::drawRects: Painter not active");
3373 d->extended->drawRects(rects, rectCount);
3377 d->updateState(d->state);
3379 if (!d->state->emulationSpecifier) {
3380 d->engine->drawRects(rects, rectCount);
3384 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3385 && d->state->matrix.type() == QTransform::TxTranslate) {
3386 for (
int i=0; i<rectCount; ++i) {
3387 QRectF r(rects[i].x() + d->state->matrix.dx(),
3388 rects[i].y() + d->state->matrix.dy(),
3392 d->engine->drawRects(&r, 1);
3395 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3396 for (
int i=0; i<rectCount; ++i) {
3397 QPainterPath rectPath;
3398 rectPath.addRect(rects[i]);
3399 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3402 QPainterPath rectPath;
3403 for (
int i=0; i<rectCount; ++i)
3404 rectPath.addRect(rects[i]);
3406 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3456void QPainter::drawPoints(
const QPointF *points,
int pointCount)
3459 if constexpr (qt_show_painter_debug_output)
3460 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3465 qWarning(
"QPainter::drawPoints: Painter not active");
3469 if (pointCount <= 0)
3473 d->extended->drawPoints(points, pointCount);
3477 d->updateState(d->state);
3479 if (!d->state->emulationSpecifier) {
3480 d->engine->drawPoints(points, pointCount);
3484 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3485 && d->state->matrix.type() == QTransform::TxTranslate) {
3487 for (
int i=0; i<pointCount; ++i) {
3488 QPointF pt(points[i].x() + d->state->matrix.dx(),
3489 points[i].y() + d->state->matrix.dy());
3490 d->engine->drawPoints(&pt, 1);
3493 QPen pen = d->state->pen;
3494 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3497 pen.setCapStyle(Qt::SquareCap);
3501 for (
int i=0; i<pointCount; ++i) {
3502 path.moveTo(points[i].x(), points[i].y());
3503 path.lineTo(points[i].x() + 0.0001, points[i].y());
3505 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3518void QPainter::drawPoints(
const QPoint *points,
int pointCount)
3521 if constexpr (qt_show_painter_debug_output)
3522 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3527 qWarning(
"QPainter::drawPoints: Painter not active");
3531 if (pointCount <= 0)
3535 d->extended->drawPoints(points, pointCount);
3539 d->updateState(d->state);
3541 if (!d->state->emulationSpecifier) {
3542 d->engine->drawPoints(points, pointCount);
3546 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3547 && d->state->matrix.type() == QTransform::TxTranslate) {
3549 for (
int i=0; i<pointCount; ++i) {
3550 QPointF pt(points[i].x() + d->state->matrix.dx(),
3551 points[i].y() + d->state->matrix.dy());
3552 d->engine->drawPoints(&pt, 1);
3555 QPen pen = d->state->pen;
3556 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3559 pen.setCapStyle(Qt::SquareCap);
3563 for (
int i=0; i<pointCount; ++i) {
3564 path.moveTo(points[i].x(), points[i].y());
3565 path.lineTo(points[i].x() + 0.0001, points[i].y());
3567 d->draw_helper(path, QPainterPrivate::StrokeDraw);
4879void QPainter::drawPixmap(
const QPointF &p,
const QPixmap &pm)
4881#if defined QT_DEBUG_DRAW
4882 if constexpr (qt_show_painter_debug_output)
4883 printf(
"QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4885 pm.width(), pm.height());
4890 if (!d->engine || pm.isNull())
4894 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4898 d->extended->drawPixmap(p, pm);
4906 int h = pm.height();
4912 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4913 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4916 d->updateState(d->state);
4918 if ((d->state->matrix.type() > QTransform::TxTranslate
4919 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4920 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4921 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4926 if (d->state->matrix.type() <= QTransform::TxScale) {
4927 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4932 setBackgroundMode(Qt::TransparentMode);
4933 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
4934 QBrush brush(d->state->pen.color(), pm);
4937 setBrushOrigin(QPointF(0, 0));
4939 drawRect(pm.rect());
4942 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4943 x += d->state->matrix.dx();
4944 y += d->state->matrix.dy();
4946 qreal scale = pm.devicePixelRatio();
4947 d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4951void QPainter::drawPixmap(
const QRectF &r,
const QPixmap &pm,
const QRectF &sr)
4953#if defined QT_DEBUG_DRAW
4954 if constexpr (qt_show_painter_debug_output)
4955 printf(
"QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4956 r.x(), r.y(), r.width(), r.height(),
4957 pm.width(), pm.height(),
4958 sr.x(), sr.y(), sr.width(), sr.height());
4962 if (!d->engine || pm.isNull())
4965 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4970 qreal w = r.width();
4971 qreal h = r.height();
4974 qreal sw = sr.width();
4975 qreal sh = sr.height();
4980 const qreal pmscale = pm.devicePixelRatio();
4984 sw = pm.width() - sx;
4987 sh = pm.height() - sy;
4995 qreal w_ratio = sx * w/sw;
5003 qreal h_ratio = sy * h/sh;
5010 if (sw + sx > pm.width()) {
5011 qreal delta = sw - (pm.width() - sx);
5012 qreal w_ratio = delta * w/sw;
5017 if (sh + sy > pm.height()) {
5018 qreal delta = sh - (pm.height() - sy);
5019 qreal h_ratio = delta * h/sh;
5024 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5028 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5033 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
5034 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
5036 d->updateState(d->state);
5038 if ((d->state->matrix.type() > QTransform::TxTranslate
5039 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5040 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5041 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
5042 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
5047 if (d->state->matrix.type() <= QTransform::TxScale) {
5048 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5053 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5061 scale(w / sw, h / sh);
5062 setBackgroundMode(Qt::TransparentMode);
5063 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5066 if (sw == pm.width() && sh == pm.height())
5067 brush = QBrush(d->state->pen.color(), pm);
5069 brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
5074 drawRect(QRectF(0, 0, sw, sh));
5077 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5078 x += d->state->matrix.dx();
5079 y += d->state->matrix.dy();
5081 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5188void QPainter::drawImage(
const QPointF &p,
const QImage &image)
5192 if (!d->engine || image.isNull())
5196 d->extended->drawImage(p, image);
5203 int w = image.width();
5204 int h = image.height();
5205 qreal scale = image.devicePixelRatio();
5207 d->updateState(d->state);
5209 if (((d->state->matrix.type() > QTransform::TxTranslate)
5210 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5211 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5212 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5217 if (d->state->matrix.type() <= QTransform::TxScale) {
5218 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5223 setBackgroundMode(Qt::TransparentMode);
5224 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5225 QBrush brush(image);
5228 setBrushOrigin(QPointF(0, 0));
5229 drawRect(QRect(QPoint(0, 0), image.size() / scale));
5234 if (d->state->matrix.type() == QTransform::TxTranslate
5235 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5236 x += d->state->matrix.dx();
5237 y += d->state->matrix.dy();
5240 d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5243void QPainter::drawImage(
const QRectF &targetRect,
const QImage &image,
const QRectF &sourceRect,
5244 Qt::ImageConversionFlags flags)
5248 if (!d->engine || image.isNull())
5251 qreal x = targetRect.x();
5252 qreal y = targetRect.y();
5253 qreal w = targetRect.width();
5254 qreal h = targetRect.height();
5255 qreal sx = sourceRect.x();
5256 qreal sy = sourceRect.y();
5257 qreal sw = sourceRect.width();
5258 qreal sh = sourceRect.height();
5259 qreal imageScale = image.devicePixelRatio();
5263 sw = image.width() - sx;
5266 sh = image.height() - sy;
5269 w = sw / imageScale;
5271 h = sh / imageScale;
5274 qreal w_ratio = sx * w/sw;
5282 qreal h_ratio = sy * h/sh;
5289 if (sw + sx > image.width()) {
5290 qreal delta = sw - (image.width() - sx);
5291 qreal w_ratio = delta * w/sw;
5296 if (sh + sy > image.height()) {
5297 qreal delta = sh - (image.height() - sy);
5298 qreal h_ratio = delta * h/sh;
5303 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5307 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5311 d->updateState(d->state);
5313 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5314 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5315 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5316 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5321 if (d->state->matrix.type() <= QTransform::TxScale) {
5322 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5327 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5334 scale(w / sw, h / sh);
5335 setBackgroundMode(Qt::TransparentMode);
5336 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5337 QBrush brush(image);
5340 setBrushOrigin(QPointF(-sx, -sy));
5342 drawRect(QRectF(0, 0, sw, sh));
5347 if (d->state->matrix.type() == QTransform::TxTranslate
5348 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5349 x += d->state->matrix.dx();
5350 y += d->state->matrix.dy();
5353 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5368void QPainter::drawGlyphRun(
const QPointF &position,
const QGlyphRun &glyphRun)
5373 qWarning(
"QPainter::drawGlyphRun: Painter not active");
5377 QRawFont font = glyphRun.rawFont();
5378 if (!font.isValid())
5381 QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5383 const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5384 const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5386 int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5387 QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5389 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
5390 bool engineRequiresPretransformedGlyphPositions = d->extended
5391 ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5392 : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5394 for (
int i=0; i<count; ++i) {
5395 QPointF processedPosition = position + glyphPositions[i];
5396 if (engineRequiresPretransformedGlyphPositions)
5397 processedPosition = d->state->transform().map(processedPosition);
5398 fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5401 d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5402 ? d->state->transform().map(position)
5405 fixedPointPositions.data(),
5408 glyphRun.overline(),
5409 glyphRun.underline(),
5410 glyphRun.strikeOut());
5414 const quint32 *glyphArray,
5426 if (extended !=
nullptr && state->matrix.isAffine()) {
5427 QStaticTextItem staticTextItem;
5428 staticTextItem.color = state->pen.color();
5429 staticTextItem.font = state->font;
5430 staticTextItem.setFontEngine(fontEngine);
5431 staticTextItem.numGlyphs = glyphCount;
5432 staticTextItem.glyphs =
reinterpret_cast<glyph_t *>(
const_cast<glyph_t *>(glyphArray));
5433 staticTextItem.glyphPositions = positions;
5435 staticTextItem.usesRawFont =
true;
5437 extended->drawStaticTextItem(&staticTextItem);
5440 textItem.fontEngine = fontEngine;
5442 QVarLengthArray<QFixed, 128> advances(glyphCount);
5443 QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5444 QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5445 memset(glyphAttributes.data(), 0, glyphAttributes.size() *
sizeof(QGlyphAttributes));
5446 memset(
static_cast<
void *>(advances.data()), 0, advances.size() *
sizeof(QFixed));
5447 memset(
static_cast<
void *>(glyphJustifications.data()), 0, glyphJustifications.size() *
sizeof(QGlyphJustification));
5449 textItem.glyphs.numGlyphs = glyphCount;
5450 textItem.glyphs.glyphs =
const_cast<glyph_t *>(glyphArray);
5451 textItem.glyphs.offsets = positions;
5452 textItem.glyphs.advances = advances.data();
5453 textItem.glyphs.justifications = glyphJustifications.data();
5454 textItem.glyphs.attributes = glyphAttributes.data();
5456 engine->drawTextItem(QPointF(0, 0), textItem);
5459 qt_draw_decoration_for_glyphs(q,
5538void QPainter::drawStaticText(
const QPointF &topLeftPosition,
const QStaticText &staticText)
5541 if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5544 QStaticTextPrivate *staticText_d =
5545 const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5547 QFontPrivate *fp = QFontPrivate::get(font());
5548 QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5549 if (font() != staticText_d->font || fp ==
nullptr || stfp ==
nullptr || fp->dpi != stfp->dpi) {
5550 staticText_d->font = font();
5551 staticText_d->needsRelayout =
true;
5552 }
else if (stfp->engineData ==
nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5553 staticText_d->needsRelayout =
true;
5556 QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5557 if (fe->type() == QFontEngine::Multi)
5558 fe =
static_cast<QFontEngineMulti *>(fe)->engine(0);
5563 if (d->extended ==
nullptr
5564 || !d->state->matrix.isAffine()
5565 || !fe->supportsTransformation(d->state->matrix)) {
5566 staticText_d->paintText(topLeftPosition,
this, pen().color());
5570 bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5571 if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5574 staticText_d->untransformedCoordinates =
false;
5575 staticText_d->needsRelayout =
true;
5576 }
else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5579 staticText_d->untransformedCoordinates =
true;
5580 staticText_d->needsRelayout =
true;
5585 QPointF transformedPosition = topLeftPosition;
5586 if (!staticText_d->untransformedCoordinates)
5587 transformedPosition = transformedPosition * d->state->matrix;
5588 QTransform oldMatrix;
5592 if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5593 qreal m11 = d->state->matrix.m11();
5594 qreal m12 = d->state->matrix.m12();
5595 qreal m13 = d->state->matrix.m13();
5596 qreal m21 = d->state->matrix.m21();
5597 qreal m22 = d->state->matrix.m22();
5598 qreal m23 = d->state->matrix.m23();
5599 qreal m33 = d->state->matrix.m33();
5601 oldMatrix = d->state->matrix;
5602 d->state->matrix.setMatrix(m11, m12, m13,
5609 bool staticTextNeedsReinit = staticText_d->needsRelayout;
5610 if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5611 staticText_d->matrix = d->state->matrix;
5612 staticTextNeedsReinit =
true;
5616 if (staticTextNeedsReinit)
5617 staticText_d->init();
5619 if (transformedPosition != staticText_d->position) {
5620 QFixed fx = QFixed::fromReal(transformedPosition.x());
5621 QFixed fy = QFixed::fromReal(transformedPosition.y());
5622 QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5623 QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5624 for (
int item=0; item<staticText_d->itemCount;++item) {
5625 QStaticTextItem *textItem = staticText_d->items + item;
5626 for (
int i=0; i<textItem->numGlyphs; ++i) {
5627 textItem->glyphPositions[i].x += fx - oldX;
5628 textItem->glyphPositions[i].y += fy - oldY;
5630 textItem->userDataNeedsUpdate =
true;
5633 staticText_d->position = transformedPosition;
5636 QPen oldPen = d->state->pen;
5637 QColor currentColor = oldPen.color();
5638 static const QColor bodyIndicator(0, 0, 0, 0);
5639 for (
int i=0; i<staticText_d->itemCount; ++i) {
5640 QStaticTextItem *item = staticText_d->items + i;
5641 if (item->color.isValid() && currentColor != item->color
5642 && item->color != bodyIndicator) {
5643 setPen(item->color);
5644 currentColor = item->color;
5645 }
else if (item->color == bodyIndicator) {
5647 currentColor = oldPen.color();
5649 d->extended->drawStaticTextItem(item);
5651 qt_draw_decoration_for_glyphs(
this,
5654 item->glyphPositions,
5657 staticText_d->font.underline(),
5658 staticText_d->font.overline(),
5659 staticText_d->font.strikeOut());
5661 if (currentColor != oldPen.color())
5664 if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5665 d->state->matrix = oldMatrix;
5671void QPainter::drawText(
const QPointF &p,
const QString &str,
int tf,
int justificationPadding)
5674 if constexpr (qt_show_painter_debug_output)
5675 printf(
"QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5680 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5683 Q_DECL_UNINITIALIZED QStackTextEngine engine(str, d->state->font);
5684 engine.option.setTextDirection(d->state->layoutDirection);
5685 if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
5686 engine.ignoreBidi =
true;
5687 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5691 line.length = str.size();
5692 engine.shapeLine(line);
5694 int nItems = engine.layoutData->items.size();
5695 QVarLengthArray<
int> visualOrder(nItems);
5696 QVarLengthArray<uchar> levels(nItems);
5697 for (
int i = 0; i < nItems; ++i)
5698 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5699 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5701 if (justificationPadding > 0) {
5702 engine.option.setAlignment(Qt::AlignJustify);
5703 engine.forceJustification =
true;
5705 line.width = justificationPadding;
5706 engine.justify(line);
5708 QFixed x = QFixed::fromReal(p.x());
5710 for (
int i = 0; i < nItems; ++i) {
5711 int item = visualOrder[i];
5712 const QScriptItem &si = engine.layoutData->items.at(item);
5713 if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
5717 QFont f = engine.font(si);
5718 QTextItemInt gf(si, &f);
5719 gf.glyphs = engine.shapedGlyphs(&si);
5720 gf.chars = engine.layoutData->string.unicode() + si.position;
5721 gf.num_chars = engine.length(item);
5722 if (engine.forceJustification) {
5723 for (
int j=0; j<gf.glyphs.numGlyphs; ++j)
5724 gf.width += gf.glyphs.effectiveAdvance(j);
5726 gf.width = si.width;
5728 gf.logClusters = engine.logClusters(&si);
5730 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5998 const qreal radiusBase = qMax(qreal(1), maxRadius);
6000 QString key =
"WaveUnderline-"_L1
6001 % pen.color().name()
6002 % HexString<qreal>(radiusBase)
6003 % HexString<qreal>(pen.widthF());
6006 if (QPixmapCache::find(key, &pixmap))
6009 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399));
6010 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
6011 const qreal radius = qFloor(radiusBase * 2) / 2.;
6018 while (xs < width) {
6021 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
6024 pixmap = QPixmap(width, radius * 2);
6025 pixmap.fill(Qt::transparent);
6028 wavePen.setCapStyle(Qt::SquareCap);
6032 const qreal maxPenWidth = .8 * radius;
6033 if (wavePen.widthF() > maxPenWidth)
6034 wavePen.setWidthF(maxPenWidth);
6037 imgPainter.setPen(wavePen);
6038 imgPainter.setRenderHint(QPainter::Antialiasing);
6039 imgPainter.translate(0, radius);
6040 imgPainter.drawPath(path);
6043 QPixmapCache::insert(key, pixmap);
6049 QTextCharFormat::UnderlineStyle underlineStyle,
6050 QTextItem::RenderFlags flags, qreal width,
6051 const QTextCharFormat &charFormat)
6053 if (underlineStyle == QTextCharFormat::NoUnderline
6054 && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
6057 const QPen oldPen = painter->pen();
6058 const QBrush oldBrush = painter->brush();
6059 painter->setBrush(Qt::NoBrush);
6061 pen.setStyle(Qt::SolidLine);
6062 pen.setWidthF(fe->lineThickness().toReal());
6063 pen.setCapStyle(Qt::FlatCap);
6065 QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
6067 const qreal underlineOffset = fe->underlinePosition().toReal();
6069 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
6070 QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
6072 underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt());
6073 if (underlineStyle == QTextCharFormat::SpellCheckUnderline)
6074 underlineStyle = QTextCharFormat::WaveUnderline;
6077 if (underlineStyle == QTextCharFormat::WaveUnderline) {
6079 painter->translate(0, pos.y() + 1);
6080 qreal maxHeight = fe->descent().toReal() - qreal(1);
6082 QColor uc = charFormat.underlineColor();
6087 const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
6088 const int descent = qFloor(maxHeight);
6090 painter->setBrushOrigin(painter->brushOrigin().x(), 0);
6091 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
6093 }
else if (underlineStyle != QTextCharFormat::NoUnderline) {
6094 const bool isAntialiasing = painter->renderHints().testFlag(QPainter::Antialiasing);
6095 if (!isAntialiasing)
6096 pen.setWidthF(qMax(fe->lineThickness().round(), QFixed(1)).toReal());
6097 const qreal lineThicknessOffset = pen.widthF() / 2.0;
6101 qreal adjustedUnderlineOffset =
std::ceil(underlineOffset) + lineThicknessOffset;
6102 if (underlineOffset <= fe->descent().toReal())
6103 adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - lineThicknessOffset);
6104 const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6105 QColor uc = charFormat.underlineColor();
6109 pen.setStyle((Qt::PenStyle)(underlineStyle));
6110 painter->setPen(pen);
6111 QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6113 textEngine->addUnderline(painter, underline);
6115 painter->drawLine(underline);
6117 if (!isAntialiasing)
6118 pen.setWidthF(fe->lineThickness().toReal());
6121 pen.setStyle(Qt::SolidLine);
6122 pen.setColor(oldPen.color());
6124 if (flags & QTextItem::StrikeOut) {
6125 QLineF strikeOutLine = line;
6126 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6127 QColor uc = charFormat.underlineColor();
6130 painter->setPen(pen);
6132 textEngine->addStrikeOut(painter, strikeOutLine);
6134 painter->drawLine(strikeOutLine);
6137 if (flags & QTextItem::Overline) {
6138 QLineF overline = line;
6139 overline.translate(0., - fe->ascent().toReal());
6140 QColor uc = charFormat.underlineColor();
6143 painter->setPen(pen);
6145 textEngine->addOverline(painter, overline);
6147 painter->drawLine(overline);
6150 painter->setPen(oldPen);
6151 painter->setBrush(oldBrush);
6204 if constexpr (qt_show_painter_debug_output)
6205 printf(
"QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6206 p.x(), p.y(), qPrintable(_ti.text()));
6214 QTextItemInt &ti =
const_cast<QTextItemInt &>(
static_cast<
const QTextItemInt &>(_ti));
6216 if (!extended && state->bgMode == Qt::OpaqueMode) {
6217 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6218 q->fillRect(rect, state->bgBrush);
6221 if (q->pen().style() == Qt::NoPen)
6224 const QPainter::RenderHints oldRenderHints = state->renderHints;
6225 if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6230 const QTransform &m = state->matrix;
6231 if (state->matrix.type() < QTransform::TxShear) {
6232 bool isPlain90DegreeRotation =
6233 (qFuzzyIsNull(m.m11())
6234 && qFuzzyIsNull(m.m12() - qreal(1))
6235 && qFuzzyIsNull(m.m21() + qreal(1))
6236 && qFuzzyIsNull(m.m22())
6239 (qFuzzyIsNull(m.m11() + qreal(1))
6240 && qFuzzyIsNull(m.m12())
6241 && qFuzzyIsNull(m.m21())
6242 && qFuzzyIsNull(m.m22() + qreal(1))
6245 (qFuzzyIsNull(m.m11())
6246 && qFuzzyIsNull(m.m12() + qreal(1))
6247 && qFuzzyIsNull(m.m21() - qreal(1))
6248 && qFuzzyIsNull(m.m22())
6251 aa = !isPlain90DegreeRotation;
6254 q->setRenderHint(QPainter::Antialiasing,
true);
6260 if (!ti.glyphs.numGlyphs) {
6261 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6262 ti.flags, ti.width.toReal(), ti.charFormat);
6263 }
else if (ti.fontEngine->type() == QFontEngine::Multi) {
6264 QFontEngineMulti *multi =
static_cast<QFontEngineMulti *>(ti.fontEngine);
6267 int which = glyphs.glyphs[0] >> 24;
6272 bool rtl = ti.flags & QTextItem::RightToLeft;
6274 x += ti.width.toReal();
6278 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6279 const int e = glyphs.glyphs[end] >> 24;
6284 multi->ensureEngineAt(which);
6285 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6288 for (i = start; i < end; ++i) {
6289 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6290 ti2.width += ti.glyphs.effectiveAdvance(i);
6294 x -= ti2.width.toReal();
6299 engine->drawTextItem(QPointF(x, y), ti2);
6300 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6301 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6304 x += ti2.width.toReal();
6307 const int hi = which << 24;
6308 for (i = start; i < end; ++i) {
6309 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6317 multi->ensureEngineAt(which);
6318 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6321 for (i = start; i < end; ++i) {
6322 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6323 ti2.width += ti.glyphs.effectiveAdvance(i);
6327 x -= ti2.width.toReal();
6332 engine->drawTextItem(QPointF(x,y), ti2);
6333 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6334 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6337 const int hi = which << 24;
6338 for (i = start; i < end; ++i)
6339 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6345 engine->drawTextItem(p, ti);
6346 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6347 ti.flags, ti.width.toReal(), ti.charFormat);
6350 if (state->renderHints != oldRenderHints) {
6351 state->renderHints = oldRenderHints;
6355 state->dirtyFlags |= QPaintEngine::DirtyHints;
6482void QPainter::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sp)
6485 if constexpr (qt_show_painter_debug_output)
6486 printf(
"QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6487 r.x(), r.y(), r.width(), r.height(),
6488 pixmap.width(), pixmap.height(),
6493 if (!d->engine || pixmap.isNull() || r.isEmpty())
6497 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawTiledPixmap()");
6500 qreal sw = pixmap.width();
6501 qreal sh = pixmap.height();
6505 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6507 sx = qRound(sx) % qRound(sw);
6509 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6511 sy = qRound(sy) % qRound(sh);
6515 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6519 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6520 fillRect(r, d->state->bgBrush);
6522 d->updateState(d->state);
6523 if ((d->state->matrix.type() > QTransform::TxTranslate
6524 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6525 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6528 setBackgroundMode(Qt::TransparentMode);
6529 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
6530 setBrush(QBrush(d->state->pen.color(), pixmap));
6535 if (d->state->matrix.type() <= QTransform::TxScale) {
6536 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6538 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6543 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6544 drawRect(QRectF(p, r.size()));
6546 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6555 if (d->state->matrix.type() == QTransform::TxTranslate
6556 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6557 x += d->state->matrix.dx();
6558 y += d->state->matrix.dy();
6561 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
7182 const QTextOption *option,
7190 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=
nullptr) );
7192 if (_r.isEmpty() && !(tf & Qt::TextDontClip)) {
7196 tf |= Qt::TextDontPrint;
7200 alignment |= option->alignment();
7201 if (option->wrapMode() != QTextOption::NoWrap)
7202 tf |= Qt::TextWordWrap;
7204 if (option->flags() & QTextOption::IncludeTrailingSpaces)
7205 tf |= Qt::TextIncludeTrailingSpaces;
7207 if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7208 tf |= Qt::TextExpandTabs;
7214 bool dontclip = (tf & Qt::TextDontClip);
7215 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7216 bool singleline = (tf & Qt::TextSingleLine);
7217 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7218 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7220 Qt::LayoutDirection layout_direction;
7221 if (tf & Qt::TextForceLeftToRight)
7222 layout_direction = Qt::LeftToRight;
7223 else if (tf & Qt::TextForceRightToLeft)
7224 layout_direction = Qt::RightToLeft;
7226 layout_direction = option->textDirection();
7228 layout_direction = painter->layoutDirection();
7230 layout_direction = Qt::LeftToRight;
7232 alignment = QGuiApplicationPrivate::visualAlignment(layout_direction, QFlag(alignment));
7234 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7235 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7236 (((alignment & Qt::AlignLeft) && !isRightToLeft) ||
7237 ((alignment & Qt::AlignRight) && isRightToLeft)));
7240 tf |= Qt::TextDontPrint;
7242 uint maxUnderlines = 0;
7244 QFontMetricsF fm(fnt);
7248 bool hasMoreLengthVariants =
false;
7251 int old_offset = offset;
7252 for (; offset < text.size(); offset++) {
7253 QChar chr = text.at(offset);
7254 if (chr == u'\r' || (singleline && chr == u'\n')) {
7255 text[offset] = u' ';
7256 }
else if (chr == u'\n') {
7257 text[offset] = QChar::LineSeparator;
7258 }
else if (chr == u'&') {
7260 }
else if (chr == u'\t') {
7262 text[offset] = u' ';
7263 }
else if (!tabarraylen && !tabstops) {
7264 tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7266 }
else if (chr == u'\x9c') {
7268 hasMoreLengthVariants =
true;
7273 QList<QTextLayout::FormatRange> underlineFormats;
7274 int length = offset - old_offset;
7275 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7276 QChar *cout = text.data() + old_offset;
7277 QChar *cout0 = cout;
7287 if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7288 QTextLayout::FormatRange range;
7289 range.start = cout - cout0;
7291 range.format.setFontUnderline(
true);
7292 underlineFormats.append(range);
7295 }
else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7296 cin[1] == u'&' && cin[2] != u'&' &&
7299 while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7318 QString finalText = text.mid(old_offset, length);
7319 Q_DECL_UNINITIALIZED QStackTextEngine engine(finalText, fnt);
7321 engine.option = *option;
7324 if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7325 engine.option.setTabStopDistance(tabstops);
7327 if (engine.option.tabs().isEmpty() && ta) {
7329 tabs.reserve(tabarraylen);
7330 for (
int i = 0; i < tabarraylen; i++)
7331 tabs.append(qreal(ta[i]));
7332 engine.option.setTabArray(tabs);
7335 engine.option.setTextDirection(layout_direction);
7336 if (alignment & Qt::AlignJustify)
7337 engine.option.setAlignment(Qt::AlignJustify);
7339 engine.option.setAlignment(Qt::AlignLeft);
7341 if (!option && (tf & Qt::TextWrapAnywhere))
7342 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7344 if (tf & Qt::TextJustificationForced)
7345 engine.forceJustification =
true;
7347 textLayout.setCacheEnabled(
true);
7348 textLayout.setFormats(underlineFormats);
7350 if (finalText.isEmpty()) {
7351 height = fm.height();
7353 tf |= Qt::TextDontPrint;
7355 qreal lineWidth = 0x01000000;
7356 if (wordwrap || (tf & Qt::TextJustificationForced))
7357 lineWidth = qMax<qreal>(0, r.width());
7359 tf |= Qt::TextIncludeTrailingSpaces;
7360 textLayout.beginLayout();
7362 qreal leading = fm.leading();
7366 QTextLine l = textLayout.createLine();
7370 l.setLineWidth(lineWidth);
7374 height = qCeil(height);
7376 if (alignment & Qt::AlignBaseline && l.lineNumber() == 0)
7377 height -= l.ascent();
7379 l.setPosition(
QPointF(0., height));
7380 height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7381 width = qMax(width, l.naturalTextWidth());
7382 if (!dontclip && !brect && height >= r.height())
7385 textLayout.endLayout();
7390 if (alignment & Qt::AlignBottom)
7391 yoff = r.height() - height;
7392 else if (alignment & Qt::AlignVCenter)
7393 yoff = (r.height() - height)/2;
7395 if (alignment & Qt::AlignRight)
7396 xoff = r.width() - width;
7397 else if (alignment & Qt::AlignHCenter)
7398 xoff = (r.width() - width)/2;
7400 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7402 if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7404 goto start_lengthVariant;
7409 if (!(tf & Qt::TextDontPrint)) {
7410 bool restore =
false;
7411 if (!dontclip && !r.contains(bounds)) {
7414 painter->setClipRect(r, Qt::IntersectClip);
7417 for (
int i = 0; i < textLayout.lineCount(); i++) {
7418 QTextLine line = textLayout.lineAt(i);
7420 eng->enableDelayDecorations();
7422 qreal advance = line.horizontalAdvance();
7424 if (alignment & Qt::AlignRight) {
7425 xoff = r.width() - advance -
7426 eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7427 }
else if (alignment & Qt::AlignHCenter) {
7428 xoff = (r.width() - advance) / 2;
7431 line.draw(painter,
QPointF(r.x() + xoff, r.y() + yoff));
7432 eng->drawDecorations(painter);
7510QPainterState::QPainterState(
const QPainterState *s)
7511 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7512 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7513 clipRegion(s->clipRegion), clipPath(s->clipPath),
7514 clipOperation(s->clipOperation),
7515 renderHints(s->renderHints), clipInfo(s->clipInfo),
7516 worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7517 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7518 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7519 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7520 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7521 layoutDirection(s->layoutDirection),
7522 composition_mode(s->composition_mode),
7523 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7525 dirtyFlags = s->dirtyFlags;
8146void QPainter::drawPixmapFragments(
const PixmapFragment *fragments,
int fragmentCount,
8147 const QPixmap &pixmap, PixmapFragmentHints hints)
8151 if (!d->engine || pixmap.isNull())
8155 for (
int i = 0; i < fragmentCount; ++i) {
8156 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8157 fragments[i].width, fragments[i].height);
8158 if (!(QRectF(pixmap.rect()).contains(sourceRect)))
8159 qWarning(
"QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
8163 if (d->engine->isExtended()) {
8164 d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8166 qreal oldOpacity = opacity();
8167 QTransform oldTransform = transform();
8169 for (
int i = 0; i < fragmentCount; ++i) {
8170 QTransform transform = oldTransform;
8173 if (fragments[i].rotation == 0) {
8174 xOffset = fragments[i].x;
8175 yOffset = fragments[i].y;
8177 transform.translate(fragments[i].x, fragments[i].y);
8178 transform.rotate(fragments[i].rotation);
8180 setOpacity(oldOpacity * fragments[i].opacity);
8181 setTransform(transform);
8183 qreal w = fragments[i].scaleX * fragments[i].width;
8184 qreal h = fragments[i].scaleY * fragments[i].height;
8185 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8186 fragments[i].width, fragments[i].height);
8187 drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8190 setOpacity(oldOpacity);
8191 setTransform(oldTransform);