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();
}
}