From 7d38d2ef3c9d1cd316b0b33199c6cabf21b3f320 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Thu, 10 Sep 2015 18:22:44 +0100 Subject: [PATCH] CuePainter fixes for caption styling. - Don't allow "nothing has changed" optimization in the case that only styling has changed (TextUtils.equals will return true in this case, but we shouldn't optimize). - Add functionality to suppress embedded styling; seems useful to have. - Added "this." for clarity. --- .../android/exoplayer/text/CuePainter.java | 80 ++++++++++++------- .../exoplayer/text/SubtitleLayout.java | 22 ++++- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/text/CuePainter.java b/library/src/main/java/com/google/android/exoplayer/text/CuePainter.java index 66b41a811a..028eb4203d 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/CuePainter.java +++ b/library/src/main/java/com/google/android/exoplayer/text/CuePainter.java @@ -71,6 +71,7 @@ import android.util.Log; private CharSequence cueText; private int cuePosition; private Alignment cueAlignment; + private boolean applyEmbeddedStyles; private int foregroundColor; private int backgroundColor; private int windowColor; @@ -121,6 +122,7 @@ import android.util.Log; * which the same parameters are passed. * * @param cue The cue to draw. + * @param applyEmbeddedStyles Whether styling embedded within the cue should be applied. * @param style The style to use when drawing the cue text. * @param fontScale The font scale. * @param bottomPaddingFraction The bottom padding fraction to apply when {@link Cue#line} is @@ -131,48 +133,55 @@ import android.util.Log; * @param cueBoxRight The right position of the enclosing cue box. * @param cueBoxBottom The bottom position of the enclosing cue box. */ - public void draw(Cue cue, CaptionStyleCompat style, float fontScale, float bottomPaddingFraction, - Canvas canvas, int cueBoxLeft, int cueBoxTop, int cueBoxRight, int cueBoxBottom) { - if (TextUtils.isEmpty(cue.text)) { + public void draw(Cue cue, boolean applyEmbeddedStyles, CaptionStyleCompat style, float fontScale, + float bottomPaddingFraction, Canvas canvas, int cueBoxLeft, int cueBoxTop, int cueBoxRight, + int cueBoxBottom) { + CharSequence cueText = cue.text; + if (TextUtils.isEmpty(cueText)) { // Nothing to draw. return; } - - if (TextUtils.equals(cueText, cue.text) - && cuePosition == cue.position - && Util.areEqual(cueAlignment, cue.alignment) - && foregroundColor == style.foregroundColor - && backgroundColor == style.backgroundColor - && windowColor == style.windowColor - && edgeType == style.edgeType - && edgeColor == style.edgeColor - && Util.areEqual(textPaint.getTypeface(), style.typeface) + if (!applyEmbeddedStyles) { + // Strip out any embedded styling. + cueText = cueText.toString(); + } + if (areCharSequencesEqual(this.cueText, cueText) + && this.cuePosition == cue.position + && Util.areEqual(this.cueAlignment, cue.alignment) + && this.applyEmbeddedStyles == applyEmbeddedStyles + && this.foregroundColor == style.foregroundColor + && this.backgroundColor == style.backgroundColor + && this.windowColor == style.windowColor + && this.edgeType == style.edgeType + && this.edgeColor == style.edgeColor + && Util.areEqual(this.textPaint.getTypeface(), style.typeface) && this.fontScale == fontScale && this.bottomPaddingFraction == bottomPaddingFraction - && parentLeft == cueBoxLeft - && parentTop == cueBoxTop - && parentRight == cueBoxRight - && parentBottom == cueBoxBottom) { + && this.parentLeft == cueBoxLeft + && this.parentTop == cueBoxTop + && this.parentRight == cueBoxRight + && this.parentBottom == cueBoxBottom) { // We can use the cached layout. drawLayout(canvas); return; } - cueText = cue.text; - cuePosition = cue.position; - cueAlignment = cue.alignment; - foregroundColor = style.foregroundColor; - backgroundColor = style.backgroundColor; - windowColor = style.windowColor; - edgeType = style.edgeType; - edgeColor = style.edgeColor; - textPaint.setTypeface(style.typeface); + this.cueText = cueText; + this.cuePosition = cue.position; + this.cueAlignment = cue.alignment; + this.applyEmbeddedStyles = applyEmbeddedStyles; + this.foregroundColor = style.foregroundColor; + this.backgroundColor = style.backgroundColor; + this.windowColor = style.windowColor; + this.edgeType = style.edgeType; + this.edgeColor = style.edgeColor; + this.textPaint.setTypeface(style.typeface); this.fontScale = fontScale; this.bottomPaddingFraction = bottomPaddingFraction; - parentLeft = cueBoxLeft; - parentTop = cueBoxTop; - parentRight = cueBoxRight; - parentBottom = cueBoxBottom; + this.parentLeft = cueBoxLeft; + this.parentTop = cueBoxTop; + this.parentRight = cueBoxRight; + this.parentBottom = cueBoxBottom; int parentWidth = parentRight - parentLeft; int parentHeight = parentBottom - parentTop; @@ -297,4 +306,15 @@ import android.util.Log; canvas.restoreToCount(saveCount); } + /** + * This method is used instead of {@link TextUtils#equals(CharSequence, CharSequence)} because the + * latter only checks the text of each sequence, and does not check for equality of styling that + * may be embedded within the {@link CharSequence}s. + */ + private static boolean areCharSequencesEqual(CharSequence first, CharSequence second) { + // Some CharSequence implementations don't perform a cheap referential equality check in their + // equals methods, so we perform one explicitly here. + return first == second || (first != null && first.equals(second)); + } + } diff --git a/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java b/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java index e0818a2d86..929537b83c 100644 --- a/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java +++ b/library/src/main/java/com/google/android/exoplayer/text/SubtitleLayout.java @@ -38,6 +38,7 @@ public final class SubtitleLayout extends View { private List cues; private float fontScale; + private boolean applyEmbeddedStyles; private CaptionStyleCompat style; private float bottomPaddingFraction; @@ -49,6 +50,7 @@ public final class SubtitleLayout extends View { super(context, attrs); painters = new ArrayList<>(); fontScale = 1; + applyEmbeddedStyles = true; style = CaptionStyleCompat.DEFAULT; bottomPaddingFraction = DEFAULT_BOTTOM_PADDING_FRACTION; } @@ -87,7 +89,21 @@ public final class SubtitleLayout extends View { } /** - * Configures the view according to the given style. + * Sets whether styling embedded within the cues should be applied. Enabled by default. + * + * @param applyEmbeddedStyles Whether styling embedded within the cues should be applied. + */ + public void setApplyEmbeddedStyles(boolean applyEmbeddedStyles) { + if (this.applyEmbeddedStyles == applyEmbeddedStyles) { + return; + } + this.applyEmbeddedStyles = applyEmbeddedStyles; + // Invalidate to trigger drawing. + invalidate(); + } + + /** + * Sets the caption style. * * @param style A style for the view. */ @@ -119,8 +135,8 @@ public final class SubtitleLayout extends View { public void dispatchDraw(Canvas canvas) { int cueCount = (cues == null) ? 0 : cues.size(); for (int i = 0; i < cueCount; i++) { - painters.get(i).draw(cues.get(i), style, fontScale, bottomPaddingFraction, canvas, getLeft(), - getTop(), getRight(), getBottom()); + painters.get(i).draw(cues.get(i), applyEmbeddedStyles, style, fontScale, + bottomPaddingFraction, canvas, getLeft(), getTop(), getRight(), getBottom()); } }