Commit 06c17f51 by ibaker Committed by Christos Tsilopoulos

Redefine numeric Cue.line in terms of viewport lines, ignore lineAnchor

Numerical lines conceptually map to a grid of lines in the viewport,
with the Cue text lines being aligned to one of the viewport lines.

It doesn't make sense to position a single-line cue differently based
on lineAnchor when it's expected to 'snap' to a particular line on the
viewport grid. So we redefine the position to be in terms of the cue
lines rather than the bounds of the cue box.

It's also not possible to always handle ANCHOR_TYPE_MIDDLE when
lineType=NUMBER (as it relies on the number of lines in the cue being
odd), so it's easier to ignore lineAnchor completely.
PiperOrigin-RevId: 318034664
parent 4138e28d
...@@ -133,6 +133,8 @@ ...@@ -133,6 +133,8 @@
* Add support for WebVTT's `ruby-position` CSS property. * Add support for WebVTT's `ruby-position` CSS property.
* Fix positioning for CEA-608 roll-up captions in the top half of screen * Fix positioning for CEA-608 roll-up captions in the top half of screen
([#7475](https://github.com/google/ExoPlayer/issues/7475)). ([#7475](https://github.com/google/ExoPlayer/issues/7475)).
* Redefine `Cue.lineType=LINE_TYPE_NUMBER` in terms of aligning the cue
text lines to grid of viewport lines, and ignore `Cue.lineAnchor`.
* DRM: * DRM:
* Add support for attaching DRM sessions to clear content in the demo app. * Add support for attaching DRM sessions to clear content in the demo app.
* Remove `DrmSessionManager` references from all renderers. * Remove `DrmSessionManager` references from all renderers.
......
...@@ -526,6 +526,13 @@ ...@@ -526,6 +526,13 @@
"subtitle_language": "en" "subtitle_language": "en"
}, },
{ {
"name": "WebVTT line positioning",
"uri": "https://html5demos.com/assets/dizzy.mp4",
"subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/webvtt/numeric-lines.vtt",
"subtitle_mime_type": "text/vtt",
"subtitle_language": "en"
},
{
"name": "SSA/ASS position & alignment", "name": "SSA/ASS position & alignment",
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4", "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4",
"subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ssa/test-subs-position.ass", "subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ssa/test-subs-position.ass",
......
...@@ -144,10 +144,9 @@ public final class Cue { ...@@ -144,10 +144,9 @@ public final class Cue {
@Nullable public final Bitmap bitmap; @Nullable public final Bitmap bitmap;
/** /**
* The position of the {@link #lineAnchor} of the cue box within the viewport in the direction * The position of the cue box within the viewport in the direction orthogonal to the writing
* orthogonal to the writing direction (determined by {@link #verticalType}), or {@link * direction (determined by {@link #verticalType}), or {@link #DIMEN_UNSET}. When set, the
* #DIMEN_UNSET}. When set, the interpretation of the value depends on the value of {@link * interpretation of the value depends on the value of {@link #lineType}.
* #lineType}.
* *
* <p>The measurement direction depends on {@link #verticalType}: * <p>The measurement direction depends on {@link #verticalType}:
* *
...@@ -167,40 +166,35 @@ public final class Cue { ...@@ -167,40 +166,35 @@ public final class Cue {
* *
* <ul> * <ul>
* <li>{@link #LINE_TYPE_FRACTION} indicates that {@link #line} is a fractional position within * <li>{@link #LINE_TYPE_FRACTION} indicates that {@link #line} is a fractional position within
* the viewport. * the viewport (measured to the part of the cue box determined by {@link #lineAnchor}).
* <li>{@link #LINE_TYPE_NUMBER} indicates that {@link #line} is a line number, where the size * <li>{@link #LINE_TYPE_NUMBER} indicates that {@link #line} is a viewport line number. The
* of each line is taken to be the size of the first line of the cue. * viewport is divided into lines (each equal in size to the first line of the cue box). The
* cue box is positioned to align with the viewport lines as follows:
* <ul> * <ul>
* <li>When {@link #line} is greater than or equal to 0 lines count from the start of the * <li>{@link #lineAnchor}) is ignored.
* viewport, with 0 indicating zero offset from the start edge. When {@link #line} is * <li>When {@code line} is greater than or equal to 0 the first line in the cue box is
* negative lines count from the end of the viewport, with -1 indicating zero offset * aligned with a viewport line, with 0 meaning the first line of the viewport.
* from the end edge. * <li>When {@code line} is negative the last line in the cue box is aligned with a
* <li>For horizontal text the line spacing is the height of the first line of the cue, * viewport line, with -1 meaning the last line of the viewport.
* and the start and end of the viewport are the top and bottom respectively. * <li>For horizontal text the start and end of the viewport are the top and bottom
* </ul> * respectively.
* </ul> * </ul>
*
* <p>Note that it's particularly important to consider the effect of {@link #lineAnchor} when
* using {@link #LINE_TYPE_NUMBER}.
*
* <ul>
* <li>{@code (line == 0 && lineAnchor == ANCHOR_TYPE_START)} positions a (potentially
* multi-line) cue at the very start of the viewport.
* <li>{@code (line == -1 && lineAnchor == ANCHOR_TYPE_END)} positions a (potentially
* multi-line) cue at the very end of the viewport.
* <li>{@code (line == 0 && lineAnchor == ANCHOR_TYPE_END)} and {@code (line == -1 && lineAnchor
* == ANCHOR_TYPE_START)} position cues entirely outside of the viewport.
* <li>{@code (line == 1 && lineAnchor == ANCHOR_TYPE_END)} positions a cue so that only the
* last line is visible at the start of the viewport.
* <li>{@code (line == -2 && lineAnchor == ANCHOR_TYPE_START)} position a cue so that only its
* first line is visible at the end of the viewport.
* </ul> * </ul>
*/ */
public final @LineType int lineType; public final @LineType int lineType;
/** /**
* The cue box anchor positioned by {@link #line}. One of {@link #ANCHOR_TYPE_START}, {@link * The cue box anchor positioned by {@link #line} when {@link #lineType} is {@link
* #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}. * #LINE_TYPE_FRACTION}.
*
* <p>One of:
*
* <ul>
* <li>{@link #ANCHOR_TYPE_START}
* <li>{@link #ANCHOR_TYPE_MIDDLE}
* <li>{@link #ANCHOR_TYPE_END}
* <li>{@link #TYPE_UNSET}
* </ul>
* *
* <p>For the normal case of horizontal text, {@link #ANCHOR_TYPE_START}, {@link * <p>For the normal case of horizontal text, {@link #ANCHOR_TYPE_START}, {@link
* #ANCHOR_TYPE_MIDDLE} and {@link #ANCHOR_TYPE_END} correspond to the top, middle and bottom of * #ANCHOR_TYPE_MIDDLE} and {@link #ANCHOR_TYPE_END} correspond to the top, middle and bottom of
...@@ -584,8 +578,8 @@ public final class Cue { ...@@ -584,8 +578,8 @@ public final class Cue {
} }
/** /**
* Sets the position of the {@code lineAnchor} of the cue box within the viewport in the * Sets the position of the cue box within the viewport in the direction orthogonal to the
* direction orthogonal to the writing direction. * writing direction.
* *
* @see Cue#line * @see Cue#line
* @see Cue#lineType * @see Cue#lineType
......
...@@ -944,17 +944,14 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -944,17 +944,14 @@ public final class Cea608Decoder extends CeaDecoder {
break; break;
} }
int lineAnchor;
int line; int line;
// Note: Row indices are in the range [1-15], Cue.line counts from 0 (top) and -1 (bottom). // Note: Row indices are in the range [1-15], Cue.line counts from 0 (top) and -1 (bottom).
if (row > (BASE_ROW / 2)) { if (row > (BASE_ROW / 2)) {
lineAnchor = Cue.ANCHOR_TYPE_END;
line = row - BASE_ROW; line = row - BASE_ROW;
// Two line adjustments. The first is because line indices from the bottom of the window // Two line adjustments. The first is because line indices from the bottom of the window
// start from -1 rather than 0. The second is a blank row to act as the safe area. // start from -1 rather than 0. The second is a blank row to act as the safe area.
line -= 2; line -= 2;
} else { } else {
lineAnchor = Cue.ANCHOR_TYPE_START;
// The `row` of roll-up cues positions the bottom line (even for cues shown in the top // The `row` of roll-up cues positions the bottom line (even for cues shown in the top
// half of the screen), so we need to consider the number of rows in this cue. In // half of the screen), so we need to consider the number of rows in this cue. In
// non-roll-up, we don't need any further adjustments because we leave the first line // non-roll-up, we don't need any further adjustments because we leave the first line
...@@ -968,7 +965,7 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -968,7 +965,7 @@ public final class Cea608Decoder extends CeaDecoder {
Alignment.ALIGN_NORMAL, Alignment.ALIGN_NORMAL,
line, line,
Cue.LINE_TYPE_NUMBER, Cue.LINE_TYPE_NUMBER,
lineAnchor, /* lineAnchor= */ Cue.TYPE_UNSET,
position, position,
positionAnchor, positionAnchor,
Cue.DIMEN_UNSET); Cue.DIMEN_UNSET);
......
...@@ -391,13 +391,7 @@ public final class WebvttCueParser { ...@@ -391,13 +391,7 @@ public final class WebvttCueParser {
builder.line = WebvttParserUtil.parsePercentage(s); builder.line = WebvttParserUtil.parsePercentage(s);
builder.lineType = Cue.LINE_TYPE_FRACTION; builder.lineType = Cue.LINE_TYPE_FRACTION;
} else { } else {
int lineNumber = Integer.parseInt(s); builder.line = Integer.parseInt(s);
if (lineNumber < 0) {
// WebVTT defines line -1 as last visible row when lineAnchor is ANCHOR_TYPE_START, where-as
// Cue defines it to be the first row that's not visible.
lineNumber--;
}
builder.line = lineNumber;
builder.lineType = Cue.LINE_TYPE_NUMBER; builder.lineType = Cue.LINE_TYPE_NUMBER;
} }
} }
......
...@@ -85,16 +85,7 @@ import java.util.List; ...@@ -85,16 +85,7 @@ import java.util.List;
Collections.sort(cuesWithUnsetLine, (c1, c2) -> Long.compare(c1.startTimeUs, c2.startTimeUs)); Collections.sort(cuesWithUnsetLine, (c1, c2) -> Long.compare(c1.startTimeUs, c2.startTimeUs));
for (int i = 0; i < cuesWithUnsetLine.size(); i++) { for (int i = 0; i < cuesWithUnsetLine.size(); i++) {
Cue cue = cuesWithUnsetLine.get(i).cue; Cue cue = cuesWithUnsetLine.get(i).cue;
currentCues.add( currentCues.add(cue.buildUpon().setLine((float) (-1 - i), Cue.LINE_TYPE_NUMBER).build());
cue.buildUpon()
.setLine((float) (-1 - i), Cue.LINE_TYPE_NUMBER)
// WebVTT doesn't use 'line alignment' (i.e. Cue#lineAnchor) when computing position
// with snap-to-lines=true (i.e. Cue#LINE_TYPE_NUMBER) but Cue does use lineAnchor
// when describing how numeric cues should be displayed. So we have to manually set
// lineAnchor=ANCHOR_TYPE_END to avoid the bottom line of cues being off the screen.
// https://www.w3.org/TR/webvtt1/#processing-cue-settings
.setLineAnchor(Cue.ANCHOR_TYPE_END)
.build());
} }
return currentCues; return currentCues;
} }
......
...@@ -203,10 +203,6 @@ public class WebvttDecoderTest { ...@@ -203,10 +203,6 @@ public class WebvttDecoderTest {
// Unspecified values should use WebVTT defaults // Unspecified values should use WebVTT defaults
assertThat(firstCue.line).isEqualTo(-1f); assertThat(firstCue.line).isEqualTo(-1f);
assertThat(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
// WebVTT specifies START as the default, but it doesn't expect this to be used if
// lineType=NUMBER so we have to override it to END in this case, otherwise the Cue will be
// displayed off the bottom of the screen.
assertThat(firstCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
assertThat(firstCue.verticalType).isEqualTo(Cue.TYPE_UNSET); assertThat(firstCue.verticalType).isEqualTo(Cue.TYPE_UNSET);
assertThat(subtitle.getEventTime(2)).isEqualTo(2_345_000L); assertThat(subtitle.getEventTime(2)).isEqualTo(2_345_000L);
...@@ -232,7 +228,7 @@ public class WebvttDecoderTest { ...@@ -232,7 +228,7 @@ public class WebvttDecoderTest {
assertThat(subtitle.getEventTime(7)).isEqualTo(7_000_000L); assertThat(subtitle.getEventTime(7)).isEqualTo(7_000_000L);
Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6))); Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6)));
assertThat(fourthCue.text.toString()).isEqualTo("This is the fourth subtitle."); assertThat(fourthCue.text.toString()).isEqualTo("This is the fourth subtitle.");
assertThat(fourthCue.line).isEqualTo(-11f); assertThat(fourthCue.line).isEqualTo(-10f);
assertThat(fourthCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_START); assertThat(fourthCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_START);
assertThat(fourthCue.textAlignment).isEqualTo(Alignment.ALIGN_CENTER); assertThat(fourthCue.textAlignment).isEqualTo(Alignment.ALIGN_CENTER);
// Derived from `align:middle`: // Derived from `align:middle`:
...@@ -280,7 +276,6 @@ public class WebvttDecoderTest { ...@@ -280,7 +276,6 @@ public class WebvttDecoderTest {
assertThat(firstCue.text.toString()).isEqualTo("Displayed at the bottom for 3 seconds."); assertThat(firstCue.text.toString()).isEqualTo("Displayed at the bottom for 3 seconds.");
assertThat(firstCue.line).isEqualTo(-1f); assertThat(firstCue.line).isEqualTo(-1f);
assertThat(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(firstCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(firstCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
List<Cue> firstAndSecondCue = subtitle.getCues(subtitle.getEventTime(1)); List<Cue> firstAndSecondCue = subtitle.getCues(subtitle.getEventTime(1));
assertThat(firstAndSecondCue).hasSize(2); assertThat(firstAndSecondCue).hasSize(2);
...@@ -288,18 +283,15 @@ public class WebvttDecoderTest { ...@@ -288,18 +283,15 @@ public class WebvttDecoderTest {
.isEqualTo("Displayed at the bottom for 3 seconds."); .isEqualTo("Displayed at the bottom for 3 seconds.");
assertThat(firstAndSecondCue.get(0).line).isEqualTo(-1f); assertThat(firstAndSecondCue.get(0).line).isEqualTo(-1f);
assertThat(firstAndSecondCue.get(0).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(firstAndSecondCue.get(0).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(firstAndSecondCue.get(0).lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
assertThat(firstAndSecondCue.get(1).text.toString()) assertThat(firstAndSecondCue.get(1).text.toString())
.isEqualTo("Appears directly above for 1 second."); .isEqualTo("Appears directly above for 1 second.");
assertThat(firstAndSecondCue.get(1).line).isEqualTo(-2f); assertThat(firstAndSecondCue.get(1).line).isEqualTo(-2f);
assertThat(firstAndSecondCue.get(1).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(firstAndSecondCue.get(1).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(firstAndSecondCue.get(1).lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
Cue thirdCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(4))); Cue thirdCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(4)));
assertThat(thirdCue.text.toString()).isEqualTo("Displayed at the bottom for 2 seconds."); assertThat(thirdCue.text.toString()).isEqualTo("Displayed at the bottom for 2 seconds.");
assertThat(thirdCue.line).isEqualTo(-1f); assertThat(thirdCue.line).isEqualTo(-1f);
assertThat(thirdCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(thirdCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(thirdCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
List<Cue> thirdAndFourthCue = subtitle.getCues(subtitle.getEventTime(5)); List<Cue> thirdAndFourthCue = subtitle.getCues(subtitle.getEventTime(5));
assertThat(thirdAndFourthCue).hasSize(2); assertThat(thirdAndFourthCue).hasSize(2);
...@@ -307,19 +299,16 @@ public class WebvttDecoderTest { ...@@ -307,19 +299,16 @@ public class WebvttDecoderTest {
.isEqualTo("Displayed at the bottom for 2 seconds."); .isEqualTo("Displayed at the bottom for 2 seconds.");
assertThat(thirdAndFourthCue.get(0).line).isEqualTo(-1f); assertThat(thirdAndFourthCue.get(0).line).isEqualTo(-1f);
assertThat(thirdAndFourthCue.get(0).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(thirdAndFourthCue.get(0).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(thirdAndFourthCue.get(0).lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
assertThat(thirdAndFourthCue.get(1).text.toString()) assertThat(thirdAndFourthCue.get(1).text.toString())
.isEqualTo("Appears directly above the previous cue, then replaces it after 1 second."); .isEqualTo("Appears directly above the previous cue, then replaces it after 1 second.");
assertThat(thirdAndFourthCue.get(1).line).isEqualTo(-2f); assertThat(thirdAndFourthCue.get(1).line).isEqualTo(-2f);
assertThat(thirdAndFourthCue.get(1).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(thirdAndFourthCue.get(1).lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(thirdAndFourthCue.get(1).lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6))); Cue fourthCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(6)));
assertThat(fourthCue.text.toString()) assertThat(fourthCue.text.toString())
.isEqualTo("Appears directly above the previous cue, then replaces it after 1 second."); .isEqualTo("Appears directly above the previous cue, then replaces it after 1 second.");
assertThat(fourthCue.line).isEqualTo(-1f); assertThat(fourthCue.line).isEqualTo(-1f);
assertThat(fourthCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); assertThat(fourthCue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER);
assertThat(fourthCue.lineAnchor).isEqualTo(Cue.ANCHOR_TYPE_END);
} }
@Test @Test
......
...@@ -337,21 +337,24 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -337,21 +337,24 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
int textTop; int textTop;
if (cueLine != Cue.DIMEN_UNSET) { if (cueLine != Cue.DIMEN_UNSET) {
int anchorPosition;
if (cueLineType == Cue.LINE_TYPE_FRACTION) { if (cueLineType == Cue.LINE_TYPE_FRACTION) {
anchorPosition = Math.round(parentHeight * cueLine) + parentTop; int anchorPosition = Math.round(parentHeight * cueLine) + parentTop;
textTop =
cueLineAnchor == Cue.ANCHOR_TYPE_END
? anchorPosition - textHeight
: cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE
? (anchorPosition * 2 - textHeight) / 2
: anchorPosition;
} else { } else {
// cueLineType == Cue.LINE_TYPE_NUMBER // cueLineType == Cue.LINE_TYPE_NUMBER
int firstLineHeight = textLayout.getLineBottom(0) - textLayout.getLineTop(0); int firstLineHeight = textLayout.getLineBottom(0) - textLayout.getLineTop(0);
if (cueLine >= 0) { if (cueLine >= 0) {
anchorPosition = Math.round(cueLine * firstLineHeight) + parentTop; textTop = Math.round(cueLine * firstLineHeight) + parentTop;
} else { } else {
anchorPosition = Math.round((cueLine + 1) * firstLineHeight) + parentBottom; textTop = Math.round((cueLine + 1) * firstLineHeight) + parentBottom - textHeight;
} }
} }
textTop = cueLineAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textHeight
: cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorPosition * 2 - textHeight) / 2
: anchorPosition;
if (textTop + textHeight > parentBottom) { if (textTop + textHeight > parentBottom) {
textTop = parentBottom - textHeight; textTop = parentBottom - textHeight;
} else if (textTop < parentTop) { } else if (textTop < parentTop) {
......
...@@ -180,16 +180,18 @@ import java.util.List; ...@@ -180,16 +180,18 @@ import java.util.List;
float linePercent; float linePercent;
int lineTranslatePercent; int lineTranslatePercent;
@Cue.AnchorType int lineAnchor; int lineAnchorTranslatePercent;
if (cue.line != Cue.DIMEN_UNSET) { if (cue.line != Cue.DIMEN_UNSET) {
switch (cue.lineType) { switch (cue.lineType) {
case Cue.LINE_TYPE_NUMBER: case Cue.LINE_TYPE_NUMBER:
if (cue.line >= 0) { if (cue.line >= 0) {
linePercent = 0; linePercent = 0;
lineTranslatePercent = Math.round(cue.line) * 100; lineTranslatePercent = Math.round(cue.line) * 100;
lineAnchorTranslatePercent = 0;
} else { } else {
linePercent = 100; linePercent = 100;
lineTranslatePercent = Math.round(cue.line + 1) * 100; lineTranslatePercent = Math.round(cue.line + 1) * 100;
lineAnchorTranslatePercent = -100;
} }
break; break;
case Cue.LINE_TYPE_FRACTION: case Cue.LINE_TYPE_FRACTION:
...@@ -197,18 +199,16 @@ import java.util.List; ...@@ -197,18 +199,16 @@ import java.util.List;
default: default:
linePercent = cue.line * 100; linePercent = cue.line * 100;
lineTranslatePercent = 0; lineTranslatePercent = 0;
lineAnchorTranslatePercent =
cue.verticalType == Cue.VERTICAL_TYPE_RL
? -anchorTypeToTranslatePercent(cue.lineAnchor)
: anchorTypeToTranslatePercent(cue.lineAnchor);
} }
lineAnchor = cue.lineAnchor;
} else { } else {
linePercent = (1.0f - bottomPaddingFraction) * 100; linePercent = (1.0f - bottomPaddingFraction) * 100;
lineTranslatePercent = 0; lineTranslatePercent = 0;
// If Cue.line == DIMEN_UNSET then ignore Cue.lineAnchor and assume ANCHOR_TYPE_END. lineAnchorTranslatePercent = -100;
lineAnchor = Cue.ANCHOR_TYPE_END;
} }
int lineAnchorTranslatePercent =
cue.verticalType == Cue.VERTICAL_TYPE_RL
? -anchorTypeToTranslatePercent(lineAnchor)
: anchorTypeToTranslatePercent(lineAnchor);
String size = String size =
cue.size != Cue.DIMEN_UNSET cue.size != Cue.DIMEN_UNSET
......
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