summaryrefslogtreecommitdiff
path: root/core/java/android/text/TextLine.java
diff options
context:
space:
mode:
authorMihai Popa <popam@google.com>2018-05-24 14:25:11 +0100
committerMihai Popa <popam@google.com>2018-05-30 12:52:50 +0100
commitce642dc2ff146f8adf01290ea9bf09e4d976e6d2 (patch)
treeb928fb3f77daf714bd1a6c8aef27cbb6bb0bb95c /core/java/android/text/TextLine.java
parenta41a7094ac17ae3e88e3cb0757a30548bcbcc40f (diff)
Supress text replacement spans for ellipsis
When a sequence of characters belonging to a text is ellipsized, we usually replace the first characters with ... and then all the others with a 0 width character, knowing that they will be drawn, but will be invisible. However, these positions could have had ReplacementSpans attached to them, such as EmojiTypefaceSpan when the EmojiCompat library is used. When this happened, all the ellipsized out characters were invisible, apart from emojis, which were still drawn as usual (as they were replacing sequences of 0 width characters). This CL fixes this behaviour, by skipping those ReplacementSpans that were completely included in ellipsis. Please check the bug for a more detailed explanation. Bug: 69802699 Test: manual testing Test: atest FrameworksCoreTests:android.text.TextLineTest Change-Id: If9758537948abaa0226fe6b551a703110c5457b9
Diffstat (limited to 'core/java/android/text/TextLine.java')
-rw-r--r--core/java/android/text/TextLine.java29
1 files changed, 23 insertions, 6 deletions
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index b9f93e5f4632..b1a44ae66eb4 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -62,6 +62,11 @@ public class TextLine {
private Spanned mSpanned;
private PrecomputedText mComputed;
+ // The start and end of a potentially existing ellipsis on this text line.
+ // We use them to filter out replacement and metric affecting spans on ellipsized away chars.
+ private int mEllipsisStart;
+ private int mEllipsisEnd;
+
// Additional width of whitespace for justification. This value is per whitespace, thus
// the line width will increase by mAddedWidth x (number of stretchable whitespaces).
private float mAddedWidth;
@@ -146,11 +151,15 @@ public class TextLine {
* @param dir the paragraph direction of this line
* @param directions the directions information of this line
* @param hasTabs true if the line might contain tabs
- * @param tabStops the tabStops. Can be null.
+ * @param tabStops the tabStops. Can be null
+ * @param ellipsisStart the start of the ellipsis relative to the line
+ * @param ellipsisEnd the end of the ellipsis relative to the line. When there
+ * is no ellipsis, this should be equal to ellipsisStart.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public void set(TextPaint paint, CharSequence text, int start, int limit, int dir,
- Directions directions, boolean hasTabs, TabStops tabStops) {
+ Directions directions, boolean hasTabs, TabStops tabStops,
+ int ellipsisStart, int ellipsisEnd) {
mPaint = paint;
mText = text;
mStart = start;
@@ -196,7 +205,8 @@ public class TextLine {
char[] chars = mChars;
for (int i = start, inext; i < limit; i = inext) {
inext = mReplacementSpanSpanSet.getNextTransition(i, limit);
- if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)) {
+ if (mReplacementSpanSpanSet.hasSpansIntersecting(i, inext)
+ && (i - start >= ellipsisEnd || inext - start <= ellipsisStart)) {
// transition into a span
chars[i - start] = '\ufffc';
for (int j = i - start + 1, e = inext - start; j < e; ++j) {
@@ -208,6 +218,9 @@ public class TextLine {
}
mTabs = tabStops;
mAddedWidth = 0;
+
+ mEllipsisStart = ellipsisStart != ellipsisEnd ? ellipsisStart : 0;
+ mEllipsisEnd = ellipsisStart != ellipsisEnd ? ellipsisEnd : 0;
}
/**
@@ -1156,11 +1169,15 @@ public class TextLine {
for (int j = 0; j < mMetricAffectingSpanSpanSet.numberOfSpans; j++) {
// Both intervals [spanStarts..spanEnds] and [mStart + i..mStart + mlimit] are NOT
// empty by construction. This special case in getSpans() explains the >= & <= tests
- if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit) ||
- (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
+ if ((mMetricAffectingSpanSpanSet.spanStarts[j] >= mStart + mlimit)
+ || (mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + i)) continue;
+
+ boolean insideEllipsis =
+ mStart + mEllipsisStart <= mMetricAffectingSpanSpanSet.spanStarts[j]
+ && mMetricAffectingSpanSpanSet.spanEnds[j] <= mStart + mEllipsisEnd;
final MetricAffectingSpan span = mMetricAffectingSpanSpanSet.spans[j];
if (span instanceof ReplacementSpan) {
- replacement = (ReplacementSpan)span;
+ replacement = !insideEllipsis ? (ReplacementSpan) span : null;
} else {
// We might have a replacement that uses the draw
// state, otherwise measure state would suffice.