From e8863d5668042ce04f569f1970fb1219b56ac796 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:16:48 +0100 Subject: [PATCH 1/5] Add `outlineWidth` to `Cue` and `SubtitlePainter` --- .../java/androidx/media3/common/text/Cue.java | 48 +++++++++++++++++-- .../androidx/media3/ui/SubtitlePainter.java | 37 +++++++++----- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java index 719a1889fb5..b2d3dcab279 100644 --- a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java +++ b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java @@ -37,6 +37,7 @@ import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import androidx.annotation.Px; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -272,6 +273,11 @@ public final class Cue { */ public final float size; + /** + * The size of the text outline stroke in pixels or {@link #DIMEN_UNSET} for default width. + */ + public final @Px float outlineWidth; + /** * The bitmap height as a fraction of the of the viewport size, or {@link #DIMEN_UNSET} if the * bitmap should be displayed at its natural height given the bitmap dimensions and the specified @@ -326,7 +332,8 @@ private Cue( boolean windowColorSet, int windowColor, @VerticalType int verticalType, - float shearDegrees) { + float shearDegrees, + @Px float outlineWidth) { // Exactly one of text or bitmap should be set. if (text == null) { Assertions.checkNotNull(bitmap); @@ -356,6 +363,7 @@ private Cue( this.textSize = textSize; this.verticalType = verticalType; this.shearDegrees = shearDegrees; + this.outlineWidth = outlineWidth; } /** Returns a new {@link Cue.Builder} initialized with the same values as this Cue. */ @@ -391,7 +399,8 @@ public boolean equals(@Nullable Object obj) { && textSizeType == that.textSizeType && textSize == that.textSize && verticalType == that.verticalType - && shearDegrees == that.shearDegrees; + && shearDegrees == that.shearDegrees + && outlineWidth == that.outlineWidth; } @Override @@ -413,7 +422,8 @@ public int hashCode() { textSizeType, textSize, verticalType, - shearDegrees); + shearDegrees, + outlineWidth); } /** A builder for {@link Cue} objects. */ @@ -436,6 +446,7 @@ public static final class Builder { @ColorInt private int windowColor; private @VerticalType int verticalType; private float shearDegrees; + private @Px float outlineWidth; public Builder() { text = null; @@ -454,6 +465,7 @@ public Builder() { windowColorSet = false; windowColor = Color.BLACK; verticalType = TYPE_UNSET; + outlineWidth = DIMEN_UNSET; } private Builder(Cue cue) { @@ -474,6 +486,7 @@ private Builder(Cue cue) { windowColor = cue.windowColor; verticalType = cue.verticalType; shearDegrees = cue.shearDegrees; + outlineWidth = cue.outlineWidth; } /** @@ -715,6 +728,27 @@ public float getSize() { return size; } + /** + * Sets the outline width in pixels + * + * @see Cue#outlineWidth + */ + @CanIgnoreReturnValue + public Builder setOutlineWidth(@Px float outlineWidth) { + this.outlineWidth = outlineWidth; + return this; + } + + /** + * Gets the outline width in pixels + * + * @see Cue#outlineWidth + */ + @Pure + public float getOutlineWidth() { + return outlineWidth; + } + /** * Sets the bitmap height as a fraction of the viewport size. * @@ -825,7 +859,8 @@ public Cue build() { windowColorSet, windowColor, verticalType, - shearDegrees); + shearDegrees, + outlineWidth); } } @@ -848,6 +883,7 @@ public Cue build() { private static final String FIELD_WINDOW_COLOR_SET = Util.intToStringMaxRadix(14); private static final String FIELD_VERTICAL_TYPE = Util.intToStringMaxRadix(15); private static final String FIELD_SHEAR_DEGREES = Util.intToStringMaxRadix(16); + private static final String FIELD_OUTLINE_WIDTH = Util.intToStringMaxRadix(19); /** * Returns a {@link Bundle} that can be serialized to bytes. @@ -923,6 +959,7 @@ private Bundle toBundleWithoutBitmap() { bundle.putInt(FIELD_WINDOW_COLOR, windowColor); bundle.putInt(FIELD_VERTICAL_TYPE, verticalType); bundle.putFloat(FIELD_SHEAR_DEGREES, shearDegrees); + bundle.putFloat(FIELD_OUTLINE_WIDTH, outlineWidth); return bundle; } @@ -995,6 +1032,9 @@ public static Cue fromBundle(Bundle bundle) { if (bundle.containsKey(FIELD_SHEAR_DEGREES)) { builder.setShearDegrees(bundle.getFloat(FIELD_SHEAR_DEGREES)); } + if (bundle.containsKey(FIELD_OUTLINE_WIDTH)) { + builder.setOutlineWidth(bundle.getFloat(FIELD_OUTLINE_WIDTH)); + } return builder.build(); } } diff --git a/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java b/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java index 697024f1d8f..215dc02f122 100644 --- a/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java +++ b/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java @@ -52,9 +52,12 @@ private static final float INNER_PADDING_RATIO = 0.125f; // Styled dimensions. - private final float outlineWidth; - private final float shadowRadius; - private final float shadowOffset; + private float outlineWidth; + private float shadowRadius; + private float shadowOffset; + private final float defaultOutlineWidth; + private final float defaultShadowRadius; + private final float defaultShadowOffset; private final float spacingMult; private final float spacingAdd; @@ -105,9 +108,14 @@ public SubtitlePainter(Context context) { Resources resources = context.getResources(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); int twoDpInPx = Math.round((2f * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); - outlineWidth = twoDpInPx; - shadowRadius = twoDpInPx; - shadowOffset = twoDpInPx; + + outlineWidth = Cue.DIMEN_UNSET; + shadowRadius = Cue.DIMEN_UNSET; + shadowOffset = Cue.DIMEN_UNSET; + + defaultOutlineWidth = twoDpInPx; + defaultShadowRadius = twoDpInPx; + defaultShadowOffset = twoDpInPx; textPaint = new TextPaint(); textPaint.setAntiAlias(true); @@ -213,6 +221,9 @@ public void draw( this.parentTop = cueBoxTop; this.parentRight = cueBoxRight; this.parentBottom = cueBoxBottom; + this.outlineWidth = cue.outlineWidth; + this.shadowRadius = cue.outlineWidth; + this.shadowOffset = cue.outlineWidth; if (isTextCue) { Assertions.checkNotNull(cueText); @@ -425,24 +436,28 @@ private void drawTextLayout(Canvas canvas) { } if (edgeType == CaptionStyleCompat.EDGE_TYPE_OUTLINE) { + float localWidth = outlineWidth != Cue.DIMEN_UNSET ? outlineWidth : defaultOutlineWidth; textPaint.setStrokeJoin(Join.ROUND); - textPaint.setStrokeWidth(outlineWidth); + textPaint.setStrokeWidth(localWidth); textPaint.setColor(edgeColor); textPaint.setStyle(Style.FILL_AND_STROKE); edgeLayout.draw(canvas); } else if (edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) { - textPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, edgeColor); + float localOffset = shadowOffset != Cue.DIMEN_UNSET ? shadowOffset : defaultShadowOffset; + float localRadius = shadowRadius != Cue.DIMEN_UNSET ? shadowRadius : defaultShadowRadius; + textPaint.setShadowLayer(localRadius, localOffset, localOffset, edgeColor); } else if (edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED || edgeType == CaptionStyleCompat.EDGE_TYPE_DEPRESSED) { boolean raised = edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED; int colorUp = raised ? Color.WHITE : edgeColor; int colorDown = raised ? edgeColor : Color.WHITE; - float offset = shadowRadius / 2f; + float localRadius = shadowRadius != Cue.DIMEN_UNSET ? shadowRadius : defaultShadowRadius; + float offset = localRadius / 2f; textPaint.setColor(foregroundColor); textPaint.setStyle(Style.FILL); - textPaint.setShadowLayer(shadowRadius, -offset, -offset, colorUp); + textPaint.setShadowLayer(localRadius, -offset, -offset, colorUp); edgeLayout.draw(canvas); - textPaint.setShadowLayer(shadowRadius, offset, offset, colorDown); + textPaint.setShadowLayer(localRadius, offset, offset, colorDown); } textPaint.setColor(foregroundColor); From 923139bdce4cb35d6ee5e8b75caa53d5578281f7 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 1 Nov 2024 18:15:37 +0100 Subject: [PATCH 2/5] Revert "Add `outlineWidth` to `Cue` and `SubtitlePainter`" This reverts commit e8863d5668042ce04f569f1970fb1219b56ac796. --- .../java/androidx/media3/common/text/Cue.java | 48 ++----------------- .../androidx/media3/ui/SubtitlePainter.java | 37 +++++--------- 2 files changed, 15 insertions(+), 70 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java index b2d3dcab279..719a1889fb5 100644 --- a/libraries/common/src/main/java/androidx/media3/common/text/Cue.java +++ b/libraries/common/src/main/java/androidx/media3/common/text/Cue.java @@ -37,7 +37,6 @@ import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.Nullable; -import androidx.annotation.Px; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -273,11 +272,6 @@ public final class Cue { */ public final float size; - /** - * The size of the text outline stroke in pixels or {@link #DIMEN_UNSET} for default width. - */ - public final @Px float outlineWidth; - /** * The bitmap height as a fraction of the of the viewport size, or {@link #DIMEN_UNSET} if the * bitmap should be displayed at its natural height given the bitmap dimensions and the specified @@ -332,8 +326,7 @@ private Cue( boolean windowColorSet, int windowColor, @VerticalType int verticalType, - float shearDegrees, - @Px float outlineWidth) { + float shearDegrees) { // Exactly one of text or bitmap should be set. if (text == null) { Assertions.checkNotNull(bitmap); @@ -363,7 +356,6 @@ private Cue( this.textSize = textSize; this.verticalType = verticalType; this.shearDegrees = shearDegrees; - this.outlineWidth = outlineWidth; } /** Returns a new {@link Cue.Builder} initialized with the same values as this Cue. */ @@ -399,8 +391,7 @@ public boolean equals(@Nullable Object obj) { && textSizeType == that.textSizeType && textSize == that.textSize && verticalType == that.verticalType - && shearDegrees == that.shearDegrees - && outlineWidth == that.outlineWidth; + && shearDegrees == that.shearDegrees; } @Override @@ -422,8 +413,7 @@ public int hashCode() { textSizeType, textSize, verticalType, - shearDegrees, - outlineWidth); + shearDegrees); } /** A builder for {@link Cue} objects. */ @@ -446,7 +436,6 @@ public static final class Builder { @ColorInt private int windowColor; private @VerticalType int verticalType; private float shearDegrees; - private @Px float outlineWidth; public Builder() { text = null; @@ -465,7 +454,6 @@ public Builder() { windowColorSet = false; windowColor = Color.BLACK; verticalType = TYPE_UNSET; - outlineWidth = DIMEN_UNSET; } private Builder(Cue cue) { @@ -486,7 +474,6 @@ private Builder(Cue cue) { windowColor = cue.windowColor; verticalType = cue.verticalType; shearDegrees = cue.shearDegrees; - outlineWidth = cue.outlineWidth; } /** @@ -728,27 +715,6 @@ public float getSize() { return size; } - /** - * Sets the outline width in pixels - * - * @see Cue#outlineWidth - */ - @CanIgnoreReturnValue - public Builder setOutlineWidth(@Px float outlineWidth) { - this.outlineWidth = outlineWidth; - return this; - } - - /** - * Gets the outline width in pixels - * - * @see Cue#outlineWidth - */ - @Pure - public float getOutlineWidth() { - return outlineWidth; - } - /** * Sets the bitmap height as a fraction of the viewport size. * @@ -859,8 +825,7 @@ public Cue build() { windowColorSet, windowColor, verticalType, - shearDegrees, - outlineWidth); + shearDegrees); } } @@ -883,7 +848,6 @@ public Cue build() { private static final String FIELD_WINDOW_COLOR_SET = Util.intToStringMaxRadix(14); private static final String FIELD_VERTICAL_TYPE = Util.intToStringMaxRadix(15); private static final String FIELD_SHEAR_DEGREES = Util.intToStringMaxRadix(16); - private static final String FIELD_OUTLINE_WIDTH = Util.intToStringMaxRadix(19); /** * Returns a {@link Bundle} that can be serialized to bytes. @@ -959,7 +923,6 @@ private Bundle toBundleWithoutBitmap() { bundle.putInt(FIELD_WINDOW_COLOR, windowColor); bundle.putInt(FIELD_VERTICAL_TYPE, verticalType); bundle.putFloat(FIELD_SHEAR_DEGREES, shearDegrees); - bundle.putFloat(FIELD_OUTLINE_WIDTH, outlineWidth); return bundle; } @@ -1032,9 +995,6 @@ public static Cue fromBundle(Bundle bundle) { if (bundle.containsKey(FIELD_SHEAR_DEGREES)) { builder.setShearDegrees(bundle.getFloat(FIELD_SHEAR_DEGREES)); } - if (bundle.containsKey(FIELD_OUTLINE_WIDTH)) { - builder.setOutlineWidth(bundle.getFloat(FIELD_OUTLINE_WIDTH)); - } return builder.build(); } } diff --git a/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java b/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java index 215dc02f122..697024f1d8f 100644 --- a/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java +++ b/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java @@ -52,12 +52,9 @@ private static final float INNER_PADDING_RATIO = 0.125f; // Styled dimensions. - private float outlineWidth; - private float shadowRadius; - private float shadowOffset; - private final float defaultOutlineWidth; - private final float defaultShadowRadius; - private final float defaultShadowOffset; + private final float outlineWidth; + private final float shadowRadius; + private final float shadowOffset; private final float spacingMult; private final float spacingAdd; @@ -108,14 +105,9 @@ public SubtitlePainter(Context context) { Resources resources = context.getResources(); DisplayMetrics displayMetrics = resources.getDisplayMetrics(); int twoDpInPx = Math.round((2f * displayMetrics.densityDpi) / DisplayMetrics.DENSITY_DEFAULT); - - outlineWidth = Cue.DIMEN_UNSET; - shadowRadius = Cue.DIMEN_UNSET; - shadowOffset = Cue.DIMEN_UNSET; - - defaultOutlineWidth = twoDpInPx; - defaultShadowRadius = twoDpInPx; - defaultShadowOffset = twoDpInPx; + outlineWidth = twoDpInPx; + shadowRadius = twoDpInPx; + shadowOffset = twoDpInPx; textPaint = new TextPaint(); textPaint.setAntiAlias(true); @@ -221,9 +213,6 @@ public void draw( this.parentTop = cueBoxTop; this.parentRight = cueBoxRight; this.parentBottom = cueBoxBottom; - this.outlineWidth = cue.outlineWidth; - this.shadowRadius = cue.outlineWidth; - this.shadowOffset = cue.outlineWidth; if (isTextCue) { Assertions.checkNotNull(cueText); @@ -436,28 +425,24 @@ private void drawTextLayout(Canvas canvas) { } if (edgeType == CaptionStyleCompat.EDGE_TYPE_OUTLINE) { - float localWidth = outlineWidth != Cue.DIMEN_UNSET ? outlineWidth : defaultOutlineWidth; textPaint.setStrokeJoin(Join.ROUND); - textPaint.setStrokeWidth(localWidth); + textPaint.setStrokeWidth(outlineWidth); textPaint.setColor(edgeColor); textPaint.setStyle(Style.FILL_AND_STROKE); edgeLayout.draw(canvas); } else if (edgeType == CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW) { - float localOffset = shadowOffset != Cue.DIMEN_UNSET ? shadowOffset : defaultShadowOffset; - float localRadius = shadowRadius != Cue.DIMEN_UNSET ? shadowRadius : defaultShadowRadius; - textPaint.setShadowLayer(localRadius, localOffset, localOffset, edgeColor); + textPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, edgeColor); } else if (edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED || edgeType == CaptionStyleCompat.EDGE_TYPE_DEPRESSED) { boolean raised = edgeType == CaptionStyleCompat.EDGE_TYPE_RAISED; int colorUp = raised ? Color.WHITE : edgeColor; int colorDown = raised ? edgeColor : Color.WHITE; - float localRadius = shadowRadius != Cue.DIMEN_UNSET ? shadowRadius : defaultShadowRadius; - float offset = localRadius / 2f; + float offset = shadowRadius / 2f; textPaint.setColor(foregroundColor); textPaint.setStyle(Style.FILL); - textPaint.setShadowLayer(localRadius, -offset, -offset, colorUp); + textPaint.setShadowLayer(shadowRadius, -offset, -offset, colorUp); edgeLayout.draw(canvas); - textPaint.setShadowLayer(localRadius, offset, offset, colorDown); + textPaint.setShadowLayer(shadowRadius, offset, offset, colorDown); } textPaint.setColor(foregroundColor); From 75c855e2bae18216aba86a0b38858d4a09cae251 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 1 Nov 2024 18:53:38 +0100 Subject: [PATCH 3/5] Added OutlineSpan --- .../media3/common/text/CustomSpanBundler.java | 12 +++++- .../media3/common/text/OutlineSpan.java | 41 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 libraries/common/src/main/java/androidx/media3/common/text/OutlineSpan.java diff --git a/libraries/common/src/main/java/androidx/media3/common/text/CustomSpanBundler.java b/libraries/common/src/main/java/androidx/media3/common/text/CustomSpanBundler.java index edcda586d2d..0734e684993 100644 --- a/libraries/common/src/main/java/androidx/media3/common/text/CustomSpanBundler.java +++ b/libraries/common/src/main/java/androidx/media3/common/text/CustomSpanBundler.java @@ -53,12 +53,13 @@ *