432void QQuickTextPrivate::updateSize()
436 if (!q->isComponentComplete()) {
437 updateOnComponentComplete =
true;
441 if (!requireImplicitSize) {
442 implicitWidthChanged();
443 implicitHeightChanged();
445 if (requireImplicitSize)
449 qreal hPadding = q->leftPadding() + q->rightPadding();
450 qreal vPadding = q->topPadding() + q->bottomPadding();
452 const QSizeF previousSize(q->contentWidth(), q->contentHeight());
454 if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
459 QFontMetricsF fm(font);
460 qreal fontHeight = qCeil(fm.height());
462 fontHeight = lineHeightMode() == QQuickText::FixedHeight
464 : fontHeight * lineHeight();
466 updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding);
467 q->setImplicitSize(hPadding, fontHeight + qMax(lineHeightOffset(), 0) + vPadding);
468 layedOutTextRect = QRectF(0, 0, 0, fontHeight);
470 signalSizeChange(previousSize);
472 emit q->lineCountChanged();
475 emit q->truncatedChanged();
477 updateType = UpdatePaintNode;
487 QRectF textRect = setupTextLayout(&baseline);
489 if (internalWidthUpdate)
492 layedOutTextRect = textRect;
493 size = textRect.size();
494 updateBaseline(baseline, q->height() - size.height() - vPadding);
496 widthExceeded =
true;
497 heightExceeded =
false;
499 extra->doc->setDefaultFont(font);
500 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
501 if (rightToLeftText) {
502 if (horizontalAlignment == QQuickText::AlignLeft)
503 horizontalAlignment = QQuickText::AlignRight;
504 else if (horizontalAlignment == QQuickText::AlignRight)
505 horizontalAlignment = QQuickText::AlignLeft;
508 option.setAlignment((Qt::Alignment)
int(horizontalAlignment | vAlign));
509 option.setWrapMode(QTextOption::WrapMode(wrapMode));
510 option.setUseDesignMetrics(renderType != QQuickText::NativeRendering);
511 extra->doc->setDefaultTextOption(option);
512 qreal naturalWidth = 0;
513 if (requireImplicitSize) {
514 extra->doc->setTextWidth(-1);
515 naturalWidth = extra->doc->idealWidth();
516 const bool wasInLayout = internalWidthUpdate;
517 internalWidthUpdate =
true;
518 q->setImplicitWidth(naturalWidth + hPadding);
519 internalWidthUpdate = wasInLayout;
521 if (internalWidthUpdate)
524 extra->doc->setPageSize(QSizeF(q->width(), -1));
525 if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
526 extra->doc->setTextWidth(availableWidth());
528 extra->doc->setTextWidth(extra->doc->idealWidth());
530 QSizeF dsize = extra->doc->size();
531 layedOutTextRect = QRectF(QPointF(0,0), dsize);
532 size = QSizeF(extra->doc->idealWidth(),dsize.height());
535 qreal baseline = QFontMetricsF(font).ascent();
536 QTextBlock firstBlock = extra->doc->firstBlock();
537 if (firstBlock.isValid() && firstBlock.layout() !=
nullptr && firstBlock.lineCount() > 0)
538 baseline = firstBlock.layout()->lineAt(0).ascent();
540 updateBaseline(baseline, q->height() - size.height() - vPadding);
543 internalWidthUpdate =
true;
544 qreal oldWidth = q->width();
546 if (!q->widthValid())
547 iWidth = size.width();
549 q->setImplicitSize(iWidth + hPadding, size.height() + qMax(lineHeightOffset(), 0) + vPadding);
550 internalWidthUpdate =
false;
557 if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
558 updateSizeRecursionGuard =
true;
560 updateSizeRecursionGuard =
false;
563 q->setImplicitHeight(size.height() + lineHeightOffset() + vPadding);
565 QTextBlock firstBlock = extra->doc->firstBlock();
566 while (firstBlock.layout()->lineCount() == 0)
567 firstBlock = firstBlock.next();
569 QTextBlock lastBlock = extra->doc->lastBlock();
570 while (lastBlock.layout()->lineCount() == 0)
571 lastBlock = lastBlock.previous();
573 if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
574 QTextLine firstLine = firstBlock.layout()->lineAt(0);
575 QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
576 advance = QSizeF(lastLine.horizontalAdvance(),
577 (lastLine.y() + lastBlock.layout()->position().y() + lastLine.ascent()) - (firstLine.y() + firstBlock.layout()->position().y() + firstLine.ascent()));
584 signalSizeChange(previousSize);
585 updateType = UpdatePaintNode;
790QRectF QQuickTextPrivate::setupTextLayout(qreal *
const baseline)
794 bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
795 bool multilineElide = elideMode == QQuickText::ElideRight
797 && (q->heightValid() || maximumLineCountValid);
799 if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid))
800 && ((singlelineElide && availableWidth() <= 0.)
801 || (multilineElide && q->heightValid() && availableHeight() <= 0.))) {
803 widthExceeded = q->widthValid() && availableWidth() <= 0.;
804 heightExceeded = q->heightValid() && availableHeight() <= 0.;
808 emit q->truncatedChanged();
812 q->setFlag(QQuickItem::ItemObservesViewport,
false);
813 emit q->lineCountChanged();
816 if (qFuzzyIsNull(q->width())) {
817 layout.setText(QString());
818 textHasChanged =
true;
821 QFontMetricsF fm(font);
822 qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : qCeil(fm.height()) * lineHeight();
823 *baseline = fm.ascent();
824 return QRectF(0, 0, 0, height);
827 bool shouldUseDesignMetrics = renderType != QQuickText::NativeRendering;
828 layout.setCacheEnabled(
true);
829 QTextOption textOption = layout.textOption();
830 if (textOption.alignment() != q->effectiveHAlign()
831 || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
832 || textOption.useDesignMetrics() != shouldUseDesignMetrics) {
833 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
834 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
835 textOption.setUseDesignMetrics(shouldUseDesignMetrics);
836 layout.setTextOption(textOption);
838 if (layout.font() != font)
839 layout.setFont(font);
841 lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
844 qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
846 const bool customLayout = isLineLaidOutConnected();
847 const bool wasTruncated = truncated;
849 bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
851 bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
852 bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
853 && (q->heightValid() || (maximumLineCountValid && canWrap));
855 const bool pixelSize = font.pixelSize() != -1;
856 QString layoutText = layout.text();
858 const qreal minimumSize = pixelSize
859 ?
static_cast<qreal>(minimumPixelSize())
860 : minimumPointSize();
861 qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
862 qreal smallFont = fontSizeMode() != QQuickText::FixedSize
863 ? qMin<qreal>(minimumSize, largeFont)
865 qreal scaledFontSize = largeFont;
866 const qreal sizeFittingThreshold(0.01);
868 bool widthChanged =
false;
869 widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
870 heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit);
874 QFont scaledFont = font;
876 int visibleCount = 0;
883 bool noBreakLastLine = multilineElide && (wrapMode == QQuickText::Wrap || wrapMode == QQuickText::WordWrap);
885 int eos = multilengthEos;
893 scaledFont.setPixelSize(scaledFontSize);
895 scaledFont.setPointSizeF(scaledFontSize);
896 if (layout.font() != scaledFont)
897 layout.setFont(scaledFont);
900 layout.beginLayout();
902 bool wrapped =
false;
903 bool truncateHeight =
false;
906 int unwrappedLineCount = 1;
907 const int maxLineCount = maximumLineCount();
909 qreal naturalHeight = 0;
910 qreal previousHeight = 0;
915 for (visibleCount = 1; ; ++visibleCount) {
916 line = layout.createLine();
918 if (noBreakLastLine && visibleCount == maxLineCount)
919 layout.engine()->option.setWrapMode(QTextOption::WrapAnywhere);
921 setupCustomLineGeometry(line, naturalHeight, layoutText.size());
923 setLineGeometry(line, lineWidth, naturalHeight);
925 if (noBreakLastLine && visibleCount == maxLineCount)
926 layout.engine()->option.setWrapMode(QTextOption::WrapMode(wrapMode));
928 unelidedRect = br.united(line.naturalTextRect());
932 if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
934 heightExceeded =
true;
939 truncateHeight =
true;
943 const QTextLine previousLine = layout.lineAt(visibleCount - 1);
944 elideText = elidedText(line.width(), previousLine);
945 elideStart = previousLine.textStart();
946 elideEnd = line.textStart() + line.textLength();
948 height = previousHeight;
952 const bool isLastLine = line.textStart() + line.textLength() >= layoutText.size();
954 if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > line.width()) {
957 widthExceeded =
true;
962 elideText = layout.engine()->elidedText(
963 Qt::TextElideMode(elideMode),
964 QFixed::fromReal(line.width()),
968 elideStart = line.textStart();
969 elideEnd = elideStart + line.textLength();
972 height = naturalHeight;
976 const bool wrappedLine = layoutText.at(line.textStart() + line.textLength() - 1) != QChar::LineSeparator;
977 wrapped |= wrappedLine;
980 ++unwrappedLineCount;
983 if (visibleCount == maxLineCount) {
985 heightExceeded |= wrapped;
987 if (multilineElide) {
992 elideText = elidedText(line.width(), line);
993 elideStart = line.textStart();
994 elideEnd = elideStart + line.textLength();
997 height = naturalHeight;
1003 previousHeight = height;
1004 height = naturalHeight;
1006 widthExceeded |= wrapped;
1014 if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
1017 for (
int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1018 line = layout.createLine();
1019 if (!line.isValid())
1021 if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
1022 ++unwrappedLineCount;
1023 setLineGeometry(line, lineWidth, naturalHeight);
1028 const int eol = line.isValid()
1029 ? line.textStart() + line.textLength()
1030 : layoutText.size();
1031 if (eol < layoutText.size() && layoutText.at(eol) != QChar::LineSeparator)
1032 line = layout.createLine();
1033 for (; line.isValid() && unwrappedLineCount < maxLineCount; ++unwrappedLineCount)
1034 line = layout.createLine();
1039 const qreal naturalWidth = layout.maximumWidth();
1041 bool wasInLayout = internalWidthUpdate;
1042 internalWidthUpdate =
true;
1043 q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1044 internalWidthUpdate = wasInLayout;
1047 singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
1048 multilineElide = elideMode == QQuickText::ElideRight
1050 && (q->heightValid() || maximumLineCountValid);
1051 canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
1053 horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
1054 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1055 && (q->heightValid() || (maximumLineCountValid && canWrap));
1057 const qreal oldWidth = lineWidth;
1058 const qreal oldHeight = maxHeight;
1060 const qreal availWidth = availableWidth();
1061 const qreal availHeight = availableHeight();
1063 lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
1064 maxHeight = q->heightValid() ? availHeight : FLT_MAX;
1068 if ((!qFuzzyCompare(lineWidth, oldWidth) || (widthExceeded && lineWidth > oldWidth))
1069 && (singlelineElide || multilineElide || canWrap || horizontalFit
1070 || q->effectiveHAlign() != QQuickText::AlignLeft)) {
1071 widthChanged =
true;
1072 widthExceeded = lineWidth >= qMin(oldWidth, naturalWidth);
1073 heightExceeded =
false;
1079 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1080 && (multilineElide || (canWrap && maximumLineCountValid))) {
1081 widthExceeded =
false;
1082 heightExceeded =
false;
1088 if (!q->widthValid() && !implicitWidthValid && unwrappedLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
1089 widthExceeded =
false;
1090 heightExceeded =
false;
1093 }
else if (widthChanged) {
1094 widthChanged =
false;
1095 if (line.isValid()) {
1096 for (
int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1097 line = layout.createLine();
1098 if (!line.isValid())
1100 setLineGeometry(line, lineWidth, naturalHeight);
1105 bool wasInLayout = internalWidthUpdate;
1106 internalWidthUpdate =
true;
1107 q->setImplicitHeight(naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1108 internalWidthUpdate = wasInLayout;
1110 multilineElide = elideMode == QQuickText::ElideRight
1112 && (q->heightValid() || maximumLineCountValid);
1113 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1114 && (q->heightValid() || (maximumLineCountValid && canWrap));
1116 const qreal oldHeight = maxHeight;
1117 maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
1120 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1121 && (multilineElide || (canWrap && maximumLineCountValid))) {
1122 widthExceeded =
false;
1123 heightExceeded =
false;
1132 if (eos != -1 && elide) {
1133 int start = eos + 1;
1134 eos = text.indexOf(QLatin1Char(
'\x9c'), start);
1135 layoutText = text.mid(start, eos != -1 ? eos - start : -1);
1136 layoutText.replace(QLatin1Char(
'\n'), QChar::LineSeparator);
1137 layout.setText(layoutText);
1138 textHasChanged =
true;
1145 if (layout.lineCount() > 0) {
1146 QTextLine firstLine = layout.lineAt(0);
1147 QTextLine lastLine = layout.lineAt(layout.lineCount() - 1);
1148 advance = QSizeF(lastLine.horizontalAdvance(),
1149 lastLine.y() - firstLine.y());
1154 if (!horizontalFit && !verticalFit)
1158 if (qFuzzyCompare(smallFont, largeFont))
1162 if (horizontalFit) {
1163 if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
1164 widthExceeded =
true;
1165 largeFont = scaledFontSize;
1167 scaledFontSize = (smallFont + largeFont) / 2;
1170 }
else if (!verticalFit) {
1171 smallFont = scaledFontSize;
1174 if ((largeFont - smallFont) < sizeFittingThreshold)
1177 scaledFontSize = (smallFont + largeFont) / 2;
1182 if (truncateHeight || unelidedRect.height() > maxHeight) {
1183 heightExceeded =
true;
1184 largeFont = scaledFontSize;
1186 scaledFontSize = (smallFont + largeFont) / 2;
1189 smallFont = scaledFontSize;
1192 if ((largeFont - smallFont) < sizeFittingThreshold)
1195 scaledFontSize = (smallFont + largeFont) / 2;
1200 implicitWidthValid =
true;
1201 implicitHeightValid =
true;
1203 QFontInfo scaledFontInfo(scaledFont);
1204 if (fontInfo.weight() != scaledFontInfo.weight()
1205 || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
1206 || fontInfo.italic() != scaledFontInfo.italic()
1207 || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
1208 || fontInfo.family() != scaledFontInfo.family()
1209 || fontInfo.styleName() != scaledFontInfo.styleName()) {
1210 fontInfo = scaledFontInfo;
1211 emit q->fontInfoChanged();
1214 if (eos != multilengthEos)
1217 assignedFont = QFontInfo(font).family();
1221 elideLayout.reset(
new QTextLayout);
1222 elideLayout->setCacheEnabled(
true);
1224 QTextEngine *engine = layout.engine();
1225 if (engine && engine->hasFormats()) {
1226 QList<QTextLayout::FormatRange> formats;
1227 switch (elideMode) {
1228 case QQuickText::ElideRight:
1229 elideFormats(elideStart, elideText.size() - 1, 0, &formats);
1231 case QQuickText::ElideLeft:
1232 elideFormats(elideEnd - elideText.size() + 1, elideText.size() - 1, 1, &formats);
1234 case QQuickText::ElideMiddle: {
1235 const int index = elideText.indexOf(elideChar);
1237 elideFormats(elideStart, index, 0, &formats);
1239 elideEnd - elideText.size() + index + 1,
1240 elideText.size() - index - 1,
1249 elideLayout->setFormats(formats);
1252 elideLayout->setFont(layout.font());
1253 elideLayout->setTextOption(layout.textOption());
1254 elideLayout->setText(elideText);
1255 elideLayout->beginLayout();
1257 QTextLine elidedLine = elideLayout->createLine();
1258 elidedLine.setPosition(QPointF(0, height));
1260 setupCustomLineGeometry(elidedLine, height, elideText.size(), visibleCount - 1);
1262 setLineGeometry(elidedLine, lineWidth, height);
1264 elideLayout->endLayout();
1266 br = br.united(elidedLine.naturalTextRect());
1268 if (visibleCount == 1)
1269 layout.clearLayout();
1271 elideLayout.reset();
1276 if (extra.isAllocated()) {
1277 extra->visibleImgTags.clear();
1278 const int mainLineCount = elide ? visibleCount - 1 : visibleCount;
1279 for (
int i = 0; i < mainLineCount; ++i)
1280 positionInlineImages(layout.lineAt(i), layout.formats());
1282 positionInlineImages(elideLayout->lineAt(0), elideLayout->formats());
1285 QTextLine firstLine = visibleCount == 1 && elideLayout
1286 ? elideLayout->lineAt(0)
1288 if (firstLine.isValid())
1289 *baseline = firstLine.y() + firstLine.ascent();
1292 br.setHeight(height);
1295 if (lineCount != visibleCount) {
1296 lineCount = visibleCount;
1297 emit q->lineCountChanged();
1300 if (truncated != wasTruncated)
1301 emit q->truncatedChanged();
2596QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
2601 if (d->text.isEmpty()) {
2602 d->containsUnscalableGlyphs =
false;
2607 if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode !=
nullptr) {
2609 d->updateType = QQuickTextPrivate::UpdateNone;
2613 d->updateType = QQuickTextPrivate::UpdateNone;
2615 const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding();
2617 QSGInternalTextNode *node =
nullptr;
2619 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2621 node =
static_cast<QSGInternalTextNode *>(oldNode);
2623 node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
2625 node->setTextStyle(QSGTextNode::TextStyle(d->style));
2626 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2627 node->setRenderTypeQuality(d->renderTypeQuality());
2629 node->setMatrix(QMatrix4x4());
2631 node->setColor(QColor::fromRgba(d->color));
2632 node->setStyleColor(QColor::fromRgba(d->styleColor));
2633 node->setLinkColor(QColor::fromRgba(d->linkColor));
2635 node->setDevicePixelRatio(d->effectiveDevicePixelRatio());
2638 node->setViewport(clipRect());
2639 const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding();
2641 node->addTextDocument(QPointF(dx, dy), d->extra->doc);
2642 }
else if (d->layedOutTextRect.width() > 0) {
2643 if (flags().testFlag(ItemObservesViewport))
2644 node->setViewport(clipRect());
2646 node->setViewport(QRectF{});
2647 const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding();
2648 int unelidedLineCount = d->lineCount;
2650 unelidedLineCount -= 1;
2651 if (unelidedLineCount > 0)
2652 node->addTextLayout(QPointF(dx, dy), &d->layout, -1, -1,0, unelidedLineCount);
2655 node->addTextLayout(QPointF(dx, dy), d->elideLayout.get());
2657 if (d->extra.isAllocated()) {
2658 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
2659 if (img->pix && img->pix->isReady())
2660 node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, img->size.width(), img->size.height()), img->pix->image());
2665 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2669 invalidateFontCaches();