436void QQuickTextPrivate::updateSize()
440 if (!q->isComponentComplete()) {
441 updateOnComponentComplete =
true;
445 if (!requireImplicitSize) {
446 implicitWidthChanged();
447 implicitHeightChanged();
449 if (requireImplicitSize)
453 qreal hPadding = q->leftPadding() + q->rightPadding();
454 qreal vPadding = q->topPadding() + q->bottomPadding();
456 const QSizeF previousSize(q->contentWidth(), q->contentHeight());
458 if (text.isEmpty() && !isLineLaidOutConnected() && fontSizeMode() == QQuickText::FixedSize) {
463 QFontMetricsF fm(font);
464 qreal fontHeight = qCeil(fm.height());
466 fontHeight = lineHeightMode() == QQuickText::FixedHeight
468 : fontHeight * lineHeight();
470 updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding);
471 q->setImplicitSize(hPadding, fontHeight + qMax(lineHeightOffset(), 0) + vPadding);
472 layedOutTextRect = QRectF(0, 0, 0, fontHeight);
474 signalSizeChange(previousSize);
476 emit q->lineCountChanged();
479 emit q->truncatedChanged();
481 updateType = UpdatePaintNode;
491 QRectF textRect = setupTextLayout(&baseline);
493 if (internalWidthUpdate)
496 layedOutTextRect = textRect;
497 size = textRect.size();
498 updateBaseline(baseline, q->height() - size.height() - vPadding);
500 widthExceeded =
true;
501 heightExceeded =
false;
503 extra->doc->setDefaultFont(font);
504 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
505 if (rightToLeftText) {
506 if (horizontalAlignment == QQuickText::AlignLeft)
507 horizontalAlignment = QQuickText::AlignRight;
508 else if (horizontalAlignment == QQuickText::AlignRight)
509 horizontalAlignment = QQuickText::AlignLeft;
512 option.setAlignment((Qt::Alignment)
int(horizontalAlignment | vAlign));
513 option.setWrapMode(QTextOption::WrapMode(wrapMode));
514 option.setUseDesignMetrics(renderType != QQuickText::NativeRendering);
515 extra->doc->setDefaultTextOption(option);
516 qreal naturalWidth = 0;
517 if (requireImplicitSize) {
518 extra->doc->setTextWidth(-1);
519 naturalWidth = extra->doc->idealWidth();
520 const bool wasInLayout = internalWidthUpdate;
521 internalWidthUpdate =
true;
522 q->setImplicitWidth(naturalWidth + hPadding);
523 internalWidthUpdate = wasInLayout;
525 if (internalWidthUpdate)
528 extra->doc->setPageSize(QSizeF(q->width(), -1));
529 if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
530 extra->doc->setTextWidth(availableWidth());
532 extra->doc->setTextWidth(extra->doc->idealWidth());
534 QSizeF dsize = extra->doc->size();
535 layedOutTextRect = QRectF(QPointF(0,0), dsize);
536 size = QSizeF(extra->doc->idealWidth(),dsize.height());
539 qreal baseline = QFontMetricsF(font).ascent();
540 QTextBlock firstBlock = extra->doc->firstBlock();
541 if (firstBlock.isValid() && firstBlock.layout() !=
nullptr && firstBlock.lineCount() > 0)
542 baseline = firstBlock.layout()->lineAt(0).ascent();
544 updateBaseline(baseline, q->height() - size.height() - vPadding);
547 internalWidthUpdate =
true;
548 qreal oldWidth = q->width();
550 if (!q->widthValid())
551 iWidth = size.width();
553 q->setImplicitSize(iWidth + hPadding, size.height() + qMax(lineHeightOffset(), 0) + vPadding);
554 internalWidthUpdate =
false;
561 if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
562 updateSizeRecursionGuard =
true;
564 updateSizeRecursionGuard =
false;
567 q->setImplicitHeight(size.height() + lineHeightOffset() + vPadding);
569 QTextBlock firstBlock = extra->doc->firstBlock();
570 while (firstBlock.layout()->lineCount() == 0)
571 firstBlock = firstBlock.next();
573 QTextBlock lastBlock = extra->doc->lastBlock();
574 while (lastBlock.layout()->lineCount() == 0)
575 lastBlock = lastBlock.previous();
577 if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
578 QTextLine firstLine = firstBlock.layout()->lineAt(0);
579 QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
580 advance = QSizeF(lastLine.horizontalAdvance(),
581 (lastLine.y() + lastBlock.layout()->position().y() + lastLine.ascent()) - (firstLine.y() + firstBlock.layout()->position().y() + firstLine.ascent()));
588 signalSizeChange(previousSize);
589 updateType = UpdatePaintNode;
794QRectF QQuickTextPrivate::setupTextLayout(qreal *
const baseline)
798 bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
799 bool multilineElide = elideMode == QQuickText::ElideRight
801 && (q->heightValid() || maximumLineCountValid);
803 if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid))
804 && ((singlelineElide && availableWidth() <= 0.)
805 || (multilineElide && q->heightValid() && availableHeight() <= 0.))) {
807 widthExceeded = q->widthValid() && availableWidth() <= 0.;
808 heightExceeded = q->heightValid() && availableHeight() <= 0.;
812 emit q->truncatedChanged();
816 q->setFlag(QQuickItem::ItemObservesViewport,
false);
817 emit q->lineCountChanged();
820 if (qFuzzyIsNull(q->width())) {
821 layout.setText(QString());
822 textHasChanged =
true;
825 QFontMetricsF fm(font);
826 qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : qCeil(fm.height()) * lineHeight();
827 *baseline = fm.ascent();
828 return QRectF(0, 0, 0, height);
831 bool shouldUseDesignMetrics = renderType != QQuickText::NativeRendering;
832 layout.setCacheEnabled(
true);
833 QTextOption textOption = layout.textOption();
834 if (textOption.alignment() != q->effectiveHAlign()
835 || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
836 || textOption.useDesignMetrics() != shouldUseDesignMetrics) {
837 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
838 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
839 textOption.setUseDesignMetrics(shouldUseDesignMetrics);
840 layout.setTextOption(textOption);
842 if (layout.font() != font)
843 layout.setFont(font);
845 lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
848 qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
850 const bool customLayout = isLineLaidOutConnected();
851 const bool wasTruncated = truncated;
853 bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
855 bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
856 bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
857 && (q->heightValid() || (maximumLineCountValid && canWrap));
859 const bool pixelSize = font.pixelSize() != -1;
860 QString layoutText = layout.text();
862 const qreal minimumSize = pixelSize
863 ?
static_cast<qreal>(minimumPixelSize())
864 : minimumPointSize();
865 qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
866 qreal smallFont = fontSizeMode() != QQuickText::FixedSize
867 ? qMin<qreal>(minimumSize, largeFont)
869 qreal scaledFontSize = largeFont;
870 const qreal sizeFittingThreshold(0.01);
872 bool widthChanged =
false;
873 widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
874 heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit);
878 QFont scaledFont = font;
880 int visibleCount = 0;
887 bool noBreakLastLine = multilineElide && (wrapMode == QQuickText::Wrap || wrapMode == QQuickText::WordWrap);
889 int eos = multilengthEos;
897 scaledFont.setPixelSize(scaledFontSize);
899 scaledFont.setPointSizeF(scaledFontSize);
900 if (layout.font() != scaledFont)
901 layout.setFont(scaledFont);
904 layout.beginLayout();
906 bool wrapped =
false;
907 bool truncateHeight =
false;
910 int unwrappedLineCount = 1;
911 const int maxLineCount = maximumLineCount();
913 qreal naturalHeight = 0;
914 qreal previousHeight = 0;
919 for (visibleCount = 1; ; ++visibleCount) {
920 line = layout.createLine();
922 if (noBreakLastLine && visibleCount == maxLineCount)
923 layout.engine()->option.setWrapMode(QTextOption::WrapAnywhere);
925 setupCustomLineGeometry(line, naturalHeight, layoutText.size());
927 setLineGeometry(line, lineWidth, naturalHeight);
929 if (noBreakLastLine && visibleCount == maxLineCount)
930 layout.engine()->option.setWrapMode(QTextOption::WrapMode(wrapMode));
932 unelidedRect = br.united(line.naturalTextRect());
936 if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
938 heightExceeded =
true;
943 truncateHeight =
true;
947 const QTextLine previousLine = layout.lineAt(visibleCount - 1);
948 elideText = elidedText(line.width(), previousLine);
949 elideStart = previousLine.textStart();
950 elideEnd = line.textStart() + line.textLength();
952 height = previousHeight;
956 const bool isLastLine = line.textStart() + line.textLength() >= layoutText.size();
958 if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > line.width()) {
961 widthExceeded =
true;
966 elideText = layout.engine()->elidedText(
967 Qt::TextElideMode(elideMode),
968 QFixed::fromReal(line.width()),
972 elideStart = line.textStart();
973 elideEnd = elideStart + line.textLength();
976 height = naturalHeight;
980 const bool wrappedLine = layoutText.at(line.textStart() + line.textLength() - 1) != QChar::LineSeparator;
981 wrapped |= wrappedLine;
984 ++unwrappedLineCount;
987 if (visibleCount == maxLineCount) {
989 heightExceeded |= wrapped;
991 if (multilineElide) {
996 elideText = elidedText(line.width(), line);
997 elideStart = line.textStart();
998 elideEnd = elideStart + line.textLength();
1001 height = naturalHeight;
1007 previousHeight = height;
1008 height = naturalHeight;
1010 widthExceeded |= wrapped;
1018 if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
1021 for (
int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1022 line = layout.createLine();
1023 if (!line.isValid())
1025 if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
1026 ++unwrappedLineCount;
1027 setLineGeometry(line, lineWidth, naturalHeight);
1032 const int eol = line.isValid()
1033 ? line.textStart() + line.textLength()
1034 : layoutText.size();
1035 if (eol < layoutText.size() && layoutText.at(eol) != QChar::LineSeparator)
1036 line = layout.createLine();
1037 for (; line.isValid() && unwrappedLineCount < maxLineCount; ++unwrappedLineCount)
1038 line = layout.createLine();
1043 const qreal naturalWidth = layout.maximumWidth();
1045 bool wasInLayout = internalWidthUpdate;
1046 internalWidthUpdate =
true;
1047 q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1048 internalWidthUpdate = wasInLayout;
1051 singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
1052 multilineElide = elideMode == QQuickText::ElideRight
1054 && (q->heightValid() || maximumLineCountValid);
1055 canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
1057 horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
1058 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1059 && (q->heightValid() || (maximumLineCountValid && canWrap));
1061 const qreal oldWidth = lineWidth;
1062 const qreal oldHeight = maxHeight;
1064 const qreal availWidth = availableWidth();
1065 const qreal availHeight = availableHeight();
1067 lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
1068 maxHeight = q->heightValid() ? availHeight : FLT_MAX;
1072 if ((!qFuzzyCompare(lineWidth, oldWidth) || (widthExceeded && lineWidth > oldWidth))
1073 && (singlelineElide || multilineElide || canWrap || horizontalFit
1074 || q->effectiveHAlign() != QQuickText::AlignLeft)) {
1075 widthChanged =
true;
1076 widthExceeded = lineWidth >= qMin(oldWidth, naturalWidth);
1077 heightExceeded =
false;
1083 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1084 && (multilineElide || (canWrap && maximumLineCountValid))) {
1085 widthExceeded =
false;
1086 heightExceeded =
false;
1092 if (!q->widthValid() && !implicitWidthValid && unwrappedLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
1093 widthExceeded =
false;
1094 heightExceeded =
false;
1097 }
else if (widthChanged) {
1098 widthChanged =
false;
1099 if (line.isValid()) {
1100 for (
int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1101 line = layout.createLine();
1102 if (!line.isValid())
1104 setLineGeometry(line, lineWidth, naturalHeight);
1109 bool wasInLayout = internalWidthUpdate;
1110 internalWidthUpdate =
true;
1111 q->setImplicitHeight(naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1112 internalWidthUpdate = wasInLayout;
1114 multilineElide = elideMode == QQuickText::ElideRight
1116 && (q->heightValid() || maximumLineCountValid);
1117 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1118 && (q->heightValid() || (maximumLineCountValid && canWrap));
1120 const qreal oldHeight = maxHeight;
1121 maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
1124 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1125 && (multilineElide || (canWrap && maximumLineCountValid))) {
1126 widthExceeded =
false;
1127 heightExceeded =
false;
1136 if (eos != -1 && elide) {
1137 int start = eos + 1;
1138 eos = text.indexOf(QLatin1Char(
'\x9c'), start);
1139 layoutText = text.mid(start, eos != -1 ? eos - start : -1);
1140 layoutText.replace(QLatin1Char(
'\n'), QChar::LineSeparator);
1141 layout.setText(layoutText);
1142 textHasChanged =
true;
1149 if (layout.lineCount() > 0) {
1150 QTextLine firstLine = layout.lineAt(0);
1151 QTextLine lastLine = layout.lineAt(layout.lineCount() - 1);
1152 advance = QSizeF(lastLine.horizontalAdvance(),
1153 lastLine.y() - firstLine.y());
1158 if (!horizontalFit && !verticalFit)
1162 if (qFuzzyCompare(smallFont, largeFont))
1166 if (horizontalFit) {
1167 if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
1168 widthExceeded =
true;
1169 largeFont = scaledFontSize;
1171 scaledFontSize = (smallFont + largeFont) / 2;
1174 }
else if (!verticalFit) {
1175 smallFont = scaledFontSize;
1178 if ((largeFont - smallFont) < sizeFittingThreshold)
1181 scaledFontSize = (smallFont + largeFont) / 2;
1186 if (truncateHeight || unelidedRect.height() > maxHeight) {
1187 heightExceeded =
true;
1188 largeFont = scaledFontSize;
1190 scaledFontSize = (smallFont + largeFont) / 2;
1193 smallFont = scaledFontSize;
1196 if ((largeFont - smallFont) < sizeFittingThreshold)
1199 scaledFontSize = (smallFont + largeFont) / 2;
1204 implicitWidthValid =
true;
1205 implicitHeightValid =
true;
1207 QFontInfo scaledFontInfo(scaledFont);
1208 if (fontInfo.weight() != scaledFontInfo.weight()
1209 || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
1210 || fontInfo.italic() != scaledFontInfo.italic()
1211 || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
1212 || fontInfo.family() != scaledFontInfo.family()
1213 || fontInfo.styleName() != scaledFontInfo.styleName()) {
1214 fontInfo = scaledFontInfo;
1215 emit q->fontInfoChanged();
1218 if (eos != multilengthEos)
1221 assignedFont = QFontInfo(font).family();
1225 elideLayout.reset(
new QTextLayout);
1226 elideLayout->setCacheEnabled(
true);
1228 QTextEngine *engine = layout.engine();
1229 if (engine && engine->hasFormats()) {
1230 QList<QTextLayout::FormatRange> formats;
1231 switch (elideMode) {
1232 case QQuickText::ElideRight:
1233 elideFormats(elideStart, elideText.size() - 1, 0, &formats);
1235 case QQuickText::ElideLeft:
1236 elideFormats(elideEnd - elideText.size() + 1, elideText.size() - 1, 1, &formats);
1238 case QQuickText::ElideMiddle: {
1239 const int index = elideText.indexOf(elideChar);
1241 elideFormats(elideStart, index, 0, &formats);
1243 elideEnd - elideText.size() + index + 1,
1244 elideText.size() - index - 1,
1253 elideLayout->setFormats(formats);
1256 elideLayout->setFont(layout.font());
1257 elideLayout->setTextOption(layout.textOption());
1258 elideLayout->setText(elideText);
1259 elideLayout->beginLayout();
1261 QTextLine elidedLine = elideLayout->createLine();
1262 elidedLine.setPosition(QPointF(0, height));
1264 setupCustomLineGeometry(elidedLine, height, elideText.size(), visibleCount - 1);
1266 setLineGeometry(elidedLine, lineWidth, height);
1268 elideLayout->endLayout();
1270 br = br.united(elidedLine.naturalTextRect());
1272 if (visibleCount == 1)
1273 layout.clearLayout();
1275 elideLayout.reset();
1280 if (extra.isAllocated()) {
1281 extra->visibleImgTags.clear();
1282 const int mainLineCount = elide ? visibleCount - 1 : visibleCount;
1283 for (
int i = 0; i < mainLineCount; ++i)
1284 positionInlineImages(layout.lineAt(i), layout.formats());
1286 positionInlineImages(elideLayout->lineAt(0), elideLayout->formats());
1289 QTextLine firstLine = visibleCount == 1 && elideLayout
1290 ? elideLayout->lineAt(0)
1292 if (firstLine.isValid())
1293 *baseline = firstLine.y() + firstLine.ascent();
1296 br.setHeight(height);
1299 if (lineCount != visibleCount) {
1300 lineCount = visibleCount;
1301 emit q->lineCountChanged();
1304 if (truncated != wasTruncated)
1305 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 QSGInternalTextNode::RecycleBin recycleBin;
2630 node->recycle(&recycleBin);
2631 node->setMatrix(QMatrix4x4());
2633 node->setColor(QColor::fromRgba(d->color));
2634 node->setStyleColor(QColor::fromRgba(d->styleColor));
2635 node->setLinkColor(QColor::fromRgba(d->linkColor));
2637 node->setDevicePixelRatio(d->effectiveDevicePixelRatio());
2640 node->setViewport(clipRect());
2641 const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding();
2643 node->addTextDocument(QPointF(dx, dy), d->extra->doc, &recycleBin);
2644 }
else if (d->layedOutTextRect.width() > 0) {
2645 if (flags().testFlag(ItemObservesViewport))
2646 node->setViewport(clipRect());
2648 node->setViewport(QRectF{});
2649 const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding();
2650 int unelidedLineCount = d->lineCount;
2652 unelidedLineCount -= 1;
2653 if (unelidedLineCount > 0)
2654 node->addTextLayout(QPointF(dx, dy), &d->layout, &recycleBin, -1, -1,0, unelidedLineCount);
2657 node->addTextLayout(QPointF(dx, dy), d->elideLayout.get(), &recycleBin);
2659 if (d->extra.isAllocated()) {
2660 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
2661 if (img->pix && img->pix->isReady()) {
2662 node->addImage(QRectF(img->pos.x() + dx,
2665 img->size.height()),
2673 d->containsUnscalableGlyphs = node->containsUnscalableGlyphs();
2677 invalidateFontCaches();
2679 node->discardUnusedNodes(&recycleBin);