Skip to content

Commit

Permalink
Avoid an unnecessary layout when eliding text.
Browse files Browse the repository at this point in the history
Query the elided text from the initial layout rather than doing a
second layout of the line to be elided.

Change-Id: I399f99a11046013c0c51add2e2f2dd14b959831a
Reviewed-by: Martin Jones <martin.jones@nokia.com>
  • Loading branch information
Andrew den Exter authored and Qt by Nokia committed Feb 17, 2012
1 parent 4a99f23 commit ece70cc
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 22 deletions.
83 changes: 61 additions & 22 deletions src/quick/items/qquicktext.cpp
Expand Up @@ -589,6 +589,28 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
#endif
}

QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine) const
{
if (nextLine) {
nextLine->setLineWidth(INT_MAX);
return layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
lineWidth,
0,
line.textStart(),
line.textLength() + nextLine->textLength());
} else {
QString elideText = layout.text().mid(line.textStart(), line.textLength());
elideText[elideText.length() - 1] = elideChar;
// Appending the elide character may push the line over the maximum width
// in which case the elided text will need to be elided.
QFontMetricsF metrics(layout.font());
if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth)
elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
return elideText;
}
}

/*!
Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
Expand Down Expand Up @@ -677,6 +699,8 @@ QRect QQuickTextPrivate::setupTextLayout()

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.
for (;;) {
if (!once) {
if (pixelSize)
Expand Down Expand Up @@ -705,22 +729,25 @@ QRect QQuickTextPrivate::setupTextLayout()
setLineGeometry(line, lineWidth, height);
}

// Elide the previous line if the accumulated height of the text exceeds the height
// of the element.
if (multilineElide && height > q->height() && visibleCount > 1) {
elide = 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;

elide = true;
characterCount = line.textStart() + line.textLength();

QTextLine previousLine = layout.lineAt(visibleCount - 2);
elideText = layoutText.mid(previousLine.textStart(), previousLine.textLength());
if (layoutText.at(line.textStart() - 1) != QChar::LineSeparator) {
line.setLineWidth(INT_MAX);
elideText += layoutText.mid(line.textStart(), line.textLength());
} else {
elideText[elideText.length() - 1] = elideChar;
}
elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
? elidedText(lineWidth, previousLine, &line)
: elidedText(lineWidth, previousLine);
// The previous line is the last one visible so move the current one off somewhere
// out of the way and back everything up one line.
line.setLineWidth(0);
line.setPosition(QPointF(FLT_MAX, FLT_MAX));
line = previousLine;
Expand All @@ -733,10 +760,19 @@ QRect QQuickTextPrivate::setupTextLayout()
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.
elide = true;
if (eos != -1) // There's an abbreviated string available.
break;

truncated = true;
height = preLayoutHeight;
elide = true;
elideText = layoutText.mid(line.textStart(), line.textLength());
elideText = layout.engine()->elidedText(
Qt::TextElideMode(elideMode),
lineWidth,
0,
line.textStart(),
line.textLength());
} else {
br = br.united(line.naturalTextRect());
}
Expand All @@ -748,21 +784,20 @@ QRect QQuickTextPrivate::setupTextLayout()
if (!wrappedLine)
++unwrappedLineCount;

// Stop if the maximum number of lines has been reached and elide the last line
// if enabled.
if (visibleCount == maximumLineCount) {
truncated = true;
characterCount = nextLine.textStart() + nextLine.textLength();

if (multilineElide) {
height = preLayoutHeight;
elide = true;
elideText = layoutText.mid(line.textStart(), line.textLength());
if (wrappedLine) {
nextLine.setLineWidth(INT_MAX);
elideText += layoutText.mid(nextLine.textStart(), nextLine.textLength());
} else {
elideText[elideText.length() - 1] = elideChar;
}
elideText += elideChar;
if (eos != -1) // There's an abbreviated string available
break;
height = preLayoutHeight;
elideText = wrappedLine
? elidedText(lineWidth, line, &nextLine)
: elidedText(lineWidth, line);
} else {
br = br.united(line.naturalTextRect());
}
Expand All @@ -778,6 +813,7 @@ QRect QQuickTextPrivate::setupTextLayout()
layout.endLayout();
br.moveTop(0);

// Save the implicitWidth of the text on the first layout only.
if (once) {
naturalWidth = layout.maximumWidth();
once = false;
Expand All @@ -799,6 +835,8 @@ QRect QQuickTextPrivate::setupTextLayout()
}
}

// If the next needs to be elided and there's an abbreviated string available
// go back and do another layout with the abbreviated string.
if (eos != -1 && elide) {
int start = eos + 1;
eos = text.indexOf(QLatin1Char('\x9c'), start);
Expand All @@ -809,6 +847,10 @@ QRect QQuickTextPrivate::setupTextLayout()
continue;
}

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) {
Expand Down Expand Up @@ -840,8 +882,6 @@ QRect QQuickTextPrivate::setupTextLayout()
}
}

if (!horizontalFit && !verticalFit)
break;
}

if (eos != multilengthEos)
Expand All @@ -853,7 +893,6 @@ QRect QQuickTextPrivate::setupTextLayout()
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
elideLayout->setText(elideText);
elideLayout->setText(elideLayout->engine()->elidedText(Qt::TextElideMode(elideMode), lineWidth));
elideLayout->beginLayout();

QTextLine elidedLine = elideLayout->createLine();
Expand Down
1 change: 1 addition & 0 deletions src/quick/items/qquicktext_p_p.h
Expand Up @@ -83,6 +83,7 @@ class Q_AUTOTEST_EXPORT QQuickTextPrivate : public QQuickImplicitSizeItemPrivate
QTextDocument *textDocument();
bool isLineLaidOutConnected();
void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height);
QString elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const;

QString text;
QUrl baseUrl;
Expand Down

0 comments on commit ece70cc

Please sign in to comment.