Merge pull request #6724 from nnoury:fix/subtitles-outline-color
PiperOrigin-RevId: 292316767
This commit is contained in:
parent
d162c07ecf
commit
4e6fe31ee1
@ -35,8 +35,11 @@
|
|||||||
* Add `showScrubber` and `hideScrubber` methods to `DefaultTimeBar`.
|
* Add `showScrubber` and `hideScrubber` methods to `DefaultTimeBar`.
|
||||||
* Update `TrackSelectionDialogBuilder` to use AndroidX Compat Dialog
|
* Update `TrackSelectionDialogBuilder` to use AndroidX Compat Dialog
|
||||||
([#7357](https://github.com/google/ExoPlayer/issues/7357)).
|
([#7357](https://github.com/google/ExoPlayer/issues/7357)).
|
||||||
* Text: Use anti-aliasing and bitmap filtering when displaying bitmap
|
* Text:
|
||||||
|
* Use anti-aliasing and bitmap filtering when displaying bitmap
|
||||||
subtitles.
|
subtitles.
|
||||||
|
* Fix `SubtitlePainter` to render `EDGE_TYPE_OUTLINE` using the correct
|
||||||
|
color.
|
||||||
* Cronet extension: Default to using the Cronet implementation in Google Play
|
* Cronet extension: Default to using the Cronet implementation in Google Play
|
||||||
Services rather than Cronet Embedded. This allows Cronet to be used with a
|
Services rather than Cronet Embedded. This allows Cronet to be used with a
|
||||||
negligible increase in application size, compared to approximately 8MB when
|
negligible increase in application size, compared to approximately 8MB when
|
||||||
|
@ -33,6 +33,7 @@ import android.text.TextPaint;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.style.AbsoluteSizeSpan;
|
import android.text.style.AbsoluteSizeSpan;
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.RelativeSizeSpan;
|
import android.text.style.RelativeSizeSpan;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -99,6 +100,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
|
|
||||||
// Derived drawing variables.
|
// Derived drawing variables.
|
||||||
private @MonotonicNonNull StaticLayout textLayout;
|
private @MonotonicNonNull StaticLayout textLayout;
|
||||||
|
private @MonotonicNonNull StaticLayout edgeLayout;
|
||||||
private int textLeft;
|
private int textLeft;
|
||||||
private int textTop;
|
private int textTop;
|
||||||
private int textPaddingX;
|
private int textPaddingX;
|
||||||
@ -291,11 +293,38 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove embedded font color to not destroy edges, otherwise it overrides edge color.
|
||||||
|
SpannableStringBuilder cueTextEdge = new SpannableStringBuilder(cueText);
|
||||||
|
if (edgeType == CaptionStyleCompat.EDGE_TYPE_OUTLINE) {
|
||||||
|
int cueLength = cueTextEdge.length();
|
||||||
|
ForegroundColorSpan[] foregroundColorSpans =
|
||||||
|
cueTextEdge.getSpans(0, cueLength, ForegroundColorSpan.class);
|
||||||
|
for (ForegroundColorSpan foregroundColorSpan : foregroundColorSpans) {
|
||||||
|
cueTextEdge.removeSpan(foregroundColorSpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EDGE_TYPE_NONE & EDGE_TYPE_DROP_SHADOW both paint in one pass, they ignore cueTextEdge.
|
||||||
|
// In other cases we use two painters and we need to apply the background in the first one only,
|
||||||
|
// otherwise the background color gets drawn in front of the edge color
|
||||||
|
// (https://github.com/google/ExoPlayer/pull/6724#issuecomment-564650572).
|
||||||
if (Color.alpha(backgroundColor) > 0) {
|
if (Color.alpha(backgroundColor) > 0) {
|
||||||
|
if (edgeType == CaptionStyleCompat.EDGE_TYPE_NONE
|
||||||
|
|| edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) {
|
||||||
SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText);
|
SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText);
|
||||||
newCueText.setSpan(
|
newCueText.setSpan(
|
||||||
new BackgroundColorSpan(backgroundColor), 0, newCueText.length(), Spanned.SPAN_PRIORITY);
|
new BackgroundColorSpan(backgroundColor),
|
||||||
|
0,
|
||||||
|
newCueText.length(),
|
||||||
|
Spanned.SPAN_PRIORITY);
|
||||||
cueText = newCueText;
|
cueText = newCueText;
|
||||||
|
} else {
|
||||||
|
cueTextEdge.setSpan(
|
||||||
|
new BackgroundColorSpan(backgroundColor),
|
||||||
|
0,
|
||||||
|
cueTextEdge.length(),
|
||||||
|
Spanned.SPAN_PRIORITY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Alignment textAlignment = cueTextAlignment == null ? Alignment.ALIGN_CENTER : cueTextAlignment;
|
Alignment textAlignment = cueTextAlignment == null ? Alignment.ALIGN_CENTER : cueTextAlignment;
|
||||||
@ -371,6 +400,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
// Update the derived drawing variables.
|
// Update the derived drawing variables.
|
||||||
this.textLayout = new StaticLayout(cueText, textPaint, textWidth, textAlignment, spacingMult,
|
this.textLayout = new StaticLayout(cueText, textPaint, textWidth, textAlignment, spacingMult,
|
||||||
spacingAdd, true);
|
spacingAdd, true);
|
||||||
|
this.edgeLayout =
|
||||||
|
new StaticLayout(
|
||||||
|
cueTextEdge, textPaint, textWidth, textAlignment, spacingMult, spacingAdd, true);
|
||||||
this.textLeft = textLeft;
|
this.textLeft = textLeft;
|
||||||
this.textTop = textTop;
|
this.textTop = textTop;
|
||||||
this.textPaddingX = textPaddingX;
|
this.textPaddingX = textPaddingX;
|
||||||
@ -410,8 +442,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void drawTextLayout(Canvas canvas) {
|
private void drawTextLayout(Canvas canvas) {
|
||||||
StaticLayout layout = textLayout;
|
StaticLayout textLayout = this.textLayout;
|
||||||
if (layout == null) {
|
StaticLayout edgeLayout = this.edgeLayout;
|
||||||
|
if (textLayout == null || edgeLayout == null) {
|
||||||
// Nothing to draw.
|
// Nothing to draw.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -434,7 +467,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
textPaint.setStrokeWidth(outlineWidth);
|
textPaint.setStrokeWidth(outlineWidth);
|
||||||
textPaint.setColor(edgeColor);
|
textPaint.setColor(edgeColor);
|
||||||
textPaint.setStyle(Style.FILL_AND_STROKE);
|
textPaint.setStyle(Style.FILL_AND_STROKE);
|
||||||
layout.draw(canvas);
|
edgeLayout.draw(canvas);
|
||||||
} else if (edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) {
|
} else if (edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) {
|
||||||
textPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, edgeColor);
|
textPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, edgeColor);
|
||||||
} else if (edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED
|
} else if (edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED
|
||||||
@ -446,13 +479,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
textPaint.setColor(foregroundColor);
|
textPaint.setColor(foregroundColor);
|
||||||
textPaint.setStyle(Style.FILL);
|
textPaint.setStyle(Style.FILL);
|
||||||
textPaint.setShadowLayer(shadowRadius, -offset, -offset, colorUp);
|
textPaint.setShadowLayer(shadowRadius, -offset, -offset, colorUp);
|
||||||
layout.draw(canvas);
|
edgeLayout.draw(canvas);
|
||||||
textPaint.setShadowLayer(shadowRadius, offset, offset, colorDown);
|
textPaint.setShadowLayer(shadowRadius, offset, offset, colorDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
textPaint.setColor(foregroundColor);
|
textPaint.setColor(foregroundColor);
|
||||||
textPaint.setStyle(Style.FILL);
|
textPaint.setStyle(Style.FILL);
|
||||||
layout.draw(canvas);
|
textLayout.draw(canvas);
|
||||||
textPaint.setShadowLayer(0, 0, 0, 0);
|
textPaint.setShadowLayer(0, 0, 0, 0);
|
||||||
|
|
||||||
canvas.restoreToCount(saveCount);
|
canvas.restoreToCount(saveCount);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user