242 QPainter *sp = pdev->sharedPainter();
249 ++sp->d_ptr->refcount;
250 sp->d_ptr->d_ptrs.push_back(q->d_ptr.get());
251 Q_UNUSED(q->d_ptr.release());
252 q->d_ptr.reset(sp->d_ptr.get());
254 Q_ASSERT(q->d_ptr->state);
257 q->d_ptr->initFrom(pdev);
259 pdev->redirected(&offset);
260 offset += q->d_ptr->engine->coordinateOffset();
263 q->d_ptr->state->ww = q->d_ptr->state->vw = pdev->width();
264 q->d_ptr->state->wh = q->d_ptr->state->vh = pdev->height();
267 if (q->d_ptr->state->WxF) {
268 q->d_ptr->state->redirectionMatrix = q->d_ptr->state->matrix;
269 q->d_ptr->state->redirectionMatrix *= q->d_ptr->hidpiScaleTransform().inverted();
270 q->d_ptr->state->redirectionMatrix.translate(-offset.x(), -offset.y());
271 q->d_ptr->state->worldMatrix = QTransform();
272 q->d_ptr->state->WxF =
false;
274 q->d_ptr->state->redirectionMatrix = QTransform::fromTranslate(-offset.x(), -offset.y());
276 q->d_ptr->updateMatrix();
278 QPaintEnginePrivate *enginePrivate = q->d_ptr->engine->d_func();
279 if (enginePrivate->currentClipDevice == pdev) {
280 enginePrivate->systemStateChanged();
285 enginePrivate->currentClipDevice = pdev;
286 enginePrivate->setSystemTransform(q->d_ptr->state->matrix);
320 if (qt_show_painter_debug_output) {
321 printf(
"QPainter::drawHelper\n");
325 if (originalPath.isEmpty())
328 QPaintEngine::PaintEngineFeatures gradientStretch =
330 | QPaintEngine::ObjectBoundingModeGradients);
332 const bool mustEmulateObjectBoundingModeGradients = extended
333 || ((state->emulationSpecifier & QPaintEngine::ObjectBoundingModeGradients)
334 && !engine->hasFeature(QPaintEngine::PatternTransform));
336 if (!(state->emulationSpecifier & ~gradientStretch)
337 && !mustEmulateObjectBoundingModeGradients) {
347 qreal strokeOffsetX = 0, strokeOffsetY = 0;
349 QPainterPath path = originalPath * state->matrix;
350 QRectF pathBounds = path.boundingRect();
352 bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen);
354 qreal penWidth = state->pen.widthF();
360 if (state->matrix.type() > QTransform::TxScale) {
362 stroker.setWidth(penWidth);
363 stroker.setJoinStyle(state->pen.joinStyle());
364 stroker.setCapStyle(state->pen.capStyle());
365 QPainterPath stroke = stroker.createStroke(originalPath);
366 strokeBounds = (stroke * state->matrix).boundingRect();
368 strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0);
369 strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0);
375 if (!strokeBounds.isEmpty()) {
376 absPathRect = strokeBounds.intersected(QRectF(0, 0,
device->width(),
device->height())).toAlignedRect();
378 absPathRect = pathBounds.adjusted(-strokeOffsetX, -strokeOffsetY, strokeOffsetX, strokeOffsetY)
379 .intersected(QRectF(0, 0, device->width(), device->height())).toAlignedRect();
382 if (q->hasClipping()) {
383 bool hasPerspectiveTransform =
false;
384 for (
const QPainterClipInfo &info : std::as_const(state->clipInfo)) {
385 if (info.matrix.type() == QTransform::TxProject) {
386 hasPerspectiveTransform =
true;
391 if (!hasPerspectiveTransform) {
398 bool old_txinv =
txinv;
399 QTransform old_invMatrix = invMatrix;
401 invMatrix = QTransform();
402 QPainterPath clipPath = q->clipPath();
403 QRectF r = clipPath.boundingRect().intersected(absPathRect);
404 absPathRect = r.toAlignedRect();
406 invMatrix = old_invMatrix;
416 if (absPathRect.width() <= 0 || absPathRect.height() <= 0)
419 QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied);
426 p.setOpacity(state->opacity);
427 p.translate(-absPathRect.x(), -absPathRect.y());
428 p.setTransform(state->matrix,
true);
429 p.setPen(doStroke ? state->pen : QPen(Qt::NoPen));
430 p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush));
431 p.setBackground(state->bgBrush);
432 p.setBackgroundMode(state->bgMode);
433 p.setBrushOrigin(state->brushOrigin);
435 p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing);
436 p.setRenderHint(QPainter::SmoothPixmapTransform,
437 state->renderHints & QPainter::SmoothPixmapTransform);
439 p.drawPath(originalPath);
442 static bool do_fallback_overlay = !qEnvironmentVariableIsEmpty(
"QT_PAINT_FALLBACK_OVERLAY");
443 if (do_fallback_overlay) {
444 QImage block(8, 8, QImage::Format_ARGB32_Premultiplied);
446 pt.fillRect(0, 0, 8, 8, QColor(196, 0, 196));
447 pt.drawLine(0, 0, 8, 8);
450 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
452 p.fillRect(0, 0, image.width(), image.height(), QBrush(block));
459 state->matrix = QTransform();
463 state->dirtyFlags |= QPaintEngine::DirtyTransform;
466 engine->drawImage(absPathRect,
468 QRectF(0, 0, absPathRect.width(), absPathRect.height()),
469 Qt::OrderedDither | Qt::OrderedAlphaDither);
518 bool changedPen =
false;
519 bool changedBrush =
false;
520 bool needsFill =
false;
522 const QPen pen = state->pen;
523 const QBrush brush = state->brush;
525 const QGradient::CoordinateMode penMode = coordinateMode(pen.brush());
526 const QGradient::CoordinateMode brushMode = coordinateMode(brush);
531 if ((op & FillDraw) && brush.style() != Qt::NoBrush) {
532 if (brushMode == QGradient::StretchToDeviceMode) {
533 q->setPen(Qt::NoPen);
534 changedPen = pen.style() != Qt::NoPen;
538 const qreal isw = 1.0 / sw;
539 const qreal ish = 1.0 / sh;
540 QTransform inv(isw, 0, 0, ish, 0, 0);
541 engine->drawPath(path * inv);
546 if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
547 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
548 boundingRect = path.boundingRect();
549 q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
555 if ((op & StrokeDraw) && pen.style() != Qt::NoPen) {
557 if (penMode == QGradient::StretchToDeviceMode) {
558 q->setPen(Qt::NoPen);
563 engine->drawPath(path);
567 q->setBrush(pen.brush());
572 stroker.setDashPattern(pen.style());
573 stroker.setWidth(pen.widthF());
574 stroker.setJoinStyle(pen.joinStyle());
575 stroker.setCapStyle(pen.capStyle());
576 stroker.setMiterLimit(pen.miterLimit());
577 QPainterPath stroke = stroker.createStroke(path);
579 const qreal isw = 1.0 / sw;
580 const qreal ish = 1.0 / sh;
581 QTransform inv(isw, 0, 0, ish, 0, 0);
582 engine->drawPath(stroke * inv);
585 if (!needsFill && brush.style() != Qt::NoBrush) {
586 q->setBrush(Qt::NoBrush);
590 if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
591 Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
594 if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
595 boundingRect = path.boundingRect();
598 p.setBrush(stretchGradientToUserSpace(pen.brush(), boundingRect));
601 }
else if (changedPen) {
607 engine->drawPath(path);
609 }
else if (needsFill) {
610 if (pen.style() != Qt::NoPen) {
611 q->setPen(Qt::NoPen);
616 engine->drawPath(path);
658 bool linearGradient =
false;
659 bool radialGradient =
false;
660 bool extendedRadialGradient =
false;
661 bool conicalGradient =
false;
662 bool patternBrush =
false;
664 bool complexXform =
false;
670 if (s->state() & (QPaintEngine::DirtyPen | QPaintEngine::DirtyBrush | QPaintEngine::DirtyHints)) {
672 if (!s->pen.isSolid() && !engine->hasFeature(QPaintEngine::BrushStroke))
673 s->emulationSpecifier |= QPaintEngine::BrushStroke;
675 s->emulationSpecifier &= ~QPaintEngine::BrushStroke;
679 QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
680 Qt::BrushStyle brushStyle = qbrush_style(s->brush);
681 Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
682 alpha = (penBrushStyle != Qt::NoBrush
683 && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
684 && !penBrush.isOpaque())
685 || (brushStyle != Qt::NoBrush
686 && (brushStyle < Qt::LinearGradientPattern && s->brush.color().alpha() != 255)
687 && !s->brush.isOpaque());
688 linearGradient = ((penBrushStyle == Qt::LinearGradientPattern) ||
689 (brushStyle == Qt::LinearGradientPattern));
690 radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
691 (brushStyle == Qt::RadialGradientPattern));
692 extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
693 conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
694 (brushStyle == Qt::ConicalGradientPattern));
695 patternBrush = (((penBrushStyle > Qt::SolidPattern
696 && penBrushStyle < Qt::LinearGradientPattern)
697 || penBrushStyle == Qt::TexturePattern) ||
698 ((brushStyle > Qt::SolidPattern
699 && brushStyle < Qt::LinearGradientPattern)
700 || brushStyle == Qt::TexturePattern));
702 bool penTextureAlpha =
false;
703 if (penBrush.style() == Qt::TexturePattern)
704 penTextureAlpha = qHasPixmapTexture(penBrush)
705 ? (penBrush.texture().depth() > 1) && penBrush.texture().hasAlpha()
706 : penBrush.textureImage().hasAlphaChannel();
707 bool brushTextureAlpha =
false;
708 if (s->brush.style() == Qt::TexturePattern) {
709 brushTextureAlpha = qHasPixmapTexture(s->brush)
710 ? (s->brush.texture().depth() > 1) && s->brush.texture().hasAlpha()
711 : s->brush.textureImage().hasAlphaChannel();
713 if (((penBrush.style() == Qt::TexturePattern && penTextureAlpha)
714 || (s->brush.style() == Qt::TexturePattern && brushTextureAlpha))
715 && !engine->hasFeature(QPaintEngine::MaskedBrush))
716 s->emulationSpecifier |= QPaintEngine::MaskedBrush;
718 s->emulationSpecifier &= ~QPaintEngine::MaskedBrush;
721 if (s->state() & (QPaintEngine::DirtyHints
722 | QPaintEngine::DirtyOpacity
723 | QPaintEngine::DirtyBackgroundMode)) {
731 qDebug(
"QPainterPrivate::updateEmulationSpecifier, state=%p\n"
733 " - linearGradient: %d\n"
734 " - radialGradient: %d\n"
735 " - conicalGradient: %d\n"
736 " - patternBrush: %d\n"
745 uint(s->renderHints),
750 if (s->state() & QPaintEngine::DirtyTransform) {
751 xform = !s->matrix.isIdentity();
752 complexXform = !s->matrix.isAffine();
753 }
else if (s->matrix.type() >= QTransform::TxTranslate) {
755 complexXform = !s->matrix.isAffine();
758 const bool brushXform = (s->brush.transform().type() != QTransform::TxNone);
759 const bool penXform = (s->pen.brush().transform().type() != QTransform::TxNone);
761 const bool patternXform = patternBrush && (xform || brushXform || penXform);
764 if (alpha && !engine->hasFeature(QPaintEngine::AlphaBlend))
765 s->emulationSpecifier |= QPaintEngine::AlphaBlend;
767 s->emulationSpecifier &= ~QPaintEngine::AlphaBlend;
770 if (linearGradient && !engine->hasFeature(QPaintEngine::LinearGradientFill))
771 s->emulationSpecifier |= QPaintEngine::LinearGradientFill;
773 s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
776 if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
777 s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
779 s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
782 if (conicalGradient && !engine->hasFeature(QPaintEngine::ConicalGradientFill))
783 s->emulationSpecifier |= QPaintEngine::ConicalGradientFill;
785 s->emulationSpecifier &= ~QPaintEngine::ConicalGradientFill;
788 if (patternBrush && !engine->hasFeature(QPaintEngine::PatternBrush))
789 s->emulationSpecifier |= QPaintEngine::PatternBrush;
791 s->emulationSpecifier &= ~QPaintEngine::PatternBrush;
794 if (patternXform && !engine->hasFeature(QPaintEngine::PatternTransform))
795 s->emulationSpecifier |= QPaintEngine::PatternTransform;
797 s->emulationSpecifier &= ~QPaintEngine::PatternTransform;
800 if (xform && !engine->hasFeature(QPaintEngine::PrimitiveTransform))
801 s->emulationSpecifier |= QPaintEngine::PrimitiveTransform;
803 s->emulationSpecifier &= ~QPaintEngine::PrimitiveTransform;
806 if (complexXform && !engine->hasFeature(QPaintEngine::PerspectiveTransform))
807 s->emulationSpecifier |= QPaintEngine::PerspectiveTransform;
809 s->emulationSpecifier &= ~QPaintEngine::PerspectiveTransform;
812 if (state->opacity != 1 && !engine->hasFeature(QPaintEngine::ConstantOpacity))
813 s->emulationSpecifier |= QPaintEngine::ConstantOpacity;
815 s->emulationSpecifier &= ~QPaintEngine::ConstantOpacity;
817 bool gradientStretch =
false;
818 bool objectBoundingMode =
false;
819 if (linearGradient || conicalGradient || radialGradient) {
820 QGradient::CoordinateMode brushMode = coordinateMode(s->brush);
821 QGradient::CoordinateMode penMode = coordinateMode(s->pen.brush());
823 gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
824 gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
826 objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
827 objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
834 if (objectBoundingMode && !engine->hasFeature(QPaintEngine::ObjectBoundingModeGradients))
835 s->emulationSpecifier |= QPaintEngine::ObjectBoundingModeGradients;
837 s->emulationSpecifier &= ~QPaintEngine::ObjectBoundingModeGradients;
840 if (s->bgMode == Qt::OpaqueMode &&
841 (is_pen_transparent(s->pen) || is_brush_transparent(s->brush)))
852 if (state->composition_mode > QPainter::CompositionMode_Xor &&
853 !engine->hasFeature(QPaintEngine::BlendModes))
854 s->emulationSpecifier |= QPaintEngine::BlendModes;
856 s->emulationSpecifier &= ~QPaintEngine::BlendModes;
1580void QPainter::restore()
1583 if (qt_show_painter_debug_output)
1584 printf(
"QPainter::restore()\n");
1587 if (d->savedStates.empty()) {
1588 qWarning(
"QPainter::restore: Unbalanced save/restore");
1590 }
else if (!d->engine) {
1591 qWarning(
"QPainter::restore: Painter not active");
1595 const auto tmp = std::exchange(d->state, std::move(d->savedStates.top()));
1596 d->savedStates.pop();
1600 d->checkEmulation();
1601 d->extended->setState(d->state.get());
1607 if (!d->state->clipInfo.isEmpty()
1608 && (tmp->changeFlags & (QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipPath))) {
1610 tmp->dirtyFlags = QPaintEngine::DirtyClipPath;
1611 tmp->clipOperation = Qt::NoClip;
1612 tmp->clipPath = QPainterPath();
1613 d->engine->updateState(*tmp);
1615 for (
const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
1616 tmp->matrix = info.matrix;
1617 tmp->clipOperation = info.operation;
1618 if (info.clipType == QPainterClipInfo::RectClip) {
1619 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1620 tmp->clipRegion = info.rect;
1621 }
else if (info.clipType == QPainterClipInfo::RegionClip) {
1622 tmp->dirtyFlags = QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyTransform;
1623 tmp->clipRegion = info.region;
1625 tmp->dirtyFlags = QPaintEngine::DirtyClipPath | QPaintEngine::DirtyTransform;
1626 tmp->clipPath = info.path;
1628 d->engine->updateState(*tmp);
1633 d->state->dirtyFlags &= ~(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1634 tmp->changeFlags &= ~uint(QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipRegion);
1635 tmp->changeFlags |= QPaintEngine::DirtyTransform;
1638 d->updateState(d->state.get());
1677bool QPainter::begin(QPaintDevice *pd)
1681 if (pd->painters > 0) {
1682 qWarning(
"QPainter::begin: A paint device can only be painted by one painter at a time.");
1686 if (d_ptr->engine) {
1687 qWarning(
"QPainter::begin: Painter already active");
1691 if (QPainterPrivate::attachPainterPrivate(
this, pd))
1696 d->helper_device = pd;
1697 d->original_device = pd;
1699 QPoint redirectionOffset;
1700 QPaintDevice *rpd = pd->redirected(&redirectionOffset);
1705 if (qt_show_painter_debug_output)
1706 printf(
"QPainter::begin(), device=%p, type=%d\n", pd, pd->devType());
1709 if (pd->devType() == QInternal::Pixmap)
1710 static_cast<QPixmap *>(pd)->detach();
1711 else if (pd->devType() == QInternal::Image)
1712 static_cast<QImage *>(pd)->detach();
1714 d->engine.reset(pd->paintEngine());
1717 qWarning(
"QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
1723 d->extended = d->engine->isExtended() ?
static_cast<QPaintEngineEx *>(d->engine.get()) :
nullptr;
1724 if (d->emulationEngine)
1725 d->emulationEngine->real_engine = d->extended;
1728 Q_ASSERT(!d->state);
1729 d->state.reset(d->extended ? d->extended->createState(
nullptr) :
new QPainterState);
1730 d->state->painter =
this;
1732 d->state->redirectionMatrix.translate(-redirectionOffset.x(), -redirectionOffset.y());
1733 d->state->brushOrigin = QPointF();
1737 d->extended->setState(d->state.get());
1739 d->engine->state = d->state.get();
1741 switch (pd->devType()) {
1742 case QInternal::Pixmap:
1744 QPixmap *pm =
static_cast<QPixmap *>(pd);
1747 qWarning(
"QPainter::begin: Cannot paint on a null pixmap");
1748 qt_cleanup_painter_state(d);
1752 if (pm->depth() == 1) {
1753 d->state->pen = QPen(Qt::color1);
1754 d->state->brush = QBrush(Qt::color0);
1758 case QInternal::Image:
1760 QImage *img =
static_cast<QImage *>(pd);
1762 if (img->isNull()) {
1763 qWarning(
"QPainter::begin: Cannot paint on a null image");
1764 qt_cleanup_painter_state(d);
1766 }
else if (img->format() == QImage::Format_Indexed8 ||
1767 img->format() == QImage::Format_CMYK8888) {
1769 qWarning() <<
"QPainter::begin: Cannot paint on an image with the"
1772 qt_cleanup_painter_state(d);
1775 if (img->depth() == 1) {
1776 d->state->pen = QPen(Qt::color1);
1777 d->state->brush = QBrush(Qt::color0);
1784 if (d->state->ww == 0)
1785 d->state->ww = d->state->wh = d->state->vw = d->state->vh = 1024;
1787 d->engine->setPaintDevice(pd);
1789 bool begun = d->engine->begin(pd);
1791 qWarning(
"QPainter::begin(): Returned false");
1792 if (d->engine->isActive()) {
1795 qt_cleanup_painter_state(d);
1799 d->engine->setActive(begun);
1804 if (d->original_device->devType() == QInternal::Widget) {
1805 d->initFrom(d->original_device);
1807 d->state->layoutDirection = Qt::LayoutDirectionAuto;
1809 d->state->deviceFont = d->state->font = QFont(d->state->deviceFont, device());
1812 QRect systemRect = d->engine->systemRect();
1813 if (!systemRect.isEmpty()) {
1814 d->state->ww = d->state->vw = systemRect.width();
1815 d->state->wh = d->state->vh = systemRect.height();
1817 d->state->ww = d->state->vw = pd->metric(QPaintDevice::PdmWidth);
1818 d->state->wh = d->state->vh = pd->metric(QPaintDevice::PdmHeight);
1821 const QPoint coordinateOffset = d->engine->coordinateOffset();
1822 d->state->redirectionMatrix.translate(-coordinateOffset.x(), -coordinateOffset.y());
1824 Q_ASSERT(d->engine->isActive());
1826 if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
1829 Q_ASSERT(d->engine->isActive());
1830 d->state->renderHints = QPainter::TextAntialiasing;
1831 ++d->device->painters;
1833 d->state->emulationSpecifier = 0;
2466QRegion QPainter::clipRegion()
const
2468 Q_D(
const QPainter);
2470 qWarning(
"QPainter::clipRegion: Painter not active");
2475 bool lastWasNothing =
true;
2478 const_cast<QPainter *>(
this)->d_ptr->updateInvMatrix();
2481 for (
const QPainterClipInfo &info : std::as_const(d->state->clipInfo)) {
2482 switch (info.clipType) {
2484 case QPainterClipInfo::RegionClip: {
2485 QTransform matrix = (info.matrix * d->invMatrix);
2486 if (lastWasNothing) {
2487 region = info.region * matrix;
2488 lastWasNothing =
false;
2491 if (info.operation == Qt::IntersectClip)
2492 region &= info.region * matrix;
2493 else if (info.operation == Qt::NoClip) {
2494 lastWasNothing =
true;
2497 region = info.region * matrix;
2501 case QPainterClipInfo::PathClip: {
2502 QTransform matrix = (info.matrix * d->invMatrix);
2503 if (lastWasNothing) {
2504 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2505 info.path.fillRule());
2506 lastWasNothing =
false;
2509 if (info.operation == Qt::IntersectClip) {
2510 region &= QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2511 info.path.fillRule());
2512 }
else if (info.operation == Qt::NoClip) {
2513 lastWasNothing =
true;
2516 region = QRegion((info.path * matrix).toFillPolygon().toPolygon(),
2517 info.path.fillRule());
2522 case QPainterClipInfo::RectClip: {
2523 QTransform matrix = (info.matrix * d->invMatrix);
2524 if (lastWasNothing) {
2525 region = QRegion(info.rect) * matrix;
2526 lastWasNothing =
false;
2529 if (info.operation == Qt::IntersectClip) {
2531 if (matrix.type() <= QTransform::TxScale)
2532 region &= matrix.mapRect(info.rect);
2534 region &= matrix.map(QRegion(info.rect));
2535 }
else if (info.operation == Qt::NoClip) {
2536 lastWasNothing =
true;
2539 region = QRegion(info.rect) * matrix;
2544 case QPainterClipInfo::RectFClip: {
2545 QTransform matrix = (info.matrix * d->invMatrix);
2546 if (lastWasNothing) {
2547 region = QRegion(info.rectf.toRect()) * matrix;
2548 lastWasNothing =
false;
2551 if (info.operation == Qt::IntersectClip) {
2553 if (matrix.type() <= QTransform::TxScale)
2554 region &= matrix.mapRect(info.rectf.toRect());
2556 region &= matrix.map(QRegion(info.rectf.toRect()));
2557 }
else if (info.operation == Qt::NoClip) {
2558 lastWasNothing =
true;
2561 region = QRegion(info.rectf.toRect()) * matrix;
2690void QPainter::setClipRect(
const QRectF &rect, Qt::ClipOperation op)
2696 qWarning(
"QPainter::setClipRect: Painter not active");
2699 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2700 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2701 op = Qt::ReplaceClip;
2703 qreal right = rect.x() + rect.width();
2704 qreal bottom = rect.y() + rect.height();
2705 qreal pts[] = { rect.x(), rect.y(),
2709 QVectorPath vp(pts, 4,
nullptr, QVectorPath::RectangleHint);
2710 d->state->clipEnabled =
true;
2711 d->extended->clip(vp, op);
2712 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2713 d->state->clipInfo.clear();
2714 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2715 d->state->clipOperation = op;
2719 if (qreal(
int(rect.top())) == rect.top()
2720 && qreal(
int(rect.bottom())) == rect.bottom()
2721 && qreal(
int(rect.left())) == rect.left()
2722 && qreal(
int(rect.right())) == rect.right())
2724 setClipRect(rect.toRect(), op);
2728 if (rect.isEmpty()) {
2729 setClipRegion(QRegion(), op);
2735 setClipPath(path, op);
2745void QPainter::setClipRect(
const QRect &rect, Qt::ClipOperation op)
2750 qWarning(
"QPainter::setClipRect: Painter not active");
2753 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2755 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2756 op = Qt::ReplaceClip;
2759 d->state->clipEnabled =
true;
2760 d->extended->clip(rect, op);
2761 if (op == Qt::ReplaceClip || op == Qt::NoClip)
2762 d->state->clipInfo.clear();
2763 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2764 d->state->clipOperation = op;
2768 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2769 op = Qt::ReplaceClip;
2771 d->state->clipRegion = rect;
2772 d->state->clipOperation = op;
2773 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2774 d->state->clipInfo.clear();
2775 d->state->clipInfo.append(QPainterClipInfo(rect, op, d->state->matrix));
2776 d->state->clipEnabled =
true;
2777 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2778 d->updateState(d->state);
2799void QPainter::setClipRegion(
const QRegion &r, Qt::ClipOperation op)
2803 QRect rect = r.boundingRect();
2804 if (qt_show_painter_debug_output)
2805 printf(
"QPainter::setClipRegion(), size=%d, [%d,%d,%d,%d]\n",
2806 r.rectCount(), rect.x(), rect.y(), rect.width(), rect.height());
2809 qWarning(
"QPainter::setClipRegion: Painter not active");
2812 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
2814 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
2815 op = Qt::ReplaceClip;
2818 d->state->clipEnabled =
true;
2819 d->extended->clip(r, op);
2820 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2821 d->state->clipInfo.clear();
2822 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2823 d->state->clipOperation = op;
2827 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
2828 op = Qt::ReplaceClip;
2830 d->state->clipRegion = r;
2831 d->state->clipOperation = op;
2832 if (op == Qt::NoClip || op == Qt::ReplaceClip)
2833 d->state->clipInfo.clear();
2834 d->state->clipInfo.append(QPainterClipInfo(r, op, d->state->matrix));
2835 d->state->clipEnabled =
true;
2836 d->state->dirtyFlags |= QPaintEngine::DirtyClipRegion | QPaintEngine::DirtyClipEnabled;
2837 d->updateState(d->state);
3011void QPainter::setClipPath(
const QPainterPath &path, Qt::ClipOperation op)
3014 if (qt_show_painter_debug_output) {
3015 QRectF b = path.boundingRect();
3016 printf(
"QPainter::setClipPath(), size=%d, op=%d, bounds=[%.2f,%.2f,%.2f,%.2f]\n",
3017 path.elementCount(), op, b.x(), b.y(), b.width(), b.height());
3023 qWarning(
"QPainter::setClipPath: Painter not active");
3027 bool simplifyClipOp = (paintEngine()->type() != QPaintEngine::Picture);
3028 if (simplifyClipOp && (!d->state->clipEnabled && op != Qt::NoClip))
3029 op = Qt::ReplaceClip;
3032 d->state->clipEnabled =
true;
3033 d->extended->clip(path, op);
3034 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3035 d->state->clipInfo.clear();
3036 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3037 d->state->clipOperation = op;
3041 if (simplifyClipOp && d->state->clipOperation == Qt::NoClip && op == Qt::IntersectClip)
3042 op = Qt::ReplaceClip;
3044 d->state->clipPath = path;
3045 d->state->clipOperation = op;
3046 if (op == Qt::NoClip || op == Qt::ReplaceClip)
3047 d->state->clipInfo.clear();
3048 d->state->clipInfo.append(QPainterClipInfo(path, op, d->state->matrix));
3049 d->state->clipEnabled =
true;
3050 d->state->dirtyFlags |= QPaintEngine::DirtyClipPath | QPaintEngine::DirtyClipEnabled;
3051 d->updateState(d->state);
3260void QPainter::drawRects(
const QRectF *rects,
int rectCount)
3263 if (qt_show_painter_debug_output)
3264 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3269 qWarning(
"QPainter::drawRects: Painter not active");
3277 d->extended->drawRects(rects, rectCount);
3281 d->updateState(d->state);
3283 if (!d->state->emulationSpecifier) {
3284 d->engine->drawRects(rects, rectCount);
3288 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3289 && d->state->matrix.type() == QTransform::TxTranslate) {
3290 for (
int i=0; i<rectCount; ++i) {
3291 QRectF r(rects[i].x() + d->state->matrix.dx(),
3292 rects[i].y() + d->state->matrix.dy(),
3295 d->engine->drawRects(&r, 1);
3298 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3299 for (
int i=0; i<rectCount; ++i) {
3300 QPainterPath rectPath;
3301 rectPath.addRect(rects[i]);
3302 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3305 QPainterPath rectPath;
3306 for (
int i=0; i<rectCount; ++i)
3307 rectPath.addRect(rects[i]);
3308 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3320void QPainter::drawRects(
const QRect *rects,
int rectCount)
3323 if (qt_show_painter_debug_output)
3324 printf(
"QPainter::drawRects(), count=%d\n", rectCount);
3329 qWarning(
"QPainter::drawRects: Painter not active");
3337 d->extended->drawRects(rects, rectCount);
3341 d->updateState(d->state);
3343 if (!d->state->emulationSpecifier) {
3344 d->engine->drawRects(rects, rectCount);
3348 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3349 && d->state->matrix.type() == QTransform::TxTranslate) {
3350 for (
int i=0; i<rectCount; ++i) {
3351 QRectF r(rects[i].x() + d->state->matrix.dx(),
3352 rects[i].y() + d->state->matrix.dy(),
3356 d->engine->drawRects(&r, 1);
3359 if (d->state->brushNeedsResolving() || d->state->penNeedsResolving()) {
3360 for (
int i=0; i<rectCount; ++i) {
3361 QPainterPath rectPath;
3362 rectPath.addRect(rects[i]);
3363 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3366 QPainterPath rectPath;
3367 for (
int i=0; i<rectCount; ++i)
3368 rectPath.addRect(rects[i]);
3370 d->draw_helper(rectPath, QPainterPrivate::StrokeAndFillDraw);
3420void QPainter::drawPoints(
const QPointF *points,
int pointCount)
3423 if (qt_show_painter_debug_output)
3424 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3429 qWarning(
"QPainter::drawPoints: Painter not active");
3433 if (pointCount <= 0)
3437 d->extended->drawPoints(points, pointCount);
3441 d->updateState(d->state);
3443 if (!d->state->emulationSpecifier) {
3444 d->engine->drawPoints(points, pointCount);
3448 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3449 && d->state->matrix.type() == QTransform::TxTranslate) {
3451 for (
int i=0; i<pointCount; ++i) {
3452 QPointF pt(points[i].x() + d->state->matrix.dx(),
3453 points[i].y() + d->state->matrix.dy());
3454 d->engine->drawPoints(&pt, 1);
3457 QPen pen = d->state->pen;
3458 bool flat_pen = pen.capStyle() == Qt::FlatCap;
3461 pen.setCapStyle(Qt::SquareCap);
3465 for (
int i=0; i<pointCount; ++i) {
3466 path.moveTo(points[i].x(), points[i].y());
3467 path.lineTo(points[i].x() + 0.0001, points[i].y());
3469 d->draw_helper(path, QPainterPrivate::StrokeDraw);
3482void QPainter::drawPoints(
const QPoint *points,
int pointCount)
3485 if (qt_show_painter_debug_output)
3486 printf(
"QPainter::drawPoints(), count=%d\n", pointCount);
3491 qWarning(
"QPainter::drawPoints: Painter not active");
3495 if (pointCount <= 0)
3499 d->extended->drawPoints(points, pointCount);
3503 d->updateState(d->state);
3505 if (!d->state->emulationSpecifier) {
3506 d->engine->drawPoints(points, pointCount);
3510 if (d->state->emulationSpecifier == QPaintEngine::PrimitiveTransform
3511 && d->state->matrix.type() == QTransform::TxTranslate) {
3513 for (
int i=0; i<pointCount; ++i) {
3514 QPointF pt(points[i].x() + d->state->matrix.dx(),
3515 points[i].y() + d->state->matrix.dy());
3516 d->engine->drawPoints(&pt, 1);
3519 QPen pen = d->state->pen;
3520 bool flat_pen = (pen.capStyle() == Qt::FlatCap);
3523 pen.setCapStyle(Qt::SquareCap);
3527 for (
int i=0; i<pointCount; ++i) {
3528 path.moveTo(points[i].x(), points[i].y());
3529 path.lineTo(points[i].x() + 0.0001, points[i].y());
3531 d->draw_helper(path, QPainterPrivate::StrokeDraw);
4307void QPainter::drawLines(
const QLineF *lines,
int lineCount)
4310 if (qt_show_painter_debug_output)
4311 printf(
"QPainter::drawLines(), line count=%d\n", lineCount);
4316 if (!d->engine || lineCount < 1)
4320 d->extended->drawLines(lines, lineCount);
4324 d->updateState(d->state);
4326 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4328 if (lineEmulation) {
4329 if (lineEmulation == QPaintEngine::PrimitiveTransform
4330 && d->state->matrix.type() == QTransform::TxTranslate) {
4331 for (
int i = 0; i < lineCount; ++i) {
4332 QLineF line = lines[i];
4333 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4334 d->engine->drawLines(&line, 1);
4337 QPainterPath linePath;
4338 for (
int i = 0; i < lineCount; ++i) {
4339 linePath.moveTo(lines[i].p1());
4340 linePath.lineTo(lines[i].p2());
4342 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4346 d->engine->drawLines(lines, lineCount);
4356void QPainter::drawLines(
const QLine *lines,
int lineCount)
4359 if (qt_show_painter_debug_output)
4360 printf(
"QPainter::drawLine(), line count=%d\n", lineCount);
4365 if (!d->engine || lineCount < 1)
4369 d->extended->drawLines(lines, lineCount);
4373 d->updateState(d->state);
4375 uint lineEmulation = line_emulation(d->state->emulationSpecifier);
4377 if (lineEmulation) {
4378 if (lineEmulation == QPaintEngine::PrimitiveTransform
4379 && d->state->matrix.type() == QTransform::TxTranslate) {
4380 for (
int i = 0; i < lineCount; ++i) {
4381 QLineF line = lines[i];
4382 line.translate(d->state->matrix.dx(), d->state->matrix.dy());
4383 d->engine->drawLines(&line, 1);
4386 QPainterPath linePath;
4387 for (
int i = 0; i < lineCount; ++i) {
4388 linePath.moveTo(lines[i].p1());
4389 linePath.lineTo(lines[i].p2());
4391 d->draw_helper(linePath, QPainterPrivate::StrokeDraw);
4395 d->engine->drawLines(lines, lineCount);
4827void QPainter::drawPixmap(
const QPointF &p,
const QPixmap &pm)
4829#if defined QT_DEBUG_DRAW
4830 if (qt_show_painter_debug_output)
4831 printf(
"QPainter::drawPixmap(), p=[%.2f,%.2f], pix=[%d,%d]\n",
4833 pm.width(), pm.height());
4838 if (!d->engine || pm.isNull())
4842 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4846 d->extended->drawPixmap(p, pm);
4854 int h = pm.height();
4860 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap()) {
4861 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4864 d->updateState(d->state);
4866 if ((d->state->matrix.type() > QTransform::TxTranslate
4867 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4868 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4869 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
4874 if (d->state->matrix.type() <= QTransform::TxScale) {
4875 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
4880 setBackgroundMode(Qt::TransparentMode);
4881 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
4882 QBrush brush(d->state->pen.color(), pm);
4885 setBrushOrigin(QPointF(0, 0));
4887 drawRect(pm.rect());
4890 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
4891 x += d->state->matrix.dx();
4892 y += d->state->matrix.dy();
4894 qreal scale = pm.devicePixelRatio();
4895 d->engine->drawPixmap(QRectF(x, y, w / scale, h / scale), pm, QRectF(0, 0, w, h));
4899void QPainter::drawPixmap(
const QRectF &r,
const QPixmap &pm,
const QRectF &sr)
4901#if defined QT_DEBUG_DRAW
4902 if (qt_show_painter_debug_output)
4903 printf(
"QPainter::drawPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], source=[%.2f,%.2f,%.2f,%.2f]\n",
4904 r.x(), r.y(), r.width(), r.height(),
4905 pm.width(), pm.height(),
4906 sr.x(), sr.y(), sr.width(), sr.height());
4910 if (!d->engine || pm.isNull())
4913 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawPixmap()");
4918 qreal w = r.width();
4919 qreal h = r.height();
4922 qreal sw = sr.width();
4923 qreal sh = sr.height();
4928 const qreal pmscale = pm.devicePixelRatio();
4932 sw = pm.width() - sx;
4935 sh = pm.height() - sy;
4943 qreal w_ratio = sx * w/sw;
4951 qreal h_ratio = sy * h/sh;
4958 if (sw + sx > pm.width()) {
4959 qreal delta = sw - (pm.width() - sx);
4960 qreal w_ratio = delta * w/sw;
4965 if (sh + sy > pm.height()) {
4966 qreal delta = sh - (pm.height() - sy);
4967 qreal h_ratio = delta * h/sh;
4972 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
4976 d->extended->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
4981 if (d->state->bgMode == Qt::OpaqueMode && pm.isQBitmap())
4982 fillRect(QRectF(x, y, w, h), d->state->bgBrush.color());
4984 d->updateState(d->state);
4986 if ((d->state->matrix.type() > QTransform::TxTranslate
4987 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
4988 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
4989 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity))
4990 || ((sw != w || sh != h) && !d->engine->hasFeature(QPaintEngine::PixmapTransform)))
4995 if (d->state->matrix.type() <= QTransform::TxScale) {
4996 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5001 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5009 scale(w / sw, h / sh);
5010 setBackgroundMode(Qt::TransparentMode);
5011 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5014 if (sw == pm.width() && sh == pm.height())
5015 brush = QBrush(d->state->pen.color(), pm);
5017 brush = QBrush(d->state->pen.color(), pm.copy(sx, sy, sw, sh));
5022 drawRect(QRectF(0, 0, sw, sh));
5025 if (!d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5026 x += d->state->matrix.dx();
5027 y += d->state->matrix.dy();
5029 d->engine->drawPixmap(QRectF(x, y, w, h), pm, QRectF(sx, sy, sw, sh));
5136void QPainter::drawImage(
const QPointF &p,
const QImage &image)
5140 if (!d->engine || image.isNull())
5144 d->extended->drawImage(p, image);
5151 int w = image.width();
5152 int h = image.height();
5153 qreal scale = image.devicePixelRatio();
5155 d->updateState(d->state);
5157 if (((d->state->matrix.type() > QTransform::TxTranslate)
5158 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5159 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5160 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5165 if (d->state->matrix.type() <= QTransform::TxScale) {
5166 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5171 setBackgroundMode(Qt::TransparentMode);
5172 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5173 QBrush brush(image);
5176 setBrushOrigin(QPointF(0, 0));
5177 drawRect(QRect(QPoint(0, 0), image.size() / scale));
5182 if (d->state->matrix.type() == QTransform::TxTranslate
5183 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5184 x += d->state->matrix.dx();
5185 y += d->state->matrix.dy();
5188 d->engine->drawImage(QRectF(x, y, w / scale, h / scale), image, QRectF(0, 0, w, h), Qt::AutoColor);
5191void QPainter::drawImage(
const QRectF &targetRect,
const QImage &image,
const QRectF &sourceRect,
5192 Qt::ImageConversionFlags flags)
5196 if (!d->engine || image.isNull())
5199 qreal x = targetRect.x();
5200 qreal y = targetRect.y();
5201 qreal w = targetRect.width();
5202 qreal h = targetRect.height();
5203 qreal sx = sourceRect.x();
5204 qreal sy = sourceRect.y();
5205 qreal sw = sourceRect.width();
5206 qreal sh = sourceRect.height();
5207 qreal imageScale = image.devicePixelRatio();
5211 sw = image.width() - sx;
5214 sh = image.height() - sy;
5217 w = sw / imageScale;
5219 h = sh / imageScale;
5222 qreal w_ratio = sx * w/sw;
5230 qreal h_ratio = sy * h/sh;
5237 if (sw + sx > image.width()) {
5238 qreal delta = sw - (image.width() - sx);
5239 qreal w_ratio = delta * w/sw;
5244 if (sh + sy > image.height()) {
5245 qreal delta = sh - (image.height() - sy);
5246 qreal h_ratio = delta * h/sh;
5251 if (w == 0 || h == 0 || sw <= 0 || sh <= 0)
5255 d->extended->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5259 d->updateState(d->state);
5261 if (((d->state->matrix.type() > QTransform::TxTranslate || (sw != w || sh != h))
5262 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
5263 || (!d->state->matrix.isAffine() && !d->engine->hasFeature(QPaintEngine::PerspectiveTransform))
5264 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
5269 if (d->state->matrix.type() <= QTransform::TxScale) {
5270 const QPointF p = roundInDeviceCoordinates(QPointF(x, y), d->state->matrix);
5275 if (d->state->matrix.type() <= QTransform::TxTranslate && sw == w && sh == h) {
5282 scale(w / sw, h / sh);
5283 setBackgroundMode(Qt::TransparentMode);
5284 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
5285 QBrush brush(image);
5288 setBrushOrigin(QPointF(-sx, -sy));
5290 drawRect(QRectF(0, 0, sw, sh));
5295 if (d->state->matrix.type() == QTransform::TxTranslate
5296 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
5297 x += d->state->matrix.dx();
5298 y += d->state->matrix.dy();
5301 d->engine->drawImage(QRectF(x, y, w, h), image, QRectF(sx, sy, sw, sh), flags);
5316void QPainter::drawGlyphRun(
const QPointF &position,
const QGlyphRun &glyphRun)
5321 qWarning(
"QPainter::drawGlyphRun: Painter not active");
5325 QRawFont font = glyphRun.rawFont();
5326 if (!font.isValid())
5329 QGlyphRunPrivate *glyphRun_d = QGlyphRunPrivate::get(glyphRun);
5331 const quint32 *glyphIndexes = glyphRun_d->glyphIndexData;
5332 const QPointF *glyphPositions = glyphRun_d->glyphPositionData;
5334 int count = qMin(glyphRun_d->glyphIndexDataSize, glyphRun_d->glyphPositionDataSize);
5335 QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
5337 QRawFontPrivate *fontD = QRawFontPrivate::get(font);
5338 bool engineRequiresPretransformedGlyphPositions = d->extended
5339 ? d->extended->requiresPretransformedGlyphPositions(fontD->fontEngine, d->state->matrix)
5340 : d->engine->type() != QPaintEngine::CoreGraphics && !d->state->matrix.isAffine();
5342 for (
int i=0; i<count; ++i) {
5343 QPointF processedPosition = position + glyphPositions[i];
5344 if (engineRequiresPretransformedGlyphPositions)
5345 processedPosition = d->state->transform().map(processedPosition);
5346 fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
5349 d->drawGlyphs(engineRequiresPretransformedGlyphPositions
5350 ? d->state->transform().map(position)
5353 fixedPointPositions.data(),
5356 glyphRun.overline(),
5357 glyphRun.underline(),
5358 glyphRun.strikeOut());
5362 const quint32 *glyphArray,
5374 if (extended !=
nullptr && state->matrix.isAffine()) {
5375 QStaticTextItem staticTextItem;
5376 staticTextItem.color = state->pen.color();
5377 staticTextItem.font = state->font;
5378 staticTextItem.setFontEngine(fontEngine);
5379 staticTextItem.numGlyphs = glyphCount;
5380 staticTextItem.glyphs =
reinterpret_cast<glyph_t *>(
const_cast<glyph_t *>(glyphArray));
5381 staticTextItem.glyphPositions = positions;
5383 staticTextItem.usesRawFont =
true;
5385 extended->drawStaticTextItem(&staticTextItem);
5388 textItem.fontEngine = fontEngine;
5390 QVarLengthArray<QFixed, 128> advances(glyphCount);
5391 QVarLengthArray<QGlyphJustification, 128> glyphJustifications(glyphCount);
5392 QVarLengthArray<QGlyphAttributes, 128> glyphAttributes(glyphCount);
5393 memset(glyphAttributes.data(), 0, glyphAttributes.size() *
sizeof(QGlyphAttributes));
5394 memset(
static_cast<
void *>(advances.data()), 0, advances.size() *
sizeof(QFixed));
5395 memset(
static_cast<
void *>(glyphJustifications.data()), 0, glyphJustifications.size() *
sizeof(QGlyphJustification));
5397 textItem.glyphs.numGlyphs = glyphCount;
5398 textItem.glyphs.glyphs =
const_cast<glyph_t *>(glyphArray);
5399 textItem.glyphs.offsets = positions;
5400 textItem.glyphs.advances = advances.data();
5401 textItem.glyphs.justifications = glyphJustifications.data();
5402 textItem.glyphs.attributes = glyphAttributes.data();
5404 engine->drawTextItem(QPointF(0, 0), textItem);
5407 qt_draw_decoration_for_glyphs(q,
5486void QPainter::drawStaticText(
const QPointF &topLeftPosition,
const QStaticText &staticText)
5489 if (!d->engine || staticText.text().isEmpty() || pen().style() == Qt::NoPen)
5492 QStaticTextPrivate *staticText_d =
5493 const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
5495 QFontPrivate *fp = QFontPrivate::get(font());
5496 QFontPrivate *stfp = QFontPrivate::get(staticText_d->font);
5497 if (font() != staticText_d->font || fp ==
nullptr || stfp ==
nullptr || fp->dpi != stfp->dpi) {
5498 staticText_d->font = font();
5499 staticText_d->needsRelayout =
true;
5500 }
else if (stfp->engineData ==
nullptr || stfp->engineData->fontCacheId != QFontCache::instance()->id()) {
5501 staticText_d->needsRelayout =
true;
5504 QFontEngine *fe = staticText_d->font.d->engineForScript(QChar::Script_Common);
5505 if (fe->type() == QFontEngine::Multi)
5506 fe =
static_cast<QFontEngineMulti *>(fe)->engine(0);
5511 if (d->extended ==
nullptr
5512 || !d->state->matrix.isAffine()
5513 || !fe->supportsTransformation(d->state->matrix)) {
5514 staticText_d->paintText(topLeftPosition,
this, pen().color());
5518 bool engineRequiresPretransform = d->extended->requiresPretransformedGlyphPositions(fe, d->state->matrix);
5519 if (staticText_d->untransformedCoordinates && engineRequiresPretransform) {
5522 staticText_d->untransformedCoordinates =
false;
5523 staticText_d->needsRelayout =
true;
5524 }
else if (!staticText_d->untransformedCoordinates && !engineRequiresPretransform) {
5527 staticText_d->untransformedCoordinates =
true;
5528 staticText_d->needsRelayout =
true;
5533 QPointF transformedPosition = topLeftPosition;
5534 if (!staticText_d->untransformedCoordinates)
5535 transformedPosition = transformedPosition * d->state->matrix;
5536 QTransform oldMatrix;
5540 if (d->state->matrix.isTranslating() && !staticText_d->untransformedCoordinates) {
5541 qreal m11 = d->state->matrix.m11();
5542 qreal m12 = d->state->matrix.m12();
5543 qreal m13 = d->state->matrix.m13();
5544 qreal m21 = d->state->matrix.m21();
5545 qreal m22 = d->state->matrix.m22();
5546 qreal m23 = d->state->matrix.m23();
5547 qreal m33 = d->state->matrix.m33();
5549 oldMatrix = d->state->matrix;
5550 d->state->matrix.setMatrix(m11, m12, m13,
5557 bool staticTextNeedsReinit = staticText_d->needsRelayout;
5558 if (!staticText_d->untransformedCoordinates && staticText_d->matrix != d->state->matrix) {
5559 staticText_d->matrix = d->state->matrix;
5560 staticTextNeedsReinit =
true;
5564 if (staticTextNeedsReinit)
5565 staticText_d->init();
5567 if (transformedPosition != staticText_d->position) {
5568 QFixed fx = QFixed::fromReal(transformedPosition.x());
5569 QFixed fy = QFixed::fromReal(transformedPosition.y());
5570 QFixed oldX = QFixed::fromReal(staticText_d->position.x());
5571 QFixed oldY = QFixed::fromReal(staticText_d->position.y());
5572 for (
int item=0; item<staticText_d->itemCount;++item) {
5573 QStaticTextItem *textItem = staticText_d->items + item;
5574 for (
int i=0; i<textItem->numGlyphs; ++i) {
5575 textItem->glyphPositions[i].x += fx - oldX;
5576 textItem->glyphPositions[i].y += fy - oldY;
5578 textItem->userDataNeedsUpdate =
true;
5581 staticText_d->position = transformedPosition;
5584 QPen oldPen = d->state->pen;
5585 QColor currentColor = oldPen.color();
5586 static const QColor bodyIndicator(0, 0, 0, 0);
5587 for (
int i=0; i<staticText_d->itemCount; ++i) {
5588 QStaticTextItem *item = staticText_d->items + i;
5589 if (item->color.isValid() && currentColor != item->color
5590 && item->color != bodyIndicator) {
5591 setPen(item->color);
5592 currentColor = item->color;
5593 }
else if (item->color == bodyIndicator) {
5595 currentColor = oldPen.color();
5597 d->extended->drawStaticTextItem(item);
5599 qt_draw_decoration_for_glyphs(
this,
5602 item->glyphPositions,
5605 staticText_d->font.underline(),
5606 staticText_d->font.overline(),
5607 staticText_d->font.strikeOut());
5609 if (currentColor != oldPen.color())
5612 if (!staticText_d->untransformedCoordinates && oldMatrix.isTranslating())
5613 d->state->matrix = oldMatrix;
5619void QPainter::drawText(
const QPointF &p,
const QString &str,
int tf,
int justificationPadding)
5622 if (qt_show_painter_debug_output)
5623 printf(
"QPainter::drawText(), pos=[%.2f,%.2f], str='%s'\n", p.x(), p.y(), str.toLatin1().constData());
5628 if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
5631 Q_DECL_UNINITIALIZED QStackTextEngine engine(str, d->state->font);
5632 engine.option.setTextDirection(d->state->layoutDirection);
5633 if (tf & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
5634 engine.ignoreBidi =
true;
5635 engine.option.setTextDirection((tf & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
5639 line.length = str.size();
5640 engine.shapeLine(line);
5642 int nItems = engine.layoutData->items.size();
5643 QVarLengthArray<
int> visualOrder(nItems);
5644 QVarLengthArray<uchar> levels(nItems);
5645 for (
int i = 0; i < nItems; ++i)
5646 levels[i] = engine.layoutData->items[i].analysis.bidiLevel;
5647 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
5649 if (justificationPadding > 0) {
5650 engine.option.setAlignment(Qt::AlignJustify);
5651 engine.forceJustification =
true;
5653 line.width = justificationPadding;
5654 engine.justify(line);
5656 QFixed x = QFixed::fromReal(p.x());
5658 for (
int i = 0; i < nItems; ++i) {
5659 int item = visualOrder[i];
5660 const QScriptItem &si = engine.layoutData->items.at(item);
5661 if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
5665 QFont f = engine.font(si);
5666 QTextItemInt gf(si, &f);
5667 gf.glyphs = engine.shapedGlyphs(&si);
5668 gf.chars = engine.layoutData->string.unicode() + si.position;
5669 gf.num_chars = engine.length(item);
5670 if (engine.forceJustification) {
5671 for (
int j=0; j<gf.glyphs.numGlyphs; ++j)
5672 gf.width += gf.glyphs.effectiveAdvance(j);
5674 gf.width = si.width;
5676 gf.logClusters = engine.logClusters(&si);
5678 drawTextItem(QPointF(x.toReal(), p.y()), gf);
5946 const qreal radiusBase = qMax(qreal(1), maxRadius);
5948 QString key =
"WaveUnderline-"_L1
5949 % pen.color().name()
5950 % HexString<qreal>(radiusBase)
5951 % HexString<qreal>(pen.widthF());
5954 if (QPixmapCache::find(key, &pixmap))
5957 const qreal halfPeriod = qMax(qreal(2), qreal(radiusBase * 1.61803399));
5958 const int width = qCeil(100 / (2 * halfPeriod)) * (2 * halfPeriod);
5959 const qreal radius = qFloor(radiusBase * 2) / 2.;
5966 while (xs < width) {
5969 path.quadTo(xs - halfPeriod / 2, ys, xs, 0);
5972 pixmap = QPixmap(width, radius * 2);
5973 pixmap.fill(Qt::transparent);
5976 wavePen.setCapStyle(Qt::SquareCap);
5980 const qreal maxPenWidth = .8 * radius;
5981 if (wavePen.widthF() > maxPenWidth)
5982 wavePen.setWidthF(maxPenWidth);
5985 imgPainter.setPen(wavePen);
5986 imgPainter.setRenderHint(QPainter::Antialiasing);
5987 imgPainter.translate(0, radius);
5988 imgPainter.drawPath(path);
5991 QPixmapCache::insert(key, pixmap);
5997 QTextCharFormat::UnderlineStyle underlineStyle,
5998 QTextItem::RenderFlags flags, qreal width,
5999 const QTextCharFormat &charFormat)
6001 if (underlineStyle == QTextCharFormat::NoUnderline
6002 && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
6005 const QPen oldPen = painter->pen();
6006 const QBrush oldBrush = painter->brush();
6007 painter->setBrush(Qt::NoBrush);
6009 pen.setStyle(Qt::SolidLine);
6010 pen.setWidthF(fe->lineThickness().toReal());
6011 pen.setCapStyle(Qt::FlatCap);
6013 QLineF line(qFloor(pos.x()), pos.y(), qFloor(pos.x() + width), pos.y());
6015 const qreal underlineOffset = fe->underlinePosition().toReal();
6017 if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
6018 QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
6020 underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt());
6021 if (underlineStyle == QTextCharFormat::SpellCheckUnderline)
6022 underlineStyle = QTextCharFormat::WaveUnderline;
6025 if (underlineStyle == QTextCharFormat::WaveUnderline) {
6027 painter->translate(0, pos.y() + 1);
6028 qreal maxHeight = fe->descent().toReal() - qreal(1);
6030 QColor uc = charFormat.underlineColor();
6035 const QPixmap wave = generateWavyPixmap(qMin(qMax(underlineOffset, pen.widthF()), maxHeight / qreal(2.)), pen);
6036 const int descent = qFloor(maxHeight);
6038 painter->setBrushOrigin(painter->brushOrigin().x(), 0);
6039 painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
6041 }
else if (underlineStyle != QTextCharFormat::NoUnderline) {
6044 qreal adjustedUnderlineOffset =
std::ceil(underlineOffset) + 0.5;
6045 if (underlineOffset <= fe->descent().toReal())
6046 adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - qreal(0.5));
6047 const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
6048 QColor uc = charFormat.underlineColor();
6052 pen.setStyle((Qt::PenStyle)(underlineStyle));
6053 painter->setPen(pen);
6054 QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos);
6056 textEngine->addUnderline(painter, underline);
6058 painter->drawLine(underline);
6061 pen.setStyle(Qt::SolidLine);
6062 pen.setColor(oldPen.color());
6064 if (flags & QTextItem::StrikeOut) {
6065 QLineF strikeOutLine = line;
6066 strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
6067 QColor uc = charFormat.underlineColor();
6070 painter->setPen(pen);
6072 textEngine->addStrikeOut(painter, strikeOutLine);
6074 painter->drawLine(strikeOutLine);
6077 if (flags & QTextItem::Overline) {
6078 QLineF overline = line;
6079 overline.translate(0., - fe->ascent().toReal());
6080 QColor uc = charFormat.underlineColor();
6083 painter->setPen(pen);
6085 textEngine->addOverline(painter, overline);
6087 painter->drawLine(overline);
6090 painter->setPen(oldPen);
6091 painter->setBrush(oldBrush);
6144 if (qt_show_painter_debug_output)
6145 printf(
"QPainter::drawTextItem(), pos=[%.f,%.f], str='%s'\n",
6146 p.x(), p.y(), qPrintable(_ti.text()));
6154 QTextItemInt &ti =
const_cast<QTextItemInt &>(
static_cast<
const QTextItemInt &>(_ti));
6156 if (!extended && state->bgMode == Qt::OpaqueMode) {
6157 QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent).toReal());
6158 q->fillRect(rect, state->bgBrush);
6161 if (q->pen().style() == Qt::NoPen)
6164 const QPainter::RenderHints oldRenderHints = state->renderHints;
6165 if (!(state->renderHints & QPainter::Antialiasing) && state->matrix.type() >= QTransform::TxScale) {
6170 const QTransform &m = state->matrix;
6171 if (state->matrix.type() < QTransform::TxShear) {
6172 bool isPlain90DegreeRotation =
6173 (qFuzzyIsNull(m.m11())
6174 && qFuzzyIsNull(m.m12() - qreal(1))
6175 && qFuzzyIsNull(m.m21() + qreal(1))
6176 && qFuzzyIsNull(m.m22())
6179 (qFuzzyIsNull(m.m11() + qreal(1))
6180 && qFuzzyIsNull(m.m12())
6181 && qFuzzyIsNull(m.m21())
6182 && qFuzzyIsNull(m.m22() + qreal(1))
6185 (qFuzzyIsNull(m.m11())
6186 && qFuzzyIsNull(m.m12() + qreal(1))
6187 && qFuzzyIsNull(m.m21() - qreal(1))
6188 && qFuzzyIsNull(m.m22())
6191 aa = !isPlain90DegreeRotation;
6194 q->setRenderHint(QPainter::Antialiasing,
true);
6200 if (!ti.glyphs.numGlyphs) {
6201 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6202 ti.flags, ti.width.toReal(), ti.charFormat);
6203 }
else if (ti.fontEngine->type() == QFontEngine::Multi) {
6204 QFontEngineMulti *multi =
static_cast<QFontEngineMulti *>(ti.fontEngine);
6207 int which = glyphs.glyphs[0] >> 24;
6212 bool rtl = ti.flags & QTextItem::RightToLeft;
6214 x += ti.width.toReal();
6218 for (end = 0; end < ti.glyphs.numGlyphs; ++end) {
6219 const int e = glyphs.glyphs[end] >> 24;
6224 multi->ensureEngineAt(which);
6225 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6228 for (i = start; i < end; ++i) {
6229 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6230 ti2.width += ti.glyphs.effectiveAdvance(i);
6234 x -= ti2.width.toReal();
6239 engine->drawTextItem(QPointF(x, y), ti2);
6240 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6241 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6244 x += ti2.width.toReal();
6247 const int hi = which << 24;
6248 for (i = start; i < end; ++i) {
6249 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6257 multi->ensureEngineAt(which);
6258 QTextItemInt ti2 = ti.midItem(multi->engine(which), start, end - start);
6261 for (i = start; i < end; ++i) {
6262 glyphs.glyphs[i] = glyphs.glyphs[i] & 0xffffff;
6263 ti2.width += ti.glyphs.effectiveAdvance(i);
6267 x -= ti2.width.toReal();
6272 engine->drawTextItem(QPointF(x,y), ti2);
6273 drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
6274 ti2.flags, ti2.width.toReal(), ti2.charFormat);
6277 const int hi = which << 24;
6278 for (i = start; i < end; ++i)
6279 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
6285 engine->drawTextItem(p, ti);
6286 drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle,
6287 ti.flags, ti.width.toReal(), ti.charFormat);
6290 if (state->renderHints != oldRenderHints) {
6291 state->renderHints = oldRenderHints;
6295 state->dirtyFlags |= QPaintEngine::DirtyHints;
6422void QPainter::drawTiledPixmap(
const QRectF &r,
const QPixmap &pixmap,
const QPointF &sp)
6425 if (qt_show_painter_debug_output)
6426 printf(
"QPainter::drawTiledPixmap(), target=[%.2f,%.2f,%.2f,%.2f], pix=[%d,%d], offset=[%.2f,%.2f]\n",
6427 r.x(), r.y(), r.width(), r.height(),
6428 pixmap.width(), pixmap.height(),
6433 if (!d->engine || pixmap.isNull() || r.isEmpty())
6437 qt_painter_thread_test(d->device->devType(), d->engine->type(),
"drawTiledPixmap()");
6440 qreal sw = pixmap.width();
6441 qreal sh = pixmap.height();
6445 sx = qRound(sw) - qRound(-sx) % qRound(sw);
6447 sx = qRound(sx) % qRound(sw);
6449 sy = qRound(sh) - -qRound(sy) % qRound(sh);
6451 sy = qRound(sy) % qRound(sh);
6455 d->extended->drawTiledPixmap(r, pixmap, QPointF(sx, sy));
6459 if (d->state->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
6460 fillRect(r, d->state->bgBrush);
6462 d->updateState(d->state);
6463 if ((d->state->matrix.type() > QTransform::TxTranslate
6464 && !d->engine->hasFeature(QPaintEngine::PixmapTransform))
6465 || (d->state->opacity != 1.0 && !d->engine->hasFeature(QPaintEngine::ConstantOpacity)))
6468 setBackgroundMode(Qt::TransparentMode);
6469 setRenderHint(Antialiasing, renderHints() & SmoothPixmapTransform);
6470 setBrush(QBrush(d->state->pen.color(), pixmap));
6475 if (d->state->matrix.type() <= QTransform::TxScale) {
6476 const QPointF p = roundInDeviceCoordinates(r.topLeft(), d->state->matrix);
6478 if (d->state->matrix.type() <= QTransform::TxTranslate) {
6483 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6484 drawRect(QRectF(p, r.size()));
6486 setBrushOrigin(QPointF(r.x()-sx, r.y()-sy));
6495 if (d->state->matrix.type() == QTransform::TxTranslate
6496 && !d->engine->hasFeature(QPaintEngine::PixmapTransform)) {
6497 x += d->state->matrix.dx();
6498 y += d->state->matrix.dy();
6501 d->engine->drawTiledPixmap(QRectF(x, y, r.width(), r.height()), pixmap, QPointF(sx, sy));
7129 int tf,
const QTextOption *option,
const QString& str, QRectF *brect,
7130 int tabstops,
int *ta,
int tabarraylen,
7134 Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=
nullptr) );
7136 if (_r.isEmpty() && !(tf & Qt::TextDontClip)) {
7140 tf |= Qt::TextDontPrint;
7144 tf |= option->alignment();
7145 if (option->wrapMode() != QTextOption::NoWrap)
7146 tf |= Qt::TextWordWrap;
7148 if (option->flags() & QTextOption::IncludeTrailingSpaces)
7149 tf |= Qt::TextIncludeTrailingSpaces;
7151 if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
7152 tf |= Qt::TextExpandTabs;
7158 bool dontclip = (tf & Qt::TextDontClip);
7159 bool wordwrap = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
7160 bool singleline = (tf & Qt::TextSingleLine);
7161 bool showmnemonic = (tf & Qt::TextShowMnemonic);
7162 bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
7164 Qt::LayoutDirection layout_direction;
7165 if (tf & Qt::TextForceLeftToRight)
7166 layout_direction = Qt::LeftToRight;
7167 else if (tf & Qt::TextForceRightToLeft)
7168 layout_direction = Qt::RightToLeft;
7170 layout_direction = option->textDirection();
7172 layout_direction = painter->layoutDirection();
7174 layout_direction = Qt::LeftToRight;
7176 tf = QGuiApplicationPrivate::visualAlignment(layout_direction, QFlag(tf));
7178 bool isRightToLeft = layout_direction == Qt::RightToLeft;
7179 bool expandtabs = ((tf & Qt::TextExpandTabs) &&
7180 (((tf & Qt::AlignLeft) && !isRightToLeft) ||
7181 ((tf & Qt::AlignRight) && isRightToLeft)));
7184 tf |= Qt::TextDontPrint;
7186 uint maxUnderlines = 0;
7188 QFontMetricsF fm(fnt);
7192 bool hasMoreLengthVariants =
false;
7195 int old_offset = offset;
7196 for (; offset < text.size(); offset++) {
7197 QChar chr = text.at(offset);
7198 if (chr == u'\r' || (singleline && chr == u'\n')) {
7199 text[offset] = u' ';
7200 }
else if (chr == u'\n') {
7201 text[offset] = QChar::LineSeparator;
7202 }
else if (chr == u'&') {
7204 }
else if (chr == u'\t') {
7206 text[offset] = u' ';
7207 }
else if (!tabarraylen && !tabstops) {
7208 tabstops = qRound(fm.horizontalAdvance(u'x')*8);
7210 }
else if (chr == u'\x9c') {
7212 hasMoreLengthVariants =
true;
7217 QList<QTextLayout::FormatRange> underlineFormats;
7218 int length = offset - old_offset;
7219 if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
7220 QChar *cout = text.data() + old_offset;
7221 QChar *cout0 = cout;
7231 if (*cin != u'&' && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
7232 QTextLayout::FormatRange range;
7233 range.start = cout - cout0;
7235 range.format.setFontUnderline(
true);
7236 underlineFormats.append(range);
7239 }
else if (hidemnmemonic && *cin == u'(' && l >= 4 &&
7240 cin[1] == u'&' && cin[2] != u'&' &&
7243 while ((cout - n) > cout0 && (cout - n - 1)->isSpace())
7262 QString finalText = text.mid(old_offset, length);
7263 Q_DECL_UNINITIALIZED QStackTextEngine engine(finalText, fnt);
7265 engine.option = *option;
7268 if (engine.option.tabStopDistance() < 0 && tabstops > 0)
7269 engine.option.setTabStopDistance(tabstops);
7271 if (engine.option.tabs().isEmpty() && ta) {
7273 tabs.reserve(tabarraylen);
7274 for (
int i = 0; i < tabarraylen; i++)
7275 tabs.append(qreal(ta[i]));
7276 engine.option.setTabArray(tabs);
7279 engine.option.setTextDirection(layout_direction);
7280 if (tf & Qt::AlignJustify)
7281 engine.option.setAlignment(Qt::AlignJustify);
7283 engine.option.setAlignment(Qt::AlignLeft);
7285 if (!option && (tf & Qt::TextWrapAnywhere))
7286 engine.option.setWrapMode(QTextOption::WrapAnywhere);
7288 if (tf & Qt::TextJustificationForced)
7289 engine.forceJustification =
true;
7291 textLayout.setCacheEnabled(
true);
7292 textLayout.setFormats(underlineFormats);
7294 if (finalText.isEmpty()) {
7295 height = fm.height();
7297 tf |= Qt::TextDontPrint;
7299 qreal lineWidth = 0x01000000;
7300 if (wordwrap || (tf & Qt::TextJustificationForced))
7301 lineWidth = qMax<qreal>(0, r.width());
7303 tf |= Qt::TextIncludeTrailingSpaces;
7304 textLayout.beginLayout();
7306 qreal leading = fm.leading();
7310 QTextLine l = textLayout.createLine();
7314 l.setLineWidth(lineWidth);
7318 height = qCeil(height);
7319 l.setPosition(
QPointF(0., height));
7320 height += textLayout.engine()->lines[l.lineNumber()].height().toReal();
7321 width = qMax(width, l.naturalTextWidth());
7322 if (!dontclip && !brect && height >= r.height())
7325 textLayout.endLayout();
7330 if (tf & Qt::AlignBottom)
7331 yoff = r.height() - height;
7332 else if (tf & Qt::AlignVCenter)
7333 yoff = (r.height() - height)/2;
7335 if (tf & Qt::AlignRight)
7336 xoff = r.width() - width;
7337 else if (tf & Qt::AlignHCenter)
7338 xoff = (r.width() - width)/2;
7340 QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
7342 if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
7344 goto start_lengthVariant;
7349 if (!(tf & Qt::TextDontPrint)) {
7350 bool restore =
false;
7351 if (!dontclip && !r.contains(bounds)) {
7354 painter->setClipRect(r, Qt::IntersectClip);
7357 for (
int i = 0; i < textLayout.lineCount(); i++) {
7358 QTextLine line = textLayout.lineAt(i);
7360 eng->enableDelayDecorations();
7362 qreal advance = line.horizontalAdvance();
7364 if (tf & Qt::AlignRight) {
7365 xoff = r.width() - advance -
7366 eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal();
7368 else if (tf & Qt::AlignHCenter)
7369 xoff = (r.width() - advance) / 2;
7371 line.draw(painter,
QPointF(r.x() + xoff, r.y() + yoff));
7372 eng->drawDecorations(painter);
7408QPainterState::QPainterState(
const QPainterState *s)
7409 : brushOrigin(s->brushOrigin), font(s->font), deviceFont(s->deviceFont),
7410 pen(s->pen), brush(s->brush), bgBrush(s->bgBrush),
7411 clipRegion(s->clipRegion), clipPath(s->clipPath),
7412 clipOperation(s->clipOperation),
7413 renderHints(s->renderHints), clipInfo(s->clipInfo),
7414 worldMatrix(s->worldMatrix), matrix(s->matrix), redirectionMatrix(s->redirectionMatrix),
7415 wx(s->wx), wy(s->wy), ww(s->ww), wh(s->wh),
7416 vx(s->vx), vy(s->vy), vw(s->vw), vh(s->vh),
7417 opacity(s->opacity), WxF(s->WxF), VxF(s->VxF),
7418 clipEnabled(s->clipEnabled), bgMode(s->bgMode), painter(s->painter),
7419 layoutDirection(s->layoutDirection),
7420 composition_mode(s->composition_mode),
7421 emulationSpecifier(s->emulationSpecifier), changeFlags(0)
7423 dirtyFlags = s->dirtyFlags;
8044void QPainter::drawPixmapFragments(
const PixmapFragment *fragments,
int fragmentCount,
8045 const QPixmap &pixmap, PixmapFragmentHints hints)
8049 if (!d->engine || pixmap.isNull())
8053 for (
int i = 0; i < fragmentCount; ++i) {
8054 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8055 fragments[i].width, fragments[i].height);
8056 if (!(QRectF(pixmap.rect()).contains(sourceRect)))
8057 qWarning(
"QPainter::drawPixmapFragments - the source rect is not contained by the pixmap's rectangle");
8061 if (d->engine->isExtended()) {
8062 d->extended->drawPixmapFragments(fragments, fragmentCount, pixmap, hints);
8064 qreal oldOpacity = opacity();
8065 QTransform oldTransform = transform();
8067 for (
int i = 0; i < fragmentCount; ++i) {
8068 QTransform transform = oldTransform;
8071 if (fragments[i].rotation == 0) {
8072 xOffset = fragments[i].x;
8073 yOffset = fragments[i].y;
8075 transform.translate(fragments[i].x, fragments[i].y);
8076 transform.rotate(fragments[i].rotation);
8078 setOpacity(oldOpacity * fragments[i].opacity);
8079 setTransform(transform);
8081 qreal w = fragments[i].scaleX * fragments[i].width;
8082 qreal h = fragments[i].scaleY * fragments[i].height;
8083 QRectF sourceRect(fragments[i].sourceLeft, fragments[i].sourceTop,
8084 fragments[i].width, fragments[i].height);
8085 drawPixmap(QRectF(-0.5 * w + xOffset, -0.5 * h + yOffset, w, h), pixmap, sourceRect);
8088 setOpacity(oldOpacity);
8089 setTransform(oldTransform);