Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Avoid Text layout being triggered unnecessarily
Text was quite often layed out twice during construction due to
geometry changes, and often at run time due to other geometry changes.
This change checks for cases which do not require relayouting and
drops out early.  These are easier to detect than trying to have a
single giant if statement covering all the positive combinations.

Change-Id: I2deb2ab52d35b3d02bced698d05fef91c9e2f745
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
  • Loading branch information
Martin Jones authored and Qt by Nokia committed Dec 7, 2011
1 parent d052d2f commit 3bb47f4
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 17 deletions.
77 changes: 60 additions & 17 deletions src/quick/items/qquicktext.cpp
Expand Up @@ -224,8 +224,12 @@ void QQuickTextPrivate::updateLayout()
tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
singleline = !tmp.contains(QChar::LineSeparator);
if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid() && wrapMode == QQuickText::NoWrap) {
QFontMetrics fm(font);
tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
if (q->width() <= 0) {
tmp = QString();
} else {
QFontMetrics fm(font);
tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
}
if (tmp != text) {
layoutTextElided = true;
if (!truncated) {
Expand Down Expand Up @@ -536,10 +540,26 @@ QRect QQuickTextPrivate::setupTextLayout()
layout.setText(elidedText);
}

if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
|| (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
// we are elided and we have a zero width or height
if (!truncated) {
truncated = true;
emit q->truncatedChanged();
}
if (lineCount) {
lineCount = 0;
emit q->lineCountChanged();
}

qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
return QRect(0, 0, 0, height);
}

qreal height = 0;
QRectF br;

bool truncate = false;
bool truncate = layoutTextElided;
bool customLayout = isLineLaidOutConnected();
bool elideEnabled = elideMode == QQuickText::ElideRight && q->widthValid();

Expand Down Expand Up @@ -1633,21 +1653,44 @@ QRectF QQuickText::boundingRect() const
void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickText);
bool elide = d->elideMode != QQuickText::ElideNone && widthValid();
if ((!d->internalWidthUpdate
&& (newGeometry.width() != oldGeometry.width() || (elide && newGeometry.height() != oldGeometry.height())))
&& (d->wrapMode != QQuickText::NoWrap
|| d->elideMode != QQuickText::ElideNone
|| d->hAlign != QQuickText::AlignLeft)) {
if ((d->singleline || d->maximumLineCountValid || heightValid()) && elide) {
// We need to re-elide
d->updateLayout();
} else {
// We just need to re-layout
d->updateSize();
}
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;

if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
goto geomChangeDone;

if (leftAligned && !wrapped && !elide)
goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout

if (!widthChanged && !wrapped && d->singleline)
goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text

if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight)
goto geomChangeDone; // only height changed and no multiline eliding.

if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
&& !wrapped && newGeometry.width() > oldGeometry.width())
goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.

if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height()) {
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 (d->updateOnComponentComplete || (elide && widthValid())) {
// We need to re-elide
d->updateLayout();
} else {
// We just need to re-layout
d->updateSize();
}

geomChangeDone:
QQuickItem::geometryChanged(newGeometry, oldGeometry);
}

Expand Down Expand Up @@ -1724,7 +1767,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
d->ensureDoc();
node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor);

} else {
} else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
if (d->elipsisLayout)
node->addTextLayout(QPoint(0, bounds.y()), d->elipsisLayout, d->color, d->style, d->styleColor);
Expand Down
4 changes: 4 additions & 0 deletions tests/auto/qtquick2/qquicktext/tst_qquicktext.cpp
Expand Up @@ -634,6 +634,8 @@ void tst_qquicktext::horizontalAlignment_RightToLeft()
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
QVERIFY(textPrivate != 0);

QTRY_VERIFY(textPrivate->layout.lineCount());

// implicit alignment should follow the reading direction of RTL text
QCOMPARE(text->hAlign(), QQuickText::AlignRight);
QCOMPARE(text->effectiveHAlign(), text->hAlign());
Expand Down Expand Up @@ -1453,6 +1455,8 @@ void tst_qquicktext::lineLaidOut()
QVERIFY(r.height() == 20);
}
}

delete canvas;
}

QTEST_MAIN(tst_qquicktext)
Expand Down

0 comments on commit 3bb47f4

Please sign in to comment.