Commit 1e72e1ac by Nicolas Noury

Introduce edgeLayout to keep outline color

Fix outline style subtitle

When a ForegroundColorSpan changes the foreground color, it is also applied
to the outline painter. In order to keep the correct color, one needs to
filter out theses span. We do this with a new cue that is our text source
for the specific edgeLayout.

Take care to only apply background color once

Test: Manual check - Subtitle view can show custom color subtitles from specific Subtitle
Renderer and outline is shown correctly using user defined color.
parent 006418ab
...@@ -33,6 +33,7 @@ import android.text.TextPaint; ...@@ -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;
...@@ -98,6 +99,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -98,6 +99,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;
...@@ -286,11 +288,32 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -286,11 +288,32 @@ 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.
// Otherwise we use two painters, and one need to apply the background in the first one only
if (Color.alpha(backgroundColor) > 0) { if (Color.alpha(backgroundColor) > 0) {
SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText); if (edgeType == CaptionStyleCompat.EDGE_TYPE_NONE ||
newCueText.setSpan( edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) {
new BackgroundColorSpan(backgroundColor), 0, newCueText.length(), Spanned.SPAN_PRIORITY); SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText);
cueText = newCueText; newCueText.setSpan(
new BackgroundColorSpan(backgroundColor), 0, newCueText.length(), Spanned.SPAN_PRIORITY);
cueText = newCueText;
} else {
SpannableStringBuilder newCueText = new SpannableStringBuilder(cueTextEdge);
newCueText.setSpan(
new BackgroundColorSpan(backgroundColor), 0, newCueText.length(), Spanned.SPAN_PRIORITY);
cueTextEdge = newCueText;
}
} }
Alignment textAlignment = cueTextAlignment == null ? Alignment.ALIGN_CENTER : cueTextAlignment; Alignment textAlignment = cueTextAlignment == null ? Alignment.ALIGN_CENTER : cueTextAlignment;
...@@ -366,6 +389,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -366,6 +389,8 @@ 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;
...@@ -425,7 +450,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -425,7 +450,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
...@@ -437,7 +462,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -437,7 +462,7 @@ 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);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment