Revert "Make ellipsize retry if text doesn't fit"
This reverts commit e88b5df5b7aaf5a5f654805eb5e5e4c2f09afaa8.
Test: bit FrameworksCoreTests:android.text.StaticLayoutTest
Test: bit FrameworksCoreTests:android.text.DynamicLayoutTest
Test: bit FrameworksCoreTests:android.text.TextUtilsTest
Test: bit CtsTextTestCases:*
Test: atest FilesActivityUiTest
Bug: 71599479
Bug: 31537595
Bug: 64156587
Change-Id: I1afa77a4b90b9b822b409a3f4721c45d0c0a6664
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 70d6486..80d7ef5 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -928,8 +928,6 @@
}
}
- // The parameters that are not changed in the method are marked as final to make the code
- // easier to understand.
private int out(final CharSequence text, final int start, final int end, int above, int below,
int top, int bottom, int v, final float spacingmult, final float spacingadd,
final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
@@ -958,21 +956,29 @@
mLineDirections = grow;
}
- lines[off + START] = start;
- lines[off + TOP] = v;
+ if (chooseHt != null) {
+ fm.ascent = above;
+ fm.descent = below;
+ fm.top = top;
+ fm.bottom = bottom;
- // Information about hyphenation, tabs, and directions are needed for determining
- // ellipsization, so the values should be assigned before ellipsization.
+ for (int i = 0; i < chooseHt.length; i++) {
+ if (chooseHt[i] instanceof LineHeightSpan.WithDensity) {
+ ((LineHeightSpan.WithDensity) chooseHt[i])
+ .chooseHeight(text, start, end, chooseHtv[i], v, fm, paint);
+ } else {
+ chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm);
+ }
+ }
- // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
- // one bit for start field
- lines[off + TAB] |= flags & TAB_MASK;
- lines[off + HYPHEN] = flags;
- lines[off + DIR] |= dir << DIR_SHIFT;
- mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
+ above = fm.ascent;
+ below = fm.descent;
+ top = fm.top;
+ bottom = fm.bottom;
+ }
- final boolean firstLine = (j == 0);
- final boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
+ boolean firstLine = (j == 0);
+ boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
if (ellipsize != null) {
// If there is only one line, then do any type of ellipsis except when it is MARQUEE
@@ -985,9 +991,9 @@
(!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
ellipsize == TextUtils.TruncateAt.END);
if (doEllipsis) {
- calculateEllipsis(text, start, end, widths, widthStart,
- ellipsisWidth - getTotalInsets(j), ellipsize, j,
- textWidth, paint, forceEllipsis, dir);
+ calculateEllipsis(start, end, widths, widthStart,
+ ellipsisWidth, ellipsize, j,
+ textWidth, paint, forceEllipsis);
}
}
@@ -1006,28 +1012,6 @@
}
}
- if (chooseHt != null) {
- fm.ascent = above;
- fm.descent = below;
- fm.top = top;
- fm.bottom = bottom;
-
- for (int i = 0; i < chooseHt.length; i++) {
- if (chooseHt[i] instanceof LineHeightSpan.WithDensity) {
- ((LineHeightSpan.WithDensity) chooseHt[i])
- .chooseHeight(text, start, end, chooseHtv[i], v, fm, paint);
-
- } else {
- chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm);
- }
- }
-
- above = fm.ascent;
- below = fm.descent;
- top = fm.top;
- bottom = fm.bottom;
- }
-
if (firstLine) {
if (trackPad) {
mTopPadding = top - above;
@@ -1038,6 +1022,8 @@
}
}
+ int extra;
+
if (lastLine) {
if (trackPad) {
mBottomPadding = bottom - below;
@@ -1048,9 +1034,8 @@
}
}
- final int extra;
if (needMultiply && (addLastLineLineSpacing || !lastLine)) {
- final double ex = (below - above) * (spacingmult - 1) + spacingadd;
+ double ex = (below - above) * (spacingmult - 1) + spacingadd;
if (ex >= 0) {
extra = (int)(ex + EXTRA_ROUNDING);
} else {
@@ -1060,6 +1045,8 @@
extra = 0;
}
+ lines[off + START] = start;
+ lines[off + TOP] = v;
lines[off + DESCENT] = below + extra;
lines[off + EXTRA] = extra;
@@ -1067,7 +1054,7 @@
// store the height as if it was ellipsized
if (!mEllipsized && currentLineIsTheLastVisibleOne) {
// below calculation as if it was the last line
- final int maxLineBelow = includePad ? bottom : below;
+ int maxLineBelow = includePad ? bottom : below;
// similar to the calculation of v below, without the extra.
mMaxLineHeight = v + (maxLineBelow - above);
}
@@ -1076,13 +1063,23 @@
lines[off + mColumns + START] = end;
lines[off + mColumns + TOP] = v;
+ // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
+ // one bit for start field
+ lines[off + TAB] |= flags & TAB_MASK;
+ lines[off + HYPHEN] = flags;
+ lines[off + DIR] |= dir << DIR_SHIFT;
+ mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
+
mLineCount++;
return v;
}
- private void calculateEllipsis(CharSequence text, int lineStart, int lineEnd, float[] widths,
- int widthStart, float avail, TextUtils.TruncateAt where, int line, float textWidth,
- TextPaint paint, boolean forceEllipsis, int dir) {
+ private void calculateEllipsis(int lineStart, int lineEnd,
+ float[] widths, int widthStart,
+ float avail, TextUtils.TruncateAt where,
+ int line, float textWidth, TextPaint paint,
+ boolean forceEllipsis) {
+ avail -= getTotalInsets(line);
if (textWidth <= avail && !forceEllipsis) {
// Everything fits!
mLines[mColumns * line + ELLIPSIS_START] = 0;
@@ -1090,53 +1087,11 @@
return;
}
- float tempAvail = avail;
- int numberOfTries = 0;
- boolean lineFits = false;
- mWorkPaint.set(paint);
- do {
- final float ellipsizedWidth = guessEllipsis(text, lineStart, lineEnd, widths,
- widthStart, tempAvail, where, line, mWorkPaint, forceEllipsis, dir);
- if (ellipsizedWidth <= avail) {
- lineFits = true;
- } else {
- numberOfTries++;
- if (numberOfTries > 10) {
- // If the text still doesn't fit after ten tries, assume it will never fit and
- // ellipsize it all.
- mLines[mColumns * line + ELLIPSIS_START] = 0;
- mLines[mColumns * line + ELLIPSIS_COUNT] = lineEnd - lineStart;
- lineFits = true;
- } else {
- // Some side effect of ellipsization has caused the text to go over the
- // available width. Let's make the available width shorter by exactly that
- // amount and retry.
- tempAvail -= ellipsizedWidth - avail;
- }
- }
- } while (!lineFits);
- mEllipsized = true;
- }
+ float ellipsisWidth = paint.measureText(TextUtils.getEllipsisString(where));
+ int ellipsisStart = 0;
+ int ellipsisCount = 0;
+ int len = lineEnd - lineStart;
- // Returns the width of the ellipsized line which in some rare cases can actually be larger
- // than 'avail' (due to kerning or other context-based effect of replacement of text by
- // ellipsis). If all the line needs to ellipsized away, or it's an invalud hyphenation mode,
- // returns 0 so the caller can stop iterating.
- //
- // This method temporarily modifies the TextPaint passed to it, so the TextPaint passed to it
- // should not be accessed while the method is running.
- private float guessEllipsis(CharSequence text, int lineStart, int lineEnd, float[] widths,
- int widthStart, float avail, TextUtils.TruncateAt where, int line,
- TextPaint paint, boolean forceEllipsis, int dir) {
- final int savedHyphenEdit = paint.getHyphenEdit();
- paint.setHyphenEdit(0);
- final float ellipsisWidth = paint.measureText(TextUtils.getEllipsisString(where));
- final int ellipsisStart;
- final int ellipsisCount;
- final int len = lineEnd - lineStart;
- final int offset = lineStart - widthStart;
-
- int hyphen = getHyphen(line);
// We only support start ellipsis on a single line
if (where == TextUtils.TruncateAt.START) {
if (mMaximumVisibleLineCount == 1) {
@@ -1144,9 +1099,9 @@
int i;
for (i = len; i > 0; i--) {
- final float w = widths[i - 1 + offset];
+ float w = widths[i - 1 + lineStart - widthStart];
if (w + sum + ellipsisWidth > avail) {
- while (i < len && widths[i + offset] == 0.0f) {
+ while (i < len && widths[i + lineStart - widthStart] == 0.0f) {
i++;
}
break;
@@ -1157,13 +1112,9 @@
ellipsisStart = 0;
ellipsisCount = i;
- // Strip the potential hyphenation at beginning of line.
- hyphen &= ~Paint.HYPHENEDIT_MASK_START_OF_LINE;
} else {
- ellipsisStart = 0;
- ellipsisCount = 0;
if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "Start ellipsis only supported with one line");
+ Log.w(TAG, "Start Ellipsis only supported with one line");
}
}
} else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE ||
@@ -1172,7 +1123,7 @@
int i;
for (i = 0; i < len; i++) {
- final float w = widths[i + offset];
+ float w = widths[i + lineStart - widthStart];
if (w + sum + ellipsisWidth > avail) {
break;
@@ -1181,27 +1132,24 @@
sum += w;
}
- if (forceEllipsis && i == len && len > 0) {
+ ellipsisStart = i;
+ ellipsisCount = len - i;
+ if (forceEllipsis && ellipsisCount == 0 && len > 0) {
ellipsisStart = len - 1;
ellipsisCount = 1;
- } else {
- ellipsisStart = i;
- ellipsisCount = len - i;
}
- // Strip the potential hyphenation at end of line.
- hyphen &= ~Paint.HYPHENEDIT_MASK_END_OF_LINE;
- } else { // where = TextUtils.TruncateAt.MIDDLE
- // We only support middle ellipsis on a single line.
+ } else {
+ // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line
if (mMaximumVisibleLineCount == 1) {
float lsum = 0, rsum = 0;
int left = 0, right = len;
- final float ravail = (avail - ellipsisWidth) / 2;
+ float ravail = (avail - ellipsisWidth) / 2;
for (right = len; right > 0; right--) {
- final float w = widths[right - 1 + offset];
+ float w = widths[right - 1 + lineStart - widthStart];
if (w + rsum > ravail) {
- while (right < len && widths[right + offset] == 0.0f) {
+ while (right < len && widths[right + lineStart - widthStart] == 0.0f) {
right++;
}
break;
@@ -1209,9 +1157,9 @@
rsum += w;
}
- final float lavail = avail - ellipsisWidth - rsum;
+ float lavail = avail - ellipsisWidth - rsum;
for (left = 0; left < right; left++) {
- final float w = widths[left + offset];
+ float w = widths[left + lineStart - widthStart];
if (w + lsum > lavail) {
break;
@@ -1223,53 +1171,14 @@
ellipsisStart = left;
ellipsisCount = right - left;
} else {
- ellipsisStart = 0;
- ellipsisCount = 0;
if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "Middle ellipsis only supported with one line");
+ Log.w(TAG, "Middle Ellipsis only supported with one line");
}
}
}
+ mEllipsized = true;
mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
-
- if (ellipsisStart == 0 && (ellipsisCount == 0 || ellipsisCount == len)) {
- // Unsupported ellipsization mode or all text is ellipsized away. Return 0.
- return 0.0f;
- }
-
- final boolean isSpanned = text instanceof Spanned;
- final Ellipsizer ellipsizedText = isSpanned
- ? new SpannedEllipsizer(text)
- : new Ellipsizer(text);
- ellipsizedText.mLayout = this;
- ellipsizedText.mMethod = where;
-
- final boolean hasTabs = getLineContainsTab(line);
- final TabStops tabStops;
- if (hasTabs && isSpanned) {
- final TabStopSpan[] tabs = getParagraphSpans((Spanned) ellipsizedText, lineStart,
- lineEnd, TabStopSpan.class);
- if (tabs.length == 0) {
- tabStops = null;
- } else {
- tabStops = new TabStops(TAB_INCREMENT, tabs);
- }
- } else {
- tabStops = null;
- }
- paint.setHyphenEdit(hyphen);
- final TextLine textline = TextLine.obtain();
- textline.set(paint, ellipsizedText, lineStart, lineEnd, dir, getLineDirections(line),
- hasTabs, tabStops);
- // Since TextLine.metric() returns negative values for RTL text, multiplication by dir
- // converts it to an actual width. Note that we don't want to use the absolute value,
- // since we may actually have glyphs with negative advances, which by definition always
- // fit.
- final float ellipsizedWidth = textline.metrics(null) * dir;
- TextLine.recycle(textline);
- paint.setHyphenEdit(savedHyphenEdit);
- return ellipsizedWidth;
}
private float getTotalInsets(int line) {
@@ -1509,8 +1418,6 @@
*/
private int mMaxLineHeight = DEFAULT_MAX_LINE_HEIGHT;
- private TextPaint mWorkPaint = new TextPaint();
-
private static final int COLUMNS_NORMAL = 5;
private static final int COLUMNS_ELLIPSIZE = 7;
private static final int START = 0;