Loading core/java/android/text/Layout.java +8 −5 Original line number Original line Diff line number Diff line Loading @@ -1066,6 +1066,7 @@ public abstract class Layout { lastLine, lastLine, new CharacterBoundsListener() { new CharacterBoundsListener() { int mLastLineNum = -1; int mLastLineNum = -1; int mNumCharactersToSkip = 0; final RectF mLineBackground = new RectF(); final RectF mLineBackground = new RectF(); @ColorInt int mLastColor = originalTextColor; @ColorInt int mLastColor = originalTextColor; Loading @@ -1073,16 +1074,14 @@ public abstract class Layout { @Override @Override public void onCharacterBounds(int index, int lineNum, float left, float top, public void onCharacterBounds(int index, int lineNum, float left, float top, float right, float bottom) { float right, float bottom) { // Skip processing if the character is a space or a tap to avoid // Skip processing if the character is a space or a tap to avoid // rendering an abrupt, empty rectangle. // rendering an abrupt, empty rectangle. if (TextLine.isLineEndSpace(mText.charAt(index))) { if (TextLine.isLineEndSpace(mText.charAt(index)) || mNumCharactersToSkip > 0) { mNumCharactersToSkip--; return; return; } } var newBackground = determineContrastingBackgroundColor(index); var hasBgColorChanged = newBackground != bgPaint.getColor(); // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a // heuristic. Highlighting is skipped based on code points, not glyph type // heuristic. Highlighting is skipped based on code points, not glyph type // (text vs. color), so emojis with default text presentation are // (text vs. color), so emojis with default text presentation are Loading @@ -1094,9 +1093,13 @@ public abstract class Layout { var isEmoji = Character.isEmojiComponent(codePoint) var isEmoji = Character.isEmojiComponent(codePoint) || Character.isExtendedPictographic(codePoint); || Character.isExtendedPictographic(codePoint); if (isEmoji && !isStandardNumber(index)) { if (isEmoji && !isStandardNumber(index)) { mNumCharactersToSkip = Character.charCount(codePoint) - 1; return; return; } } var newBackground = determineContrastingBackgroundColor(index); var hasBgColorChanged = newBackground != bgPaint.getColor(); if (lineNum != mLastLineNum || hasBgColorChanged) { if (lineNum != mLastLineNum || hasBgColorChanged) { // Draw what we have so far, then reset the rect and update its color // Draw what we have so far, then reset the rect and update its color drawRect(); drawRect(); Loading core/java/android/text/SpanColors.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -72,7 +72,7 @@ public class SpanColors { mWorkPaint.setColor(finalColor); mWorkPaint.setColor(finalColor); for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { if ((index >= mCharacterStyleSpanSet.spanStarts[k]) if ((index >= mCharacterStyleSpanSet.spanStarts[k]) && (index <= mCharacterStyleSpanSet.spanEnds[k])) { && (index < mCharacterStyleSpanSet.spanEnds[k])) { final CharacterStyle span = mCharacterStyleSpanSet.spans[k]; final CharacterStyle span = mCharacterStyleSpanSet.spans[k]; span.updateDrawState(mWorkPaint); span.updateDrawState(mWorkPaint); Loading core/tests/coretests/src/android/text/LayoutTest.java +70 −4 Original line number Original line Diff line number Diff line Loading @@ -948,10 +948,11 @@ public class LayoutTest { Text | Background Text | Background ======================== ======================== al | BW a | BW l | WW w | WW w | WW ei | WW ei\t | WW \t; | WW ; | BB s | BB s | BB df | BB df | BB s | BB s | BB Loading Loading @@ -1012,7 +1013,7 @@ public class LayoutTest { expect.that(removeAlpha(backgroundCommands.get(3).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(3).paint.getColor())) .isEqualTo(Color.WHITE); .isEqualTo(Color.WHITE); expect.that(removeAlpha(backgroundCommands.get(4).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(4).paint.getColor())) .isEqualTo(Color.WHITE); .isEqualTo(Color.BLACK); expect.that(removeAlpha(backgroundCommands.get(5).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(5).paint.getColor())) .isEqualTo(Color.BLACK); .isEqualTo(Color.BLACK); expect.that(removeAlpha(backgroundCommands.get(6).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(6).paint.getColor())) Loading Loading @@ -1041,6 +1042,71 @@ public class LayoutTest { testSpannableStringAppliesAllColorsCorrectly(spannedText); testSpannableStringAppliesAllColorsCorrectly(spannedText); } } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testSingleEmoji_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString(" 😀 "); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testTwoEmojis_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString(" 😀😀 "); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testSingleTextBetweenEmoji_drawsCorrectBackgroundsOnText() { // TODO(b/405847642): Find a way to verify emojis at the beginning and end of a string are // rendered without rectangles. SpannableString spannedText = new SpannableString("😀!😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiWithinText_drawsSameBackgroundswithText() { SpannableString spannedText = new SpannableString("Hello😀World"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiWithinTextWithSpace_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString("Hello 😀 World"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtStart_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("😀HelloWorld"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testLeadingEmojiWithSpace_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("😀 HelloWorld"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtEnd_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("HelloWorld😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtEndWithSpace_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("HelloWorld 😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testRoundedRectSize_belowMinimum_usesMinimumValue() { public void highContrastTextEnabled_testRoundedRectSize_belowMinimum_usesMinimumValue() { Loading core/tests/coretests/src/android/text/SpanColorsTest.java +99 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.graphics.Color; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.ImageSpan; import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan; Loading @@ -41,6 +42,7 @@ public class SpanColorsTest { private final TextPaint mWorkPaint = new TextPaint(); private final TextPaint mWorkPaint = new TextPaint(); private SpanColors mSpanColors; private SpanColors mSpanColors; private SpannableString mSpannedText; private SpannableString mSpannedText; private SpannableString mSpannedTextWithEmoji; @Before @Before public void setup() { public void setup() { Loading @@ -55,6 +57,13 @@ public class SpanColorsTest { Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpannedText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, 16, mSpannedText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, 16, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); Spanned.SPAN_INCLUSIVE_EXCLUSIVE); mSpannedTextWithEmoji = new SpannableString("Hello 🫱🏻🫲🏾world!"); mSpannedTextWithEmoji.setSpan(new ForegroundColorSpan(Color.RED), 0, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); mSpannedTextWithEmoji.setSpan(new ForegroundColorSpan(Color.GREEN), mSpannedTextWithEmoji.length() - 2, mSpannedTextWithEmoji.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } } @Test @Test Loading @@ -72,9 +81,99 @@ public class SpanColorsTest { @Test @Test public void testMultipleColorSpans() { public void testMultipleColorSpans() { mSpanColors.init(mWorkPaint, mSpannedText, 0, mSpannedText.length()); mSpanColors.init(mWorkPaint, mSpannedText, 0, mSpannedText.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(4)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(7)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(9)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(10)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(13)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(13)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(14)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(15)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); } @Test public void testSingleColorSpanWithEmoji() { mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 1, 4); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); } @Test public void testMultipleColorSpansWithEmoji() { mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 0, mSpannedText.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(4)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(6)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(7)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(8)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(9)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(10)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(13)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(14)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(15)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(17)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(18)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(19)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(20)).isEqualTo(Color.GREEN); } @Test public void testSingleColorSpanWithEmojiAndCharacterStyle() { mSpannedTextWithEmoji.setSpan(new CharacterStyle() { @Override public void updateDrawState(TextPaint ds) { ds.setColor(Color.BLACK); } }, 1, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 1, 11); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.BLACK); } @Test public void testMultipleColorSpansWithEmojiAndCharacterStyle() { mSpannedTextWithEmoji.setSpan(new CharacterStyle() { @Override public void updateDrawState(TextPaint ds) { ds.setColor(Color.BLACK); } }, 1, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 0, mSpannedTextWithEmoji.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(4)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(5)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(7)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(9)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(10)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(13)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(14)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(15)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(17)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(18)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(19)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(20)).isEqualTo(Color.GREEN); } } } } Loading
core/java/android/text/Layout.java +8 −5 Original line number Original line Diff line number Diff line Loading @@ -1066,6 +1066,7 @@ public abstract class Layout { lastLine, lastLine, new CharacterBoundsListener() { new CharacterBoundsListener() { int mLastLineNum = -1; int mLastLineNum = -1; int mNumCharactersToSkip = 0; final RectF mLineBackground = new RectF(); final RectF mLineBackground = new RectF(); @ColorInt int mLastColor = originalTextColor; @ColorInt int mLastColor = originalTextColor; Loading @@ -1073,16 +1074,14 @@ public abstract class Layout { @Override @Override public void onCharacterBounds(int index, int lineNum, float left, float top, public void onCharacterBounds(int index, int lineNum, float left, float top, float right, float bottom) { float right, float bottom) { // Skip processing if the character is a space or a tap to avoid // Skip processing if the character is a space or a tap to avoid // rendering an abrupt, empty rectangle. // rendering an abrupt, empty rectangle. if (TextLine.isLineEndSpace(mText.charAt(index))) { if (TextLine.isLineEndSpace(mText.charAt(index)) || mNumCharactersToSkip > 0) { mNumCharactersToSkip--; return; return; } } var newBackground = determineContrastingBackgroundColor(index); var hasBgColorChanged = newBackground != bgPaint.getColor(); // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a // heuristic. Highlighting is skipped based on code points, not glyph type // heuristic. Highlighting is skipped based on code points, not glyph type // (text vs. color), so emojis with default text presentation are // (text vs. color), so emojis with default text presentation are Loading @@ -1094,9 +1093,13 @@ public abstract class Layout { var isEmoji = Character.isEmojiComponent(codePoint) var isEmoji = Character.isEmojiComponent(codePoint) || Character.isExtendedPictographic(codePoint); || Character.isExtendedPictographic(codePoint); if (isEmoji && !isStandardNumber(index)) { if (isEmoji && !isStandardNumber(index)) { mNumCharactersToSkip = Character.charCount(codePoint) - 1; return; return; } } var newBackground = determineContrastingBackgroundColor(index); var hasBgColorChanged = newBackground != bgPaint.getColor(); if (lineNum != mLastLineNum || hasBgColorChanged) { if (lineNum != mLastLineNum || hasBgColorChanged) { // Draw what we have so far, then reset the rect and update its color // Draw what we have so far, then reset the rect and update its color drawRect(); drawRect(); Loading
core/java/android/text/SpanColors.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -72,7 +72,7 @@ public class SpanColors { mWorkPaint.setColor(finalColor); mWorkPaint.setColor(finalColor); for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { if ((index >= mCharacterStyleSpanSet.spanStarts[k]) if ((index >= mCharacterStyleSpanSet.spanStarts[k]) && (index <= mCharacterStyleSpanSet.spanEnds[k])) { && (index < mCharacterStyleSpanSet.spanEnds[k])) { final CharacterStyle span = mCharacterStyleSpanSet.spans[k]; final CharacterStyle span = mCharacterStyleSpanSet.spans[k]; span.updateDrawState(mWorkPaint); span.updateDrawState(mWorkPaint); Loading
core/tests/coretests/src/android/text/LayoutTest.java +70 −4 Original line number Original line Diff line number Diff line Loading @@ -948,10 +948,11 @@ public class LayoutTest { Text | Background Text | Background ======================== ======================== al | BW a | BW l | WW w | WW w | WW ei | WW ei\t | WW \t; | WW ; | BB s | BB s | BB df | BB df | BB s | BB s | BB Loading Loading @@ -1012,7 +1013,7 @@ public class LayoutTest { expect.that(removeAlpha(backgroundCommands.get(3).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(3).paint.getColor())) .isEqualTo(Color.WHITE); .isEqualTo(Color.WHITE); expect.that(removeAlpha(backgroundCommands.get(4).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(4).paint.getColor())) .isEqualTo(Color.WHITE); .isEqualTo(Color.BLACK); expect.that(removeAlpha(backgroundCommands.get(5).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(5).paint.getColor())) .isEqualTo(Color.BLACK); .isEqualTo(Color.BLACK); expect.that(removeAlpha(backgroundCommands.get(6).paint.getColor())) expect.that(removeAlpha(backgroundCommands.get(6).paint.getColor())) Loading Loading @@ -1041,6 +1042,71 @@ public class LayoutTest { testSpannableStringAppliesAllColorsCorrectly(spannedText); testSpannableStringAppliesAllColorsCorrectly(spannedText); } } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testSingleEmoji_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString(" 😀 "); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testTwoEmojis_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString(" 😀😀 "); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testSingleTextBetweenEmoji_drawsCorrectBackgroundsOnText() { // TODO(b/405847642): Find a way to verify emojis at the beginning and end of a string are // rendered without rectangles. SpannableString spannedText = new SpannableString("😀!😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiWithinText_drawsSameBackgroundswithText() { SpannableString spannedText = new SpannableString("Hello😀World"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiWithinTextWithSpace_drawsSameBackgrounds() { SpannableString spannedText = new SpannableString("Hello 😀 World"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtStart_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("😀HelloWorld"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testLeadingEmojiWithSpace_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("😀 HelloWorld"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtEnd_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("HelloWorld😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testEmojiAtEndWithSpace_drawsCorrectBackgroundsOnText() { SpannableString spannedText = new SpannableString("HelloWorld 😀"); testSpannableStringAppliesAllColorsCorrectly(spannedText); } @Test @Test @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) @RequiresFlagsEnabled(FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) public void highContrastTextEnabled_testRoundedRectSize_belowMinimum_usesMinimumValue() { public void highContrastTextEnabled_testRoundedRectSize_belowMinimum_usesMinimumValue() { Loading
core/tests/coretests/src/android/text/SpanColorsTest.java +99 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.graphics.Color; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.Presubmit; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.ImageSpan; import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan; Loading @@ -41,6 +42,7 @@ public class SpanColorsTest { private final TextPaint mWorkPaint = new TextPaint(); private final TextPaint mWorkPaint = new TextPaint(); private SpanColors mSpanColors; private SpanColors mSpanColors; private SpannableString mSpannedText; private SpannableString mSpannedText; private SpannableString mSpannedTextWithEmoji; @Before @Before public void setup() { public void setup() { Loading @@ -55,6 +57,13 @@ public class SpanColorsTest { Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpannedText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, 16, mSpannedText.setSpan(new ForegroundColorSpan(Color.BLUE), 12, 16, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); Spanned.SPAN_INCLUSIVE_EXCLUSIVE); mSpannedTextWithEmoji = new SpannableString("Hello 🫱🏻🫲🏾world!"); mSpannedTextWithEmoji.setSpan(new ForegroundColorSpan(Color.RED), 0, 5, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); mSpannedTextWithEmoji.setSpan(new ForegroundColorSpan(Color.GREEN), mSpannedTextWithEmoji.length() - 2, mSpannedTextWithEmoji.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } } @Test @Test Loading @@ -72,9 +81,99 @@ public class SpanColorsTest { @Test @Test public void testMultipleColorSpans() { public void testMultipleColorSpans() { mSpanColors.init(mWorkPaint, mSpannedText, 0, mSpannedText.length()); mSpanColors.init(mWorkPaint, mSpannedText, 0, mSpannedText.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(4)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(7)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(9)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(10)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(13)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(13)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(14)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(15)).isEqualTo(Color.BLUE); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); } @Test public void testSingleColorSpanWithEmoji() { mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 1, 4); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); } @Test public void testMultipleColorSpansWithEmoji() { mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 0, mSpannedText.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(4)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(5)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(6)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(7)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(8)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(9)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(10)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(13)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(14)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(15)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(17)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(18)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(19)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(20)).isEqualTo(Color.GREEN); } @Test public void testSingleColorSpanWithEmojiAndCharacterStyle() { mSpannedTextWithEmoji.setSpan(new CharacterStyle() { @Override public void updateDrawState(TextPaint ds) { ds.setColor(Color.BLACK); } }, 1, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 1, 11); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.BLACK); } @Test public void testMultipleColorSpansWithEmojiAndCharacterStyle() { mSpannedTextWithEmoji.setSpan(new CharacterStyle() { @Override public void updateDrawState(TextPaint ds) { ds.setColor(Color.BLACK); } }, 1, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mSpanColors.init(mWorkPaint, mSpannedTextWithEmoji, 0, mSpannedTextWithEmoji.length()); assertThat(mSpanColors.getColorAt(0)).isEqualTo(Color.RED); assertThat(mSpanColors.getColorAt(1)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(2)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(3)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(4)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(5)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(6)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(7)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(8)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(9)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(10)).isEqualTo(Color.BLACK); assertThat(mSpanColors.getColorAt(11)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(12)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(13)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(14)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(15)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(16)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(17)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(18)).isEqualTo(SpanColors.NO_COLOR_FOUND); assertThat(mSpanColors.getColorAt(19)).isEqualTo(Color.GREEN); assertThat(mSpanColors.getColorAt(20)).isEqualTo(Color.GREEN); } } } }