mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add vertical text support to TtmlDecoder
I needed to use Cue.Builder instead of just SpannableStringBuilder for the regionOutput values, so I could attach the vertical info where appropriate (since this is a property of the Cue, not a span). PiperOrigin-RevId: 290709294
This commit is contained in:
parent
37908dd4df
commit
3aa52c2317
@ -497,12 +497,36 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the cue image. */
|
||||
/**
|
||||
* Gets the cue text.
|
||||
*
|
||||
* @see Cue#text
|
||||
*/
|
||||
@Nullable
|
||||
public CharSequence getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cue image.
|
||||
*
|
||||
* @see Cue#bitmap
|
||||
*/
|
||||
public Builder setBitmap(Bitmap bitmap) {
|
||||
this.bitmap = bitmap;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cue image.
|
||||
*
|
||||
* @see Cue#bitmap
|
||||
*/
|
||||
@Nullable
|
||||
public Bitmap getBitmap() {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alignment of the cue text within the cue box.
|
||||
*
|
||||
@ -515,6 +539,16 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alignment of the cue text within the cue box, or null if the alignment is undefined.
|
||||
*
|
||||
* @see Cue#textAlignment
|
||||
*/
|
||||
@Nullable
|
||||
public Alignment getTextAlignment() {
|
||||
return textAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the position of the {@code lineAnchor} of the cue box within the viewport in the
|
||||
* direction orthogonal to the writing direction.
|
||||
@ -561,6 +595,26 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of the {@code lineAnchor} of the cue box within the viewport in the
|
||||
* direction orthogonal to the writing direction.
|
||||
*
|
||||
* @see Cue#line
|
||||
*/
|
||||
public float getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the value of {@link #getLine()}.
|
||||
*
|
||||
* @see Cue#lineType
|
||||
*/
|
||||
@LineType
|
||||
public int getLineType() {
|
||||
return lineType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cue box anchor positioned by {@link #setLine(float, int) line}.
|
||||
*
|
||||
@ -575,6 +629,16 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cue box anchor positioned by {@link #setLine(float, int) line}.
|
||||
*
|
||||
* @see Cue#lineAnchor
|
||||
*/
|
||||
@AnchorType
|
||||
public int getLineAnchor() {
|
||||
return lineAnchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fractional position of the {@link #setPositionAnchor(int) positionAnchor} of the cue
|
||||
* box within the viewport in the direction orthogonal to {@link #setLine(float, int) line}.
|
||||
@ -590,6 +654,16 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fractional position of the {@link #setPositionAnchor(int) positionAnchor} of the cue
|
||||
* box within the viewport in the direction orthogonal to {@link #setLine(float, int) line}.
|
||||
*
|
||||
* @see Cue#position
|
||||
*/
|
||||
public float getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cue box anchor positioned by {@link #setPosition(float) position}.
|
||||
*
|
||||
@ -605,7 +679,17 @@ public final class Cue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default text size type for this cue's text.
|
||||
* Gets the cue box anchor positioned by {@link #setPosition(float) position}.
|
||||
*
|
||||
* @see Cue#positionAnchor
|
||||
*/
|
||||
@AnchorType
|
||||
public int getPositionAnchor() {
|
||||
return positionAnchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default text size and type for this cue's text.
|
||||
*
|
||||
* @see Cue#textSize
|
||||
* @see Cue#textSizeType
|
||||
@ -616,12 +700,29 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default text size type for this cue's text.
|
||||
*
|
||||
* @see Cue#textSizeType
|
||||
*/
|
||||
@TextSizeType
|
||||
public int getTextSizeType() {
|
||||
return textSizeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default text size for this cue's text.
|
||||
*
|
||||
* @see Cue#textSize
|
||||
*/
|
||||
public float getTextSize() {
|
||||
return textSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of the cue box in the writing direction specified as a fraction of the viewport
|
||||
* size in that direction.
|
||||
*
|
||||
* @see Cue#textSize
|
||||
* @see Cue#textSizeType
|
||||
* @see Cue#size
|
||||
*/
|
||||
public Builder setSize(float size) {
|
||||
@ -630,7 +731,17 @@ public final class Cue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bitmap height as a fraction of the of the viewport size.
|
||||
* Gets the size of the cue box in the writing direction specified as a fraction of the viewport
|
||||
* size in that direction.
|
||||
*
|
||||
* @see Cue#size
|
||||
*/
|
||||
public float getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bitmap height as a fraction of the viewport size.
|
||||
*
|
||||
* @see Cue#bitmapHeight
|
||||
*/
|
||||
@ -639,6 +750,15 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bitmap height as a fraction of the viewport size.
|
||||
*
|
||||
* @see Cue#bitmapHeight
|
||||
*/
|
||||
public float getBitmapHeight() {
|
||||
return bitmapHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fill color of the window.
|
||||
*
|
||||
@ -653,6 +773,25 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fill color of the window is set.
|
||||
*
|
||||
* @see Cue#windowColorSet
|
||||
*/
|
||||
public boolean isWindowColorSet() {
|
||||
return windowColorSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fill color of the window.
|
||||
*
|
||||
* @see Cue#windowColor
|
||||
*/
|
||||
@ColorInt
|
||||
public int getWindowColor() {
|
||||
return windowColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertical formatting for this Cue.
|
||||
*
|
||||
@ -663,6 +802,16 @@ public final class Cue {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the vertical formatting for this Cue.
|
||||
*
|
||||
* @see Cue#verticalType
|
||||
*/
|
||||
@VerticalType
|
||||
public int getVerticalType() {
|
||||
return verticalType;
|
||||
}
|
||||
|
||||
/** Build the cue. */
|
||||
public Cue build() {
|
||||
return new Cue(
|
||||
|
@ -540,6 +540,21 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TtmlNode.ATTR_TTS_WRITING_MODE:
|
||||
switch (Util.toLowerInvariant(attributeValue)) {
|
||||
// TODO: Support horizontal RTL modes.
|
||||
case TtmlNode.VERTICAL:
|
||||
case TtmlNode.VERTICAL_LR:
|
||||
style = createIfNull(style).setVerticalType(Cue.VERTICAL_TYPE_LR);
|
||||
break;
|
||||
case TtmlNode.VERTICAL_RL:
|
||||
style = createIfNull(style).setVerticalType(Cue.VERTICAL_TYPE_RL);
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// ignore
|
||||
break;
|
||||
|
@ -28,7 +28,6 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@ -67,7 +66,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
public static final String ATTR_TTS_COLOR = "color";
|
||||
public static final String ATTR_TTS_TEXT_DECORATION = "textDecoration";
|
||||
public static final String ATTR_TTS_TEXT_ALIGN = "textAlign";
|
||||
public static final String ATTR_TTS_WRITING_MODE = "writingMode";
|
||||
|
||||
// Values for textDecoration
|
||||
public static final String LINETHROUGH = "linethrough";
|
||||
public static final String NO_LINETHROUGH = "nolinethrough";
|
||||
public static final String UNDERLINE = "underline";
|
||||
@ -75,12 +76,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
public static final String ITALIC = "italic";
|
||||
public static final String BOLD = "bold";
|
||||
|
||||
// Values for textAlign
|
||||
public static final String LEFT = "left";
|
||||
public static final String CENTER = "center";
|
||||
public static final String RIGHT = "right";
|
||||
public static final String START = "start";
|
||||
public static final String END = "end";
|
||||
|
||||
// Values for writingMode
|
||||
public static final String VERTICAL = "tb";
|
||||
public static final String VERTICAL_LR = "tblr";
|
||||
public static final String VERTICAL_RL = "tbrl";
|
||||
|
||||
@Nullable public final String tag;
|
||||
@Nullable public final String text;
|
||||
public final boolean isTextNode;
|
||||
@ -211,7 +218,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
List<Pair<String, String>> regionImageOutputs = new ArrayList<>();
|
||||
traverseForImage(timeUs, regionId, regionImageOutputs);
|
||||
|
||||
TreeMap<String, SpannableStringBuilder> regionTextOutputs = new TreeMap<>();
|
||||
TreeMap<String, Cue.Builder> regionTextOutputs = new TreeMap<>();
|
||||
traverseForText(timeUs, false, regionId, regionTextOutputs);
|
||||
traverseForStyle(timeUs, globalStyles, regionTextOutputs);
|
||||
|
||||
@ -242,20 +249,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
// Create text based cues.
|
||||
for (Entry<String, SpannableStringBuilder> entry : regionTextOutputs.entrySet()) {
|
||||
for (Map.Entry<String, Cue.Builder> entry : regionTextOutputs.entrySet()) {
|
||||
TtmlRegion region = Assertions.checkNotNull(regionMap.get(entry.getKey()));
|
||||
cues.add(
|
||||
new Cue(
|
||||
cleanUpText(entry.getValue()),
|
||||
/* textAlignment= */ null,
|
||||
region.line,
|
||||
region.lineType,
|
||||
region.lineAnchor,
|
||||
region.position,
|
||||
/* positionAnchor= */ Cue.TYPE_UNSET,
|
||||
region.width,
|
||||
region.textSizeType,
|
||||
region.textSize));
|
||||
Cue.Builder regionOutput = entry.getValue();
|
||||
cleanUpText((SpannableStringBuilder) Assertions.checkNotNull(regionOutput.getText()));
|
||||
regionOutput.setLine(region.line, region.lineType);
|
||||
regionOutput.setLineAnchor(region.lineAnchor);
|
||||
regionOutput.setPosition(region.position);
|
||||
regionOutput.setSize(region.width);
|
||||
regionOutput.setTextSize(region.textSize, region.textSizeType);
|
||||
cues.add(regionOutput.build());
|
||||
}
|
||||
|
||||
return cues;
|
||||
@ -277,7 +280,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
long timeUs,
|
||||
boolean descendsPNode,
|
||||
String inheritedRegion,
|
||||
Map<String, SpannableStringBuilder> regionOutputs) {
|
||||
Map<String, Cue.Builder> regionOutputs) {
|
||||
nodeStartsByRegion.clear();
|
||||
nodeEndsByRegion.clear();
|
||||
if (TAG_METADATA.equals(tag)) {
|
||||
@ -288,13 +291,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
String resolvedRegionId = ANONYMOUS_REGION_ID.equals(regionId) ? inheritedRegion : regionId;
|
||||
|
||||
if (isTextNode && descendsPNode) {
|
||||
getRegionOutput(resolvedRegionId, regionOutputs).append(Assertions.checkNotNull(text));
|
||||
getRegionOutputText(resolvedRegionId, regionOutputs).append(Assertions.checkNotNull(text));
|
||||
} else if (TAG_BR.equals(tag) && descendsPNode) {
|
||||
getRegionOutput(resolvedRegionId, regionOutputs).append('\n');
|
||||
getRegionOutputText(resolvedRegionId, regionOutputs).append('\n');
|
||||
} else if (isActive(timeUs)) {
|
||||
// This is a container node, which can contain zero or more children.
|
||||
for (Entry<String, SpannableStringBuilder> entry : regionOutputs.entrySet()) {
|
||||
nodeStartsByRegion.put(entry.getKey(), entry.getValue().length());
|
||||
for (Map.Entry<String, Cue.Builder> entry : regionOutputs.entrySet()) {
|
||||
nodeStartsByRegion.put(
|
||||
entry.getKey(), Assertions.checkNotNull(entry.getValue().getText()).length());
|
||||
}
|
||||
|
||||
boolean isPNode = TAG_P.equals(tag);
|
||||
@ -303,36 +307,38 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
regionOutputs);
|
||||
}
|
||||
if (isPNode) {
|
||||
TtmlRenderUtil.endParagraph(getRegionOutput(resolvedRegionId, regionOutputs));
|
||||
TtmlRenderUtil.endParagraph(getRegionOutputText(resolvedRegionId, regionOutputs));
|
||||
}
|
||||
|
||||
for (Entry<String, SpannableStringBuilder> entry : regionOutputs.entrySet()) {
|
||||
nodeEndsByRegion.put(entry.getKey(), entry.getValue().length());
|
||||
for (Map.Entry<String, Cue.Builder> entry : regionOutputs.entrySet()) {
|
||||
nodeEndsByRegion.put(
|
||||
entry.getKey(), Assertions.checkNotNull(entry.getValue().getText()).length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SpannableStringBuilder getRegionOutput(
|
||||
String resolvedRegionId, Map<String, SpannableStringBuilder> regionOutputs) {
|
||||
private static SpannableStringBuilder getRegionOutputText(
|
||||
String resolvedRegionId, Map<String, Cue.Builder> regionOutputs) {
|
||||
if (!regionOutputs.containsKey(resolvedRegionId)) {
|
||||
regionOutputs.put(resolvedRegionId, new SpannableStringBuilder());
|
||||
Cue.Builder regionOutput = new Cue.Builder();
|
||||
regionOutput.setText(new SpannableStringBuilder());
|
||||
regionOutputs.put(resolvedRegionId, regionOutput);
|
||||
}
|
||||
return regionOutputs.get(resolvedRegionId);
|
||||
return (SpannableStringBuilder)
|
||||
Assertions.checkNotNull(regionOutputs.get(resolvedRegionId).getText());
|
||||
}
|
||||
|
||||
private void traverseForStyle(
|
||||
long timeUs,
|
||||
Map<String, TtmlStyle> globalStyles,
|
||||
Map<String, SpannableStringBuilder> regionOutputs) {
|
||||
long timeUs, Map<String, TtmlStyle> globalStyles, Map<String, Cue.Builder> regionOutputs) {
|
||||
if (!isActive(timeUs)) {
|
||||
return;
|
||||
}
|
||||
for (Entry<String, Integer> entry : nodeEndsByRegion.entrySet()) {
|
||||
for (Map.Entry<String, Integer> entry : nodeEndsByRegion.entrySet()) {
|
||||
String regionId = entry.getKey();
|
||||
int start = nodeStartsByRegion.containsKey(regionId) ? nodeStartsByRegion.get(regionId) : 0;
|
||||
int end = entry.getValue();
|
||||
if (start != end) {
|
||||
SpannableStringBuilder regionOutput = Assertions.checkNotNull(regionOutputs.get(regionId));
|
||||
Cue.Builder regionOutput = Assertions.checkNotNull(regionOutputs.get(regionId));
|
||||
applyStyleToOutput(globalStyles, regionOutput, start, end);
|
||||
}
|
||||
}
|
||||
@ -342,17 +348,20 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
}
|
||||
|
||||
private void applyStyleToOutput(
|
||||
Map<String, TtmlStyle> globalStyles,
|
||||
SpannableStringBuilder regionOutput,
|
||||
int start,
|
||||
int end) {
|
||||
Map<String, TtmlStyle> globalStyles, Cue.Builder regionOutput, int start, int end) {
|
||||
@Nullable TtmlStyle resolvedStyle = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
|
||||
@Nullable SpannableStringBuilder text = (SpannableStringBuilder) regionOutput.getText();
|
||||
if (text == null) {
|
||||
text = new SpannableStringBuilder();
|
||||
regionOutput.setText(text);
|
||||
}
|
||||
if (resolvedStyle != null) {
|
||||
TtmlRenderUtil.applyStylesToSpan(regionOutput, start, end, resolvedStyle);
|
||||
TtmlRenderUtil.applyStylesToSpan(text, start, end, resolvedStyle);
|
||||
regionOutput.setVerticalType(resolvedStyle.getVerticalType());
|
||||
}
|
||||
}
|
||||
|
||||
private SpannableStringBuilder cleanUpText(SpannableStringBuilder builder) {
|
||||
private static void cleanUpText(SpannableStringBuilder builder) {
|
||||
// Having joined the text elements, we need to do some final cleanup on the result.
|
||||
// 1. Collapse multiple consecutive spaces into a single space.
|
||||
int builderLength = builder.length();
|
||||
@ -396,7 +405,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
builder.delete(builderLength - 1, builderLength);
|
||||
/*builderLength--;*/
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import android.graphics.Typeface;
|
||||
import android.text.Layout;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.Cue.VerticalType;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -73,6 +75,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
private float fontSize;
|
||||
private @MonotonicNonNull String id;
|
||||
private Layout.@MonotonicNonNull Alignment textAlign;
|
||||
@Cue.VerticalType private int verticalType;
|
||||
|
||||
public TtmlStyle() {
|
||||
linethrough = UNSPECIFIED;
|
||||
@ -80,6 +83,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
bold = UNSPECIFIED;
|
||||
italic = UNSPECIFIED;
|
||||
fontSizeUnit = UNSPECIFIED;
|
||||
verticalType = Cue.TYPE_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,6 +224,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
if (chaining && !hasBackgroundColor && ancestor.hasBackgroundColor) {
|
||||
setBackgroundColor(ancestor.backgroundColor);
|
||||
}
|
||||
if (chaining && verticalType != Cue.TYPE_UNSET && ancestor.verticalType == Cue.TYPE_UNSET) {
|
||||
setVerticalType(ancestor.verticalType);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -262,4 +269,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
return fontSize;
|
||||
}
|
||||
|
||||
public TtmlStyle setVerticalType(@VerticalType int verticalType) {
|
||||
this.verticalType = verticalType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@VerticalType
|
||||
public int getVerticalType() {
|
||||
return verticalType;
|
||||
}
|
||||
}
|
||||
|
17
library/core/src/test/assets/ttml/vertical_text.xml
Normal file
17
library/core/src/test/assets/ttml/vertical_text.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<tt xmlns:ttm="http://www.w3.org/2006/10/ttaf1#metadata"
|
||||
xmlns:ttp="http://www.w3.org/2006/10/ttaf1#parameter"
|
||||
xmlns:tts="http://www.w3.org/2006/10/ttaf1#style"
|
||||
xmlns="http://www.w3.org/ns/ttml"
|
||||
xmlns="http://www.w3.org/2006/10/ttaf1">
|
||||
<body>
|
||||
<div>
|
||||
<p begin="10s" end="18s" tts:writingMode="tbrl">Vertical right-to-left (e.g. Japanese)</p>
|
||||
</div>
|
||||
<div>
|
||||
<p begin="20s" end="28s" tts:writingMode="tblr">Vertical left-to-right (e.g. Mongolian)</p>
|
||||
</div>
|
||||
<div>
|
||||
<p begin="30s" end="38s">Horizontal text</p>
|
||||
</div>
|
||||
</body>
|
||||
</tt>
|
@ -66,6 +66,7 @@ public final class TtmlDecoderTest {
|
||||
private static final String BITMAP_REGION_FILE = "ttml/bitmap_percentage_region.xml";
|
||||
private static final String BITMAP_PIXEL_REGION_FILE = "ttml/bitmap_pixel_region.xml";
|
||||
private static final String BITMAP_UNSUPPORTED_REGION_FILE = "ttml/bitmap_unsupported_region.xml";
|
||||
private static final String VERTICAL_TEXT_FILE = "ttml/vertical_text.xml";
|
||||
|
||||
@Test
|
||||
public void testInlineAttributes() throws IOException, SubtitleDecoderException {
|
||||
@ -587,6 +588,26 @@ public final class TtmlDecoderTest {
|
||||
assertThat(cue.bitmapHeight).isEqualTo(Cue.DIMEN_UNSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVerticalText() throws IOException, SubtitleDecoderException {
|
||||
TtmlSubtitle subtitle = getSubtitle(VERTICAL_TEXT_FILE);
|
||||
|
||||
List<Cue> firstCues = subtitle.getCues(10_000_000);
|
||||
assertThat(firstCues).hasSize(1);
|
||||
Cue firstCue = firstCues.get(0);
|
||||
assertThat(firstCue.verticalType).isEqualTo(Cue.VERTICAL_TYPE_RL);
|
||||
|
||||
List<Cue> secondCues = subtitle.getCues(20_000_000);
|
||||
assertThat(secondCues).hasSize(1);
|
||||
Cue secondCue = secondCues.get(0);
|
||||
assertThat(secondCue.verticalType).isEqualTo(Cue.VERTICAL_TYPE_LR);
|
||||
|
||||
List<Cue> thirdCues = subtitle.getCues(30_000_000);
|
||||
assertThat(thirdCues).hasSize(1);
|
||||
Cue thirdCue = thirdCues.get(0);
|
||||
assertThat(thirdCue.verticalType).isEqualTo(Cue.TYPE_UNSET);
|
||||
}
|
||||
|
||||
private void assertSpans(
|
||||
TtmlSubtitle subtitle,
|
||||
int second,
|
||||
|
Loading…
x
Reference in New Issue
Block a user