diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleWebView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleWebView.java index 7ca75c1196..e8cd6ff2d1 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleWebView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleWebView.java @@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.ui.SubtitleView.DEFAULT_TEXT_SIZE_FR import android.content.Context; import android.graphics.Color; +import android.text.Layout; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewGroup; @@ -28,6 +29,7 @@ import android.webkit.WebView; import androidx.annotation.Nullable; import com.google.android.exoplayer2.text.CaptionStyleCompat; import com.google.android.exoplayer2.text.Cue; +import com.google.android.exoplayer2.util.Util; import java.util.Collections; import java.util.List; @@ -148,18 +150,116 @@ import java.util.List; } private void updateWebView() { - StringBuilder cueText = new StringBuilder(); + StringBuilder html = new StringBuilder(); + html.append("") + .append("
"); + for (int i = 0; i < cues.size(); i++) { - if (i > 0) { - cueText.append("
"); + float horizontalPositionPercent; + int horizontalTranslatePercent; + Cue cue = cues.get(i); + if (cue.position != Cue.DIMEN_UNSET) { + horizontalPositionPercent = cue.position * 100; + horizontalTranslatePercent = translatePercentFromAnchorType(cue.positionAnchor); + } else { + horizontalPositionPercent = 50; + horizontalTranslatePercent = -50; } - cueText.append(SpannedToHtmlConverter.convert(cues.get(i).text)); + + float verticalPositionPercent; + int verticalTranslatePercent; + if (cue.line != Cue.DIMEN_UNSET) { + verticalTranslatePercent = translatePercentFromAnchorType(cue.lineAnchor); + switch (cue.lineType) { + case Cue.LINE_TYPE_FRACTION: + verticalPositionPercent = cue.line * 100; + break; + case Cue.LINE_TYPE_NUMBER: + if (cue.line >= 0) { + verticalPositionPercent = 0; + verticalTranslatePercent += Math.round(cue.line) * 100; + } else { + verticalPositionPercent = 100; + verticalTranslatePercent += Math.round(cue.line + 1) * 100; + } + break; + case Cue.TYPE_UNSET: + default: + verticalPositionPercent = 0; + break; + } + } else { + verticalPositionPercent = 100; + verticalTranslatePercent = -100; + } + + String width = + cue.size != Cue.DIMEN_UNSET + ? Util.formatInvariant("%.2f%%", cue.size * 100) + : "fit-content"; + + String textAlign = convertAlignmentToCss(cue.textAlignment); + + html.append( + Util.formatInvariant( + "
", + horizontalPositionPercent, + verticalPositionPercent, + width, + textAlign, + horizontalTranslatePercent, + verticalTranslatePercent)) + .append(SpannedToHtmlConverter.convert(cue.text)) + .append("
"); } - webView.loadData( - "

" - + cueText - + "

", - "text/html", - /* encoding= */ null); + + html.append("
"); + + webView.loadData(html.toString(), "text/html", /* encoding= */ null); + } + + private String convertAlignmentToCss(@Nullable Layout.Alignment alignment) { + if (alignment == null) { + return "unset"; + } + switch (alignment) { + case ALIGN_NORMAL: + return "start"; + case ALIGN_CENTER: + return "center"; + case ALIGN_OPPOSITE: + return "end"; + default: + return "unset"; + } + } + + private static int translatePercentFromAnchorType(@Cue.AnchorType int anchorType) { + switch (anchorType) { + case Cue.TYPE_UNSET: + case Cue.ANCHOR_TYPE_START: + return 0; + case Cue.ANCHOR_TYPE_MIDDLE: + return -50; + case Cue.ANCHOR_TYPE_END: + return -100; + } + throw new IllegalArgumentException(); } }