aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew den Exter <andrew.den-exter@nokia.com>2012-06-07 15:56:16 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-09 01:34:54 +0200
commit3095493a4ce4bec11b9381a3d1d23f17b313332c (patch)
tree2869549eec623e38d8915c58592a235671f7a387
parentd65b660d5d7f30058efc74c7cab074641923038f (diff)
Reduce the number of unnecessary layouts on geometry changes.
Improve checks for geometry changes that don't affect layout, i.e width increasing when the previous layout didn't wrap or elide. Set implicit sizes just once during layout rather than setting the implicit width during and the implicit height after to limit the when an implicit size change can change geometry. And if there are multiple layouts of the same text/font combination re-use cached layout data as much as possible by guarding against unnecessary property changes on the layout, and not creating a new layout for calculating the implicit size of truncated text. Change-Id: Ia05e52e9170e1f5d3364896ab119e00d8a318299 Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
-rw-r--r--src/quick/items/qquicktext.cpp355
-rw-r--r--src/quick/items/qquicktext_p_p.h12
-rw-r--r--src/quick/items/qquicktextutil.cpp12
-rw-r--r--src/quick/items/qquicktextutil_p.h5
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp260
5 files changed, 505 insertions, 139 deletions
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index b19b13fec2..fa5652141c 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -78,6 +78,7 @@ QQuickTextPrivate::QQuickTextPrivate()
#if defined(Q_OS_MAC)
, layoutThread(0), paintingThread(0)
#endif
+ , lineWidth(0)
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
, lineCount(1), multilengthEos(-1)
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
@@ -85,7 +86,8 @@ QQuickTextPrivate::QQuickTextPrivate()
, style(QQuickText::Normal)
, updateType(UpdatePaintNode)
, maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
- , styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false)
+ , styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
+ , requireImplicitSize(false), implicitWidthValid(false), implicitHeightValid(false)
, truncated(false), hAlignImplicit(true), rightToLeftText(false)
, layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
{
@@ -278,16 +280,26 @@ QQuickTextPrivate::~QQuickTextPrivate()
qreal QQuickTextPrivate::getImplicitWidth() const
{
- if (!requireImplicitWidth) {
+ if (!requireImplicitSize) {
// We don't calculate implicitWidth unless it is required.
// We need to force a size update now to ensure implicitWidth is calculated
QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
- me->requireImplicitWidth = true;
+ me->requireImplicitSize = true;
me->updateSize();
}
return implicitWidth;
}
+qreal QQuickTextPrivate::getImplicitHeight() const
+{
+ if (!requireImplicitSize) {
+ QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
+ me->requireImplicitSize = true;
+ me->updateSize();
+ }
+ return implicitHeight;
+}
+
void QQuickText::q_imagesLoaded()
{
Q_D(QQuickText);
@@ -409,10 +421,11 @@ void QQuickTextPrivate::updateSize()
return;
}
- if (!requireImplicitWidth) {
+ if (!requireImplicitSize) {
emit q->implicitWidthChanged();
+ emit q->implicitHeightChanged();
// if the implicitWidth is used, then updateSize() has already been called (recursively)
- if (requireImplicitWidth)
+ if (requireImplicitSize)
return;
}
@@ -437,8 +450,6 @@ void QQuickTextPrivate::updateSize()
return;
}
- qreal naturalWidth = 0;
-
QSizeF size(0, 0);
QSizeF previousSize = layedOutTextRect.size();
#if defined(Q_OS_MAC)
@@ -448,7 +459,7 @@ void QQuickTextPrivate::updateSize()
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
qreal baseline = 0;
- QRectF textRect = setupTextLayout(&naturalWidth, &baseline);
+ QRectF textRect = setupTextLayout(&baseline);
if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
return; // get this far we'll get a warning to that effect if it is.
@@ -457,7 +468,8 @@ void QQuickTextPrivate::updateSize()
size = textRect.size();
updateBaseline(baseline, q->height() - size.height());
} else {
- singleline = false; // richtext can't elide or be optimized for single-line case
+ widthExceeded = true; // always relayout rich text on width changes..
+ heightExceeded = false; // rich text layout isn't affected by height changes.
ensureDoc();
extra->doc->setDefaultFont(font);
QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
@@ -472,7 +484,8 @@ void QQuickTextPrivate::updateSize()
option.setWrapMode(QTextOption::WrapMode(wrapMode));
option.setUseDesignMetrics(true);
extra->doc->setDefaultTextOption(option);
- if (requireImplicitWidth && q->widthValid()) {
+ qreal naturalWidth = 0;
+ if (requireImplicitSize && q->widthValid()) {
extra->doc->setTextWidth(-1);
naturalWidth = extra->doc->idealWidth();
const bool wasInLayout = internalWidthUpdate;
@@ -486,25 +499,27 @@ void QQuickTextPrivate::updateSize()
extra->doc->setTextWidth(q->width());
else
extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+ widthExceeded = extra->doc->textWidth() < extra->doc->idealWidth();
QSizeF dsize = extra->doc->size();
layedOutTextRect = QRectF(QPointF(0,0), dsize);
size = QSizeF(extra->doc->idealWidth(),dsize.height());
QFontMetricsF fm(font);
updateBaseline(fm.ascent(), q->height() - size.height());
- }
- //### need to comfirm cost of always setting these for richText
- internalWidthUpdate = true;
- qreal iWidth = -1;
- if (!q->widthValid())
- iWidth = size.width();
- if (iWidth > -1)
- q->setImplicitSize(iWidth, size.height());
- internalWidthUpdate = false;
+ //### need to confirm cost of always setting these for richText
+ internalWidthUpdate = true;
+ qreal iWidth = -1;
+ if (!q->widthValid())
+ iWidth = size.width();
+ if (iWidth > -1)
+ q->setImplicitSize(iWidth, size.height());
+ internalWidthUpdate = false;
+
+ if (iWidth == -1)
+ q->setImplicitHeight(size.height());
+ }
- if (iWidth == -1)
- q->setImplicitHeight(size.height());
if (layedOutTextRect.size() != previousSize)
emit q->contentSizeChanged();
updateType = UpdatePaintNode;
@@ -661,7 +676,6 @@ void QQuickTextPrivate::elideFormats(
QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const
{
if (nextLine) {
- nextLine->setLineWidth(INT_MAX);
return layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
QFixed::fromReal(lineWidth),
@@ -690,22 +704,21 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT
already absolutely positioned horizontally).
*/
-QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *const baseline)
+QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
{
Q_Q(QQuickText);
- layout.setCacheEnabled(true);
- QTextOption textOption = layout.textOption();
- textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
- textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
- textOption.setUseDesignMetrics(true);
- layout.setTextOption(textOption);
- layout.setFont(font);
-
- if (!requireImplicitWidth
- && ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
- || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight))) {
+ bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
+ bool multilineElide = elideMode == QQuickText::ElideRight
+ && q->widthValid()
+ && (q->heightValid() || maximumLineCountValid);
+
+ if ((!requireImplicitSize || (implicitWidthValid && implicitHeightValid))
+ && ((singlelineElide && q->width() <= 0.) || (multilineElide && q->heightValid() && q->height() <= 0.))) {
// we are elided and we have a zero width or height
+ widthExceeded = q->widthValid() && q->width() <= 0.;
+ heightExceeded = q->heightValid() && q->height() <= 0.;
+
if (!truncated) {
truncated = true;
emit q->truncatedChanged();
@@ -716,21 +729,32 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
}
QFontMetricsF fm(font);
- qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight();
+ qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : qCeil(fm.height()) * lineHeight();
*baseline = fm.ascent();
return QRectF(0, 0, 0, height);
}
- qreal lineWidth = q->widthValid() && q->width() > 0 ? q->width() : FLT_MAX;
- const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+ layout.setCacheEnabled(true);
+ QTextOption textOption = layout.textOption();
+ if (textOption.alignment() != q->effectiveHAlign()
+ || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
+ || !textOption.useDesignMetrics()) {
+ textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
+ textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
+ textOption.setUseDesignMetrics(true);
+ layout.setTextOption(textOption);
+ }
+ if (layout.font() != font)
+ layout.setFont(font);
+
+ lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
+ ? q->width()
+ : FLT_MAX;
+ qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX;
const bool customLayout = isLineLaidOutConnected();
const bool wasTruncated = truncated;
- bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
- bool multilineElide = elideMode == QQuickText::ElideRight
- && q->widthValid()
- && (q->heightValid() || maximumLineCountValid);
bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
@@ -746,11 +770,13 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
: largeFont;
int scaledFontSize = largeFont;
+ widthExceeded = q->width() <= 0 && (singlelineElide || canWrap || horizontalFit);
+ heightExceeded = q->height() <= 0 && (multilineElide || verticalFit);
+
QRectF br;
QFont scaledFont = font;
- QTextLine line;
int visibleCount = 0;
bool elide;
qreal height = 0;
@@ -759,19 +785,19 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
int elideStart = 0;
int elideEnd = 0;
- *naturalWidth = 0;
-
int eos = multilengthEos;
// Repeated layouts with reduced font sizes or abbreviated strings may be required if the text
- // doesn't fit within the element dimensions.
+ // doesn't fit within the item dimensions, or a binding to implicitWidth/Height changes
+ // the item dimensions.
for (;;) {
if (!once) {
if (pixelSize)
scaledFont.setPixelSize(scaledFontSize);
else
scaledFont.setPointSize(scaledFontSize);
- layout.setFont(scaledFont);
+ if (layout.font() != scaledFont)
+ layout.setFont(scaledFont);
}
layout.beginLayout();
@@ -784,27 +810,31 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
int unwrappedLineCount = 1;
int maxLineCount = maximumLineCount();
height = 0;
+ qreal naturalHeight = 0;
+ qreal previousHeight = 0;
br = QRectF();
- line = layout.createLine();
- for (visibleCount = 1; ; ++visibleCount) {
- qreal preLayoutHeight = height;
+ QRectF unelidedRect;
+ QTextLine line = layout.createLine();
+ for (visibleCount = 1; ; ++visibleCount) {
if (customLayout) {
- setupCustomLineGeometry(line, height);
+ setupCustomLineGeometry(line, naturalHeight);
} else {
- setLineGeometry(line, lineWidth, height);
+ setLineGeometry(line, lineWidth, naturalHeight);
}
+ unelidedRect = br.united(line.naturalTextRect());
+
// Elide the previous line if the accumulated height of the text exceeds the height
// of the element.
- if (multilineElide && height > maxHeight && visibleCount > 1) {
+ if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
elide = true;
+ heightExceeded = true;
if (eos != -1) // There's an abbreviated string available, skip the rest as it's
break; // all going to be discarded.
truncated = true;
truncateHeight = true;
- height = preLayoutHeight;
characterCount = line.textStart() + line.textLength();
visibleCount -= 1;
@@ -816,36 +846,37 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
elideStart = previousLine.textStart();
// elideEnd isn't required for right eliding.
- line = previousLine;
- height -= (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : previousLine.height() * lineHeight();
+ height = previousHeight;
break;
}
- QTextLine nextLine = layout.createLine();
- if (!nextLine.isValid()) {
- characterCount = line.textStart() + line.textLength();
- if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > lineWidth) {
- // Elide a single line of text if its width exceeds the element width.
+ const QTextLine previousLine = line;
+ line = layout.createLine();
+ if (!line.isValid()) {
+ characterCount = previousLine.textStart() + previousLine.textLength();
+ if (singlelineElide && visibleCount == 1 && previousLine.naturalTextWidth() > lineWidth) {
+ // Elide a single previousLine of text if its width exceeds the element width.
elide = true;
+ widthExceeded = true;
if (eos != -1) // There's an abbreviated string available.
break;
truncated = true;
- height = preLayoutHeight;
elideText = layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
QFixed::fromReal(lineWidth),
0,
- line.textStart(),
- line.textLength());
- elideStart = line.textStart();
- elideEnd = elideStart + line.textLength();
+ previousLine.textStart(),
+ previousLine.textLength());
+ elideStart = previousLine.textStart();
+ elideEnd = elideStart + previousLine.textLength();
} else {
- br = br.united(line.naturalTextRect());
+ br = unelidedRect;
+ height = naturalHeight;
}
break;
} else {
- const bool wrappedLine = layoutText.at(nextLine.textStart() - 1) != QChar::LineSeparator;
+ const bool wrappedLine = layoutText.at(line.textStart() - 1) != QChar::LineSeparator;
wrapped |= wrappedLine;
if (!wrappedLine)
@@ -855,58 +886,66 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
// if enabled.
if (visibleCount == maxLineCount) {
truncated = true;
- characterCount = nextLine.textStart() + nextLine.textLength();
+ heightExceeded |= wrapped;
+ characterCount = line.textStart() + line.textLength();
if (multilineElide) {
elide = true;
if (eos != -1) // There's an abbreviated string available
break;
- height = preLayoutHeight;
elideText = wrappedLine
- ? elidedText(lineWidth, line, &nextLine)
- : elidedText(lineWidth, line);
- elideStart = line.textStart();
+ ? elidedText(lineWidth, previousLine, &line)
+ : elidedText(lineWidth, previousLine);
+ elideStart = previousLine.textStart();
// elideEnd isn't required for right eliding.
} else {
- br = br.united(line.naturalTextRect());
+ br = unelidedRect;
+ height = naturalHeight;
}
break;
}
}
- br = br.united(line.naturalTextRect());
- line = nextLine;
+ br = unelidedRect;
+ previousHeight = height;
+ height = naturalHeight;
}
- layout.endLayout();
- br.moveTop(0);
+ widthExceeded |= wrapped;
- // Save the implicitWidth of the text on the first layout only.
+ // Save the implicit size of the text on the first layout only.
if (once) {
- *naturalWidth = layout.maximumWidth();
once = false;
- if (requireImplicitWidth
- && characterCount < layoutText.length()
- && unwrappedLineCount < maxLineCount) {
- // Use a new layout to get the maximum width for the remaining text. Using a
- // different layout excludes the truncated text from rendering.
- QTextLayout widthLayout(layoutText.mid(characterCount), scaledFont);
- widthLayout.setTextOption(layout.textOption());
-
- widthLayout.beginLayout();
- for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) {
- QTextLine line = widthLayout.createLine();
+ // If implicit sizes are required layout any additional lines up to the maximum line
+ // count.
+ if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
+ // Layout the remainder of the wrapped lines up to maxLineCount to get the implicit
+ // height.
+ for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
+ line = layout.createLine();
if (!line.isValid())
break;
+ if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
+ ++unwrappedLineCount;
+ setLineGeometry(line, lineWidth, naturalHeight);
}
- widthLayout.endLayout();
- *naturalWidth = qMax(*naturalWidth, widthLayout.maximumWidth());
+
+ // Create the remainder of the unwrapped lines up to maxLineCount to get the
+ // implicit width.
+ if (line.isValid() && layoutText.at(line.textStart() + line.textLength()) != QChar::LineSeparator)
+ line = layout.createLine();
+ for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
+ line = layout.createLine();
}
+ layout.endLayout();
+
+ const qreal naturalWidth = layout.maximumWidth();
bool wasInLayout = internalWidthUpdate;
internalWidthUpdate = true;
- q->setImplicitWidth(*naturalWidth);
+ q->setImplicitSize(naturalWidth, naturalHeight);
internalWidthUpdate = wasInLayout;
+ // Update any variables that are dependent on the validity of the width or height.
singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
multilineElide = elideMode == QQuickText::ElideRight
&& q->widthValid()
@@ -918,13 +957,38 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
&& (q->heightValid() || (maximumLineCountValid && canWrap));
const qreal oldWidth = lineWidth;
- lineWidth = q->widthValid() && q->width() > 0 ? q->width() : *naturalWidth;
- if (lineWidth != oldWidth && (singlelineElide || multilineElide || canWrap || horizontalFit))
+ const qreal oldHeight = maxHeight;
+
+ lineWidth = q->widthValid() && q->width() > 0 ? q->width() : naturalWidth;
+ maxHeight = q->heightValid() ? q->height() : FLT_MAX;
+
+ // If the width of the item has changed and it's possible the result of wrapping,
+ // eliding, or scaling has changed do another layout.
+ if ((lineWidth < qMin(oldWidth, naturalWidth) || (widthExceeded && lineWidth > oldWidth))
+ && (singlelineElide || multilineElide || canWrap || horizontalFit)) {
+ widthExceeded = false;
+ heightExceeded = false;
+ continue;
+ }
+
+ // If the height of the item has changed and it's possible the result of eliding,
+ // line count truncation or scaling has changed, do another layout.
+ if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
+ && (multilineElide || (canWrap && maximumLineCountValid))) {
+ widthExceeded = false;
+ heightExceeded = false;
continue;
+ }
+
// If the horizontal alignment is not left and the width was not valid we need to relayout
// now that we know the maximum line width.
- if (!q->widthValid() && maxLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft)
+ if (!implicitWidthValid && lineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
+ widthExceeded = false;
+ heightExceeded = false;
continue;
+ }
+ } else {
+ layout.endLayout();
}
// If the next needs to be elided and there's an abbreviated string available
@@ -939,14 +1003,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
continue;
}
+ br.moveTop(0);
+
if (!horizontalFit && !verticalFit)
break;
// Try and find a font size that better fits the dimensions of the element.
- QRectF unelidedRect = br.united(line.naturalTextRect());
-
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
+ widthExceeded = true;
largeFont = scaledFontSize - 1;
if (smallFont > largeFont)
break;
@@ -966,6 +1031,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
+ heightExceeded = true;
largeFont = scaledFontSize - 1;
if (smallFont > largeFont)
break;
@@ -980,6 +1046,9 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
}
}
+ implicitWidthValid = true;
+ implicitHeightValid = true;
+
if (eos != multilengthEos)
truncated = true;
@@ -1023,7 +1092,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth, qreal *cons
QTextLine elidedLine = elideLayout->createLine();
elidedLine.setPosition(QPointF(0, height));
if (customLayout) {
- setupCustomLineGeometry(elidedLine, height, line.lineNumber());
+ setupCustomLineGeometry(elidedLine, height, visibleCount - 1);
} else {
setLineGeometry(elidedLine, lineWidth, height);
}
@@ -1389,6 +1458,8 @@ void QQuickText::setFont(const QFont &font)
// with headings or <font> tag, we need to re-parse
if (d->formatModifiesFontSize)
d->textHasChanged = true;
+ d->implicitWidthValid = false;
+ d->implicitHeightValid = false;
d->updateLayout();
}
@@ -1429,6 +1500,8 @@ void QQuickText::setText(const QString &n)
d->determineHorizontalAlignment();
}
d->textHasChanged = true;
+ d->implicitWidthValid = false;
+ d->implicitHeightValid = false;
qDeleteAll(d->imgTags);
d->imgTags.clear();
d->updateLayout();
@@ -1788,6 +1861,7 @@ void QQuickText::setMaximumLineCount(int lines)
d->maximumLineCountValid = lines==INT_MAX ? false : true;
if (d->maximumLineCount() != lines) {
d->extra.value().maximumLineCount = lines;
+ d->implicitHeightValid = false;
d->updateLayout();
emit maximumLineCountChanged();
}
@@ -2013,8 +2087,8 @@ QRectF QQuickText::boundingRect() const
Q_D(const QQuickText);
QRectF rect = d->layedOutTextRect;
- rect.moveLeft(QQuickTextUtil::alignedX(rect, width(), d->hAlign));
- rect.moveTop(QQuickTextUtil::alignedY(rect, height(), d->vAlign));
+ rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), d->hAlign));
+ rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign));
if (d->style != Normal)
rect.adjust(-1, 0, 1, 2);
@@ -2044,32 +2118,54 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
bool widthChanged = newGeometry.width() != oldGeometry.width();
bool heightChanged = newGeometry.height() != oldGeometry.height();
- bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
bool wrapped = d->wrapMode != QQuickText::NoWrap;
bool elide = d->elideMode != QQuickText::ElideNone;
bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
+ bool verticalScale = (d->fontSizeMode() & QQuickText::VerticalFit) && heightValid();
+
+ bool widthMaximum = newGeometry.width() >= oldGeometry.width() && !d->widthExceeded;
+ bool heightMaximum = newGeometry.height() >= oldGeometry.height() && !d->heightExceeded;
if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
goto geomChangeDone;
- if (leftAligned && !wrapped && !elide && !scaleFont)
- goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
+ if (effectiveHAlign() != QQuickText::AlignLeft && widthChanged) {
+ // If the width has changed and we're not left aligned do an update so the text is
+ // repositioned even if a full layout isn't required.
+ d->updateType = QQuickTextPrivate::UpdatePaintNode;
+ update();
+ }
- if (!widthChanged && !wrapped && d->singleline && !scaleFont)
- goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text
+ if (!wrapped && !elide && !scaleFont)
+ goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
- if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight && !scaleFont && !d->isLineLaidOutConnected())
- goto geomChangeDone; // only height changed and no multiline eliding.
+ if (elide // eliding and dimensions were and remain invalid;
+ && ((widthValid() && oldGeometry.width() <= 0 && newGeometry.width() <= 0)
+ || (heightValid() && oldGeometry.height() <= 0 && newGeometry.height() <= 0))) {
+ goto geomChangeDone;
+ }
- if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
- && !wrapped && newGeometry.width() > oldGeometry.width() && !scaleFont)
- goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.
+ if (widthMaximum && heightMaximum && !d->isLineLaidOutConnected()) // Size is sufficient and growing.
+ goto geomChangeDone;
- if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height() && !scaleFont) {
- if (!d->truncated)
- goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
- if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount())
- goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
+ if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
+ if (newGeometry.height() > oldGeometry.height()) {
+ if (!d->heightExceeded) // Height is adequate and growing.
+ goto geomChangeDone;
+ if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
+ goto geomChangeDone;
+ } else if (newGeometry.height() < oldGeometry.height()) {
+ if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
+ goto geomChangeDone;
+
+ if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+ && d->elideMode != QQuickText::ElideRight
+ && !(d->maximumLineCountValid && d->widthExceeded)) {
+ goto geomChangeDone;
+ }
+ }
+ } else if (!heightChanged && widthMaximum) {
+ goto geomChangeDone;
}
if (d->updateOnComponentComplete || d->textHasChanged) {
@@ -2110,7 +2206,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
d->updateType = QQuickTextPrivate::UpdateNone;
- const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect, height(), d->vAlign);
+ const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height(), height(), d->vAlign);
// We need to make sure the layout is done in the current thread
#if defined(Q_OS_MAC)
@@ -2134,29 +2230,30 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
const QColor linkColor = QColor::fromRgba(d->linkColor);
if (d->richText) {
+ const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), d->hAlign);
d->ensureDoc();
- const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect, width(), d->hAlign);
node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
- } else if (d->elideMode == QQuickText::ElideNone || d->layedOutTextRect.width() > 0.) {
+ } else if (d->layedOutTextRect.width() > 0) {
+ const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), d->hAlign);
int unelidedLineCount = d->lineCount;
if (d->elideLayout)
unelidedLineCount -= 1;
if (unelidedLineCount > 0) {
node->addTextLayout(
- QPoint(0, dy),
+ QPointF(dx, dy),
&d->layout,
color, d->style, styleColor, linkColor,
QColor(), QColor(), -1, -1,
0, unelidedLineCount);
}
if (d->elideLayout)
- node->addTextLayout(QPoint(0, dy), d->elideLayout, color, d->style, styleColor, linkColor);
- }
+ node->addTextLayout(QPointF(dx, dy), d->elideLayout, color, d->style, styleColor, linkColor);
- foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
- QQuickPixmap *pix = img->pix;
- if (pix && pix->isReady())
- node->addImage(QRectF(img->pos.x(), img->pos.y() + dy, pix->width(), pix->height()), pix->image());
+ foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
+ QQuickPixmap *pix = img->pix;
+ if (pix && pix->isReady())
+ node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, pix->width(), pix->height()), pix->image());
+ }
}
return node;
}
@@ -2214,6 +2311,7 @@ void QQuickText::setLineHeight(qreal lineHeight)
return;
d->extra.value().lineHeight = lineHeight;
+ d->implicitHeightValid = false;
d->updateLayout();
emit lineHeightChanged(lineHeight);
}
@@ -2242,6 +2340,7 @@ void QQuickText::setLineHeightMode(LineHeightMode mode)
if (mode == d->lineHeightMode())
return;
+ d->implicitHeightValid = false;
d->extra.value().lineHeightMode = mode;
d->updateLayout();
@@ -2400,14 +2499,14 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
{
Q_Q(const QQuickText);
QPointF translatedMousePos = mousePos;
- translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect, q->height(), vAlign);
+ translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect.height(), q->height(), vAlign);
if (styledText) {
QString link = anchorAt(&layout, translatedMousePos);
if (link.isEmpty() && elideLayout)
link = anchorAt(elideLayout, translatedMousePos);
return link;
} else if (richText && extra.isAllocated() && extra->doc) {
- translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect, q->width(), hAlign);
+ translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), hAlign);
return extra->doc->documentLayout()->anchorAt(translatedMousePos);
}
return QString();
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index 985b1e1c80..49d3580578 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -121,6 +121,8 @@ public:
QThread *paintingThread;
#endif
+ qreal lineWidth;
+
QRgb color;
QRgb linkColor;
QRgb styleColor;
@@ -146,9 +148,12 @@ public:
bool updateOnComponentComplete:1;
bool richText:1;
bool styledText:1;
- bool singleline:1;
+ bool widthExceeded:1;
+ bool heightExceeded:1;
bool internalWidthUpdate:1;
- bool requireImplicitWidth:1;
+ bool requireImplicitSize:1;
+ bool implicitWidthValid:1;
+ bool implicitHeightValid:1;
bool truncated:1;
bool hAlignImplicit:1;
bool rightToLeftText:1;
@@ -160,10 +165,11 @@ public:
static const QChar elideChar;
virtual qreal getImplicitWidth() const;
+ virtual qreal getImplicitHeight() const;
void ensureDoc();
- QRectF setupTextLayout(qreal *const naturalWidth, qreal * const baseline);
+ QRectF setupTextLayout(qreal * const baseline);
void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
bool isLinkActivatedConnected();
static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
diff --git a/src/quick/items/qquicktextutil.cpp b/src/quick/items/qquicktextutil.cpp
index 176301d450..151d72c6ee 100644
--- a/src/quick/items/qquicktextutil.cpp
+++ b/src/quick/items/qquicktextutil.cpp
@@ -78,7 +78,7 @@ QQuickItem *QQuickTextUtil::createCursor(
return item;
}
-qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
+qreal QQuickTextUtil::alignedX(const qreal textWidth, const qreal itemWidth, int alignment)
{
qreal x = 0;
switch (alignment) {
@@ -86,26 +86,26 @@ qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
case Qt::AlignJustify:
break;
case Qt::AlignRight:
- x = width - rect.width();
+ x = itemWidth - textWidth;
break;
case Qt::AlignHCenter:
- x = (width - rect.width()) / 2;
+ x = (itemWidth - textWidth) / 2;
break;
}
return x;
}
-qreal QQuickTextUtil::alignedY(const QRectF &rect, const qreal height, int alignment)
+qreal QQuickTextUtil::alignedY(const qreal textHeight, const qreal itemHeight, int alignment)
{
qreal y = 0;
switch (alignment) {
case Qt::AlignTop:
break;
case Qt::AlignBottom:
- y = height - rect.height();
+ y = itemHeight - textHeight;
break;
case Qt::AlignVCenter:
- y = (height - rect.height()) / 2;
+ y = (itemHeight - textHeight) / 2;
break;
}
return y;
diff --git a/src/quick/items/qquicktextutil_p.h b/src/quick/items/qquicktextutil_p.h
index d6c05aac3b..21435c31f8 100644
--- a/src/quick/items/qquicktextutil_p.h
+++ b/src/quick/items/qquicktextutil_p.h
@@ -66,8 +66,9 @@ public:
template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
template <typename Private> static void createCursor(Private *d);
- static qreal alignedX(const QRectF &rect, qreal width, int alignment);
- static qreal alignedY(const QRectF &rect, qreal height, int alignment);
+
+ static qreal alignedX(qreal textWidth, qreal itemWidth, int alignment);
+ static qreal alignedY(qreal textHeight, qreal itemHeight, int alignment);
private:
static QQuickItem *createCursor(
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 0adddb9c85..7a7f5cc053 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -62,6 +62,10 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
Q_DECLARE_METATYPE(QQuickText::TextFormat)
+QT_BEGIN_NAMESPACE
+extern void qt_setQtEnableTestFont(bool value);
+QT_END_NAMESPACE
+
class tst_qquicktext : public QQmlDataTest
{
Q_OBJECT
@@ -116,6 +120,7 @@ private slots:
void contentSize();
void implicitSizeBinding_data();
void implicitSizeBinding();
+ void geometryChanged();
void boundingRect_data();
void boundingRect();
@@ -218,6 +223,7 @@ tst_qquicktext::tst_qquicktext()
// << "#AA0011DD"
// << "#00F16B11";
//
+ qt_setQtEnableTestFont(true);
}
QQuickView *tst_qquicktext::createView(const QString &filename)
@@ -2031,6 +2037,260 @@ void tst_qquicktext::contentSize()
QCOMPARE(spy.count(), ++spyCount);
}
+void tst_qquicktext::geometryChanged()
+{
+ // Test that text is re-laid out when the geometry of the item by verifying changes in content
+ // size. Implicit width is also tested as that in combination with item geometry provides a
+ // reference for expected content sizes.
+
+ QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
+ QQmlComponent textComponent(&engine);
+ textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+
+ const qreal implicitHeight = textObject->implicitHeight();
+
+ const qreal widths[] = { 100, 2000, 3000, -100, 100 };
+ const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
+
+ QCOMPARE(textObject->implicitWidth(), 0.);
+ QVERIFY(implicitHeight > 0.);
+ QCOMPARE(textObject->width(), textObject->implicitWidth());
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setText("The quick red fox jumped over the lazy brown dog");
+
+ const qreal implicitWidth = textObject->implicitWidth();
+
+ QVERIFY(implicitWidth > 0.);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), textObject->implicitWidth());
+ QCOMPARE(textObject->height(), textObject->implicitHeight());
+ QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
+ QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
+
+ // Changing the geometry with no eliding, or wrapping doesn't change the content size.
+ for (int i = 0; i < 5; ++i) {
+ textObject->setWidth(widths[i]);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), widths[i]);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+ }
+
+ // With eliding enabled the content width is bounded to the item width, but is never
+ // larger than the implicit width.
+ textObject->setElideMode(QQuickText::ElideRight);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(2000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 2000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(3000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 3000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(-100);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), -100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), 0.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(100.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ // With wrapping enabled the implicit height changes with the width.
+ textObject->setElideMode(QQuickText::ElideNone);
+ textObject->setWrapMode(QQuickText::Wrap);
+ const qreal wrappedImplicitHeight = textObject->implicitHeight();
+
+ QVERIFY(wrappedImplicitHeight > implicitHeight);
+
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), wrappedImplicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+ textObject->setWidth(2000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 2000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(3000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 3000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(-100);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), -100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(100.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), wrappedImplicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+ // With no eliding or maximum line count the content height is the same as the implicit height.
+ for (int i = 0; i < 5; ++i) {
+ textObject->setHeight(heights[i]);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), heights[i]);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+ }
+
+ // The implicit height is unaffected by eliding but the content height will change.
+ textObject->setElideMode(QQuickText::ElideRight);
+
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setHeight(2000);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), 2000.);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+ textObject->setHeight(3000);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), 3000.);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
+
+ textObject->setHeight(-implicitHeight);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), -implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 0.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight); // content height is never less than font height. seems a little odd in this instance.
+
+ textObject->setHeight(implicitHeight);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ // Varying the height with a maximum line count but no eliding won't affect the content height.
+ textObject->setElideMode(QQuickText::ElideNone);
+ textObject->setMaximumLineCount(2);
+ textObject->resetHeight();
+
+ const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
+ QVERIFY(maxLineCountImplicitHeight > implicitHeight);
+ QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
+
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+
+ for (int i = 0; i < 5; ++i) {
+ textObject->setHeight(heights[i]);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), heights[i]);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+ }
+
+ // Varying the width with a maximum line count won't increase the implicit height beyond the
+ // height of the maximum number of lines.
+ textObject->setWidth(2000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 2000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(3000.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), 3000.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth);
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(-100);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), implicitHeight);
+ QCOMPARE(textObject->width(), -100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
+ QCOMPARE(textObject->contentHeight(), implicitHeight);
+
+ textObject->setWidth(50.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+ QCOMPARE(textObject->width(), 50.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 50.);
+ QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+
+ textObject->setWidth(100.);
+ QCOMPARE(textObject->implicitWidth(), implicitWidth);
+ QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
+ QCOMPARE(textObject->width(), 100.);
+ QCOMPARE(textObject->height(), implicitHeight);
+ QVERIFY(textObject->contentWidth() <= 100.);
+ QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
+}
+
void tst_qquicktext::implicitSizeBinding_data()
{
implicitSize_data();