Update WebvttCue to use defaults from the spec

Cue's UNSET and null values should be used when the source data
doesn't specify *and* the spec doesn't provide a clear default.
In the WebVTT case, the defaults are clear, so we use them
explicitly.

PiperOrigin-RevId: 277522899
This commit is contained in:
ibaker 2019-10-30 16:39:14 +00:00 committed by Oliver Woodman
parent 0c63362258
commit b3f94e3768
6 changed files with 206 additions and 88 deletions

View File

@ -15,15 +15,23 @@
*/ */
package com.google.android.exoplayer2.text.webvtt; package com.google.android.exoplayer2.text.webvtt;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.text.Layout.Alignment; import android.text.Layout.Alignment;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
/** /**
* A representation of a WebVTT cue. * A representation of a WebVTT cue.
*/ */
public final class WebvttCue extends Cue { public final class WebvttCue extends Cue {
private static final float DEFAULT_POSITION = 0.5f;
public final long startTime; public final long startTime;
public final long endTime; public final long endTime;
@ -50,26 +58,73 @@ public final class WebvttCue extends Cue {
* @return Whether this cue should be placed in the default position. * @return Whether this cue should be placed in the default position.
*/ */
public boolean isNormalCue() { public boolean isNormalCue() {
return (line == DIMEN_UNSET && position == DIMEN_UNSET); return (line == DIMEN_UNSET && position == DEFAULT_POSITION);
} }
/** /** Builder for WebVTT cues. */
* Builder for WebVTT cues.
*/
@SuppressWarnings("hiding") @SuppressWarnings("hiding")
public static class Builder { public static class Builder {
/**
* Valid values for {@link #setTextAlignment(int)}.
*
* <p>We use a custom list (and not {@link Alignment} directly) in order to include both {@code
* START}/{@code LEFT} and {@code END}/{@code RIGHT}. The distinction is important for {@link
* #derivePosition(int)}.
*
* <p>These correspond to the valid values for the 'align' cue setting in the <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment">WebVTT spec</a>.
*/
@Documented
@Retention(SOURCE)
@IntDef({
TextAlignment.START,
TextAlignment.CENTER,
TextAlignment.END,
TextAlignment.LEFT,
TextAlignment.RIGHT
})
public @interface TextAlignment {
/**
* See WebVTT's <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-start-alignment">align:start</a>.
*/
int START = 1;
/**
* See WebVTT's <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-center-alignment">align:center</a>.
*/
int CENTER = 2;
/**
* See WebVTT's <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-end-alignment">align:end</a>.
*/
int END = 3;
/**
* See WebVTT's <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-left-alignment">align:left</a>.
*/
int LEFT = 4;
/**
* See WebVTT's <a
* href="https://www.w3.org/TR/webvtt1/#webvtt-cue-right-alignment">align:right</a>.
*/
int RIGHT = 5;
}
private static final String TAG = "WebvttCueBuilder"; private static final String TAG = "WebvttCueBuilder";
private long startTime; private long startTime;
private long endTime; private long endTime;
private CharSequence text; @Nullable private CharSequence text;
private Alignment textAlignment; @TextAlignment private int textAlignment;
private float line; private float line;
private int lineType; // Equivalent to WebVTT's snap-to-lines flag:
private int lineAnchor; // https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
@LineType private int lineType;
@AnchorType private int lineAnchor;
private float position; private float position;
private int positionAnchor; @AnchorType private int positionAnchor;
private float width; private float width;
// Initialization methods // Initialization methods
@ -82,23 +137,43 @@ public final class WebvttCue extends Cue {
startTime = 0; startTime = 0;
endTime = 0; endTime = 0;
text = null; text = null;
textAlignment = null; // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
textAlignment = TextAlignment.CENTER;
line = Cue.DIMEN_UNSET; line = Cue.DIMEN_UNSET;
lineType = Cue.TYPE_UNSET; // Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
lineAnchor = Cue.TYPE_UNSET; lineType = Cue.LINE_TYPE_NUMBER;
// Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-line-alignment
lineAnchor = Cue.ANCHOR_TYPE_START;
position = Cue.DIMEN_UNSET; position = Cue.DIMEN_UNSET;
positionAnchor = Cue.TYPE_UNSET; positionAnchor = Cue.TYPE_UNSET;
width = Cue.DIMEN_UNSET; // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-size
width = 1.0f;
} }
// Construction methods. // Construction methods.
public WebvttCue build() { public WebvttCue build() {
if (position != Cue.DIMEN_UNSET && positionAnchor == Cue.TYPE_UNSET) { line = computeLine(line, lineType);
derivePositionAnchorFromAlignment();
if (position == Cue.DIMEN_UNSET) {
position = derivePosition(textAlignment);
} }
return new WebvttCue(startTime, endTime, text, textAlignment, line, lineType, lineAnchor,
position, positionAnchor, width); if (positionAnchor == Cue.TYPE_UNSET) {
positionAnchor = derivePositionAnchor(textAlignment);
}
return new WebvttCue(
startTime,
endTime,
text,
convertTextAlignment(textAlignment),
line,
lineType,
lineAnchor,
position,
positionAnchor,
width);
} }
public Builder setStartTime(long time) { public Builder setStartTime(long time) {
@ -116,7 +191,7 @@ public final class WebvttCue extends Cue {
return this; return this;
} }
public Builder setTextAlignment(Alignment textAlignment) { public Builder setTextAlignment(@TextAlignment int textAlignment) {
this.textAlignment = textAlignment; this.textAlignment = textAlignment;
return this; return this;
} }
@ -126,12 +201,12 @@ public final class WebvttCue extends Cue {
return this; return this;
} }
public Builder setLineType(int lineType) { public Builder setLineType(@LineType int lineType) {
this.lineType = lineType; this.lineType = lineType;
return this; return this;
} }
public Builder setLineAnchor(int lineAnchor) { public Builder setLineAnchor(@AnchorType int lineAnchor) {
this.lineAnchor = lineAnchor; this.lineAnchor = lineAnchor;
return this; return this;
} }
@ -141,7 +216,7 @@ public final class WebvttCue extends Cue {
return this; return this;
} }
public Builder setPositionAnchor(int positionAnchor) { public Builder setPositionAnchor(@AnchorType int positionAnchor) {
this.positionAnchor = positionAnchor; this.positionAnchor = positionAnchor;
return this; return this;
} }
@ -151,29 +226,69 @@ public final class WebvttCue extends Cue {
return this; return this;
} }
private Builder derivePositionAnchorFromAlignment() { // https://www.w3.org/TR/webvtt1/#webvtt-cue-line
if (textAlignment == null) { private static float computeLine(float line, @LineType int lineType) {
positionAnchor = Cue.TYPE_UNSET; if (line != Cue.DIMEN_UNSET
&& lineType == Cue.LINE_TYPE_FRACTION
&& (line < 0.0f || line > 1.0f)) {
return 1.0f; // Step 1
} else if (line != Cue.DIMEN_UNSET) {
// Step 2: Do nothing, line is already correct.
return line;
} else if (lineType == Cue.LINE_TYPE_FRACTION) {
return 1.0f; // Step 3
} else { } else {
switch (textAlignment) { // Steps 4 - 10 (stacking multiple simultaneous cues) are handled by WebvttSubtitle#getCues
case ALIGN_NORMAL: // and WebvttCue#isNormalCue.
positionAnchor = Cue.ANCHOR_TYPE_START; return DIMEN_UNSET;
break;
case ALIGN_CENTER:
positionAnchor = Cue.ANCHOR_TYPE_MIDDLE;
break;
case ALIGN_OPPOSITE:
positionAnchor = Cue.ANCHOR_TYPE_END;
break;
default:
Log.w(TAG, "Unrecognized alignment: " + textAlignment);
positionAnchor = Cue.ANCHOR_TYPE_START;
break;
}
} }
return this;
} }
} // https://www.w3.org/TR/webvtt1/#webvtt-cue-position
private static float derivePosition(@TextAlignment int textAlignment) {
switch (textAlignment) {
case TextAlignment.LEFT:
return 0.0f;
case TextAlignment.RIGHT:
return 1.0f;
case TextAlignment.START:
case TextAlignment.CENTER:
case TextAlignment.END:
default:
return DEFAULT_POSITION;
}
}
// https://www.w3.org/TR/webvtt1/#webvtt-cue-position-alignment
@AnchorType
private static int derivePositionAnchor(@TextAlignment int textAlignment) {
switch (textAlignment) {
case TextAlignment.LEFT:
case TextAlignment.START:
return Cue.ANCHOR_TYPE_START;
case TextAlignment.RIGHT:
case TextAlignment.END:
return Cue.ANCHOR_TYPE_END;
case TextAlignment.CENTER:
default:
return Cue.ANCHOR_TYPE_MIDDLE;
}
}
private static Alignment convertTextAlignment(@TextAlignment int textAlignment) {
switch (textAlignment) {
case TextAlignment.START:
case TextAlignment.LEFT:
return Alignment.ALIGN_NORMAL;
case TextAlignment.CENTER:
return Alignment.ALIGN_CENTER;
case TextAlignment.END:
case TextAlignment.RIGHT:
return Alignment.ALIGN_OPPOSITE;
default:
Log.w(TAG, "Unknown textAlignment: " + textAlignment);
return null;
}
}
}
} }

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.text.webvtt; package com.google.android.exoplayer2.text.webvtt;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.text.Layout.Alignment;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
@ -87,7 +86,7 @@ public final class WebvttCueParser {
* Parses the next valid WebVTT cue in a parsable array, including timestamps, settings and text. * Parses the next valid WebVTT cue in a parsable array, including timestamps, settings and text.
* *
* @param webvttData Parsable WebVTT file data. * @param webvttData Parsable WebVTT file data.
* @param builder Builder for WebVTT Cues. * @param builder Builder for WebVTT Cues (output parameter).
* @param styles List of styles defined by the CSS style blocks preceding the cues. * @param styles List of styles defined by the CSS style blocks preceding the cues.
* @return Whether a valid Cue was found. * @return Whether a valid Cue was found.
*/ */
@ -252,14 +251,11 @@ public final class WebvttCueParser {
// Internal methods // Internal methods
private static void parseLineAttribute(String s, WebvttCue.Builder builder) private static void parseLineAttribute(String s, WebvttCue.Builder builder) {
throws NumberFormatException {
int commaIndex = s.indexOf(','); int commaIndex = s.indexOf(',');
if (commaIndex != -1) { if (commaIndex != -1) {
builder.setLineAnchor(parsePositionAnchor(s.substring(commaIndex + 1))); builder.setLineAnchor(parsePositionAnchor(s.substring(commaIndex + 1)));
s = s.substring(0, commaIndex); s = s.substring(0, commaIndex);
} else {
builder.setLineAnchor(Cue.TYPE_UNSET);
} }
if (s.endsWith("%")) { if (s.endsWith("%")) {
builder.setLine(WebvttParserUtil.parsePercentage(s)).setLineType(Cue.LINE_TYPE_FRACTION); builder.setLine(WebvttParserUtil.parsePercentage(s)).setLineType(Cue.LINE_TYPE_FRACTION);
@ -274,18 +270,16 @@ public final class WebvttCueParser {
} }
} }
private static void parsePositionAttribute(String s, WebvttCue.Builder builder) private static void parsePositionAttribute(String s, WebvttCue.Builder builder) {
throws NumberFormatException {
int commaIndex = s.indexOf(','); int commaIndex = s.indexOf(',');
if (commaIndex != -1) { if (commaIndex != -1) {
builder.setPositionAnchor(parsePositionAnchor(s.substring(commaIndex + 1))); builder.setPositionAnchor(parsePositionAnchor(s.substring(commaIndex + 1)));
s = s.substring(0, commaIndex); s = s.substring(0, commaIndex);
} else {
builder.setPositionAnchor(Cue.TYPE_UNSET);
} }
builder.setPosition(WebvttParserUtil.parsePercentage(s)); builder.setPosition(WebvttParserUtil.parsePercentage(s));
} }
@Cue.AnchorType
private static int parsePositionAnchor(String s) { private static int parsePositionAnchor(String s) {
switch (s) { switch (s) {
case "start": case "start":
@ -301,20 +295,24 @@ public final class WebvttCueParser {
} }
} }
private static Alignment parseTextAlignment(String s) { @WebvttCue.Builder.TextAlignment
private static int parseTextAlignment(String s) {
switch (s) { switch (s) {
case "start": case "start":
return WebvttCue.Builder.TextAlignment.START;
case "left": case "left":
return Alignment.ALIGN_NORMAL; return WebvttCue.Builder.TextAlignment.LEFT;
case "center": case "center":
case "middle": case "middle":
return Alignment.ALIGN_CENTER; return WebvttCue.Builder.TextAlignment.CENTER;
case "end": case "end":
return WebvttCue.Builder.TextAlignment.END;
case "right": case "right":
return Alignment.ALIGN_OPPOSITE; return WebvttCue.Builder.TextAlignment.RIGHT;
default: default:
Log.w(TAG, "Invalid alignment value: " + s); Log.w(TAG, "Invalid alignment value: " + s);
return null; // Default value: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
return WebvttCue.Builder.TextAlignment.CENTER;
} }
} }

View File

@ -83,6 +83,9 @@ import java.util.List;
list = new ArrayList<>(); list = new ArrayList<>();
} }
WebvttCue cue = cues.get(i); WebvttCue cue = cues.get(i);
// TODO(ibaker): Replace this with a closer implementation of the WebVTT spec (keeping
// individual cues, but tweaking their `line` value):
// https://www.w3.org/TR/webvtt1/#cue-computed-line
if (cue.isNormalCue()) { if (cue.isNormalCue()) {
// we want to merge all of the normal cues into a single cue to ensure they are drawn // we want to merge all of the normal cues into a single cue to ensure they are drawn
// correctly (i.e. don't overlap) and to emulate roll-up, but only if there are multiple // correctly (i.e. don't overlap) and to emulate roll-up, but only if there are multiple

View File

@ -21,13 +21,12 @@ NOTE Line as absolute negative number and without line alignment.
00:06.000 --> 00:07.000 line:-10 align:middle 00:06.000 --> 00:07.000 line:-10 align:middle
This is the fourth subtitle. This is the fourth subtitle.
NOTE The positioning alignment should be inherited from align. NOTE The position and positioning alignment should be inherited from align.
00:07.000 --> 00:08.000 position:10% align:end size:10% 00:07.000 --> 00:08.000 align:right
This is the fifth subtitle. This is the fifth subtitle.
NOTE In newer drafts, align:middle has been replaced by align:center NOTE In newer drafts, align:middle has been replaced by align:center
00:10.000 --> 00:11.000 line:45%,end align:center size:35% 00:10.000 --> 00:11.000 line:45%,end align:center size:35%
This is the sixth subtitle. This is the sixth subtitle.

View File

@ -87,7 +87,8 @@ public final class Mp4WebvttDecoderTest {
public void testSingleCueSample() throws SubtitleDecoderException { public void testSingleCueSample() throws SubtitleDecoderException {
Mp4WebvttDecoder decoder = new Mp4WebvttDecoder(); Mp4WebvttDecoder decoder = new Mp4WebvttDecoder();
Subtitle result = decoder.decode(SINGLE_CUE_SAMPLE, SINGLE_CUE_SAMPLE.length, false); Subtitle result = decoder.decode(SINGLE_CUE_SAMPLE, SINGLE_CUE_SAMPLE.length, false);
Cue expectedCue = new Cue("Hello World"); // Line feed must be trimmed by the decoder // Line feed must be trimmed by the decoder
Cue expectedCue = new WebvttCue.Builder().setText("Hello World").build();
assertMp4WebvttSubtitleEquals(result, expectedCue); assertMp4WebvttSubtitleEquals(result, expectedCue);
} }
@ -95,8 +96,8 @@ public final class Mp4WebvttDecoderTest {
public void testTwoCuesSample() throws SubtitleDecoderException { public void testTwoCuesSample() throws SubtitleDecoderException {
Mp4WebvttDecoder decoder = new Mp4WebvttDecoder(); Mp4WebvttDecoder decoder = new Mp4WebvttDecoder();
Subtitle result = decoder.decode(DOUBLE_CUE_SAMPLE, DOUBLE_CUE_SAMPLE.length, false); Subtitle result = decoder.decode(DOUBLE_CUE_SAMPLE, DOUBLE_CUE_SAMPLE.length, false);
Cue firstExpectedCue = new Cue("Hello World"); Cue firstExpectedCue = new WebvttCue.Builder().setText("Hello World").build();
Cue secondExpectedCue = new Cue("Bye Bye"); Cue secondExpectedCue = new WebvttCue.Builder().setText("Bye Bye").build();
assertMp4WebvttSubtitleEquals(result, firstExpectedCue, secondExpectedCue); assertMp4WebvttSubtitleEquals(result, firstExpectedCue, secondExpectedCue);
} }
@ -104,7 +105,9 @@ public final class Mp4WebvttDecoderTest {
public void testNoCueSample() throws SubtitleDecoderException { public void testNoCueSample() throws SubtitleDecoderException {
Mp4WebvttDecoder decoder = new Mp4WebvttDecoder(); Mp4WebvttDecoder decoder = new Mp4WebvttDecoder();
Subtitle result = decoder.decode(NO_CUE_SAMPLE, NO_CUE_SAMPLE.length, false); Subtitle result = decoder.decode(NO_CUE_SAMPLE, NO_CUE_SAMPLE.length, false);
assertMp4WebvttSubtitleEquals(result); assertThat(result.getEventTimeCount()).isEqualTo(1);
assertThat(result.getEventTime(0)).isEqualTo(0);
assertThat(result.getCues(0)).isEmpty();
} }
// Negative tests. // Negative tests.

View File

@ -224,8 +224,8 @@ public class WebvttDecoderTest {
"This is the first subtitle.", "This is the first subtitle.",
Alignment.ALIGN_NORMAL, Alignment.ALIGN_NORMAL,
/* line= */ Cue.DIMEN_UNSET, /* line= */ Cue.DIMEN_UNSET,
/* lineType= */ Cue.TYPE_UNSET, /* lineType= */ Cue.LINE_TYPE_NUMBER,
/* lineAnchor= */ Cue.TYPE_UNSET, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.1f, /* position= */ 0.1f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_START, /* positionAnchor= */ Cue.ANCHOR_TYPE_START,
/* size= */ 0.35f); /* size= */ 0.35f);
@ -237,10 +237,10 @@ public class WebvttDecoderTest {
"This is the second subtitle.", "This is the second subtitle.",
Alignment.ALIGN_OPPOSITE, Alignment.ALIGN_OPPOSITE,
/* line= */ Cue.DIMEN_UNSET, /* line= */ Cue.DIMEN_UNSET,
/* lineType= */ Cue.TYPE_UNSET, /* lineType= */ Cue.LINE_TYPE_NUMBER,
/* lineAnchor= */ Cue.TYPE_UNSET, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ Cue.DIMEN_UNSET, /* position= */ 0.5f,
/* positionAnchor= */ Cue.TYPE_UNSET, /* positionAnchor= */ Cue.ANCHOR_TYPE_END,
/* size= */ 0.35f); /* size= */ 0.35f);
assertCue( assertCue(
subtitle, subtitle,
@ -252,8 +252,8 @@ public class WebvttDecoderTest {
/* line= */ 0.45f, /* line= */ 0.45f,
/* lineType= */ Cue.LINE_TYPE_FRACTION, /* lineType= */ Cue.LINE_TYPE_FRACTION,
/* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* lineAnchor= */ Cue.ANCHOR_TYPE_END,
/* position= */ Cue.DIMEN_UNSET, /* position= */ 0.5f,
/* positionAnchor= */ Cue.TYPE_UNSET, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ 0.35f); /* size= */ 0.35f);
assertCue( assertCue(
subtitle, subtitle,
@ -262,12 +262,12 @@ public class WebvttDecoderTest {
/* endTimeUs= */ 7000000, /* endTimeUs= */ 7000000,
"This is the fourth subtitle.", "This is the fourth subtitle.",
Alignment.ALIGN_CENTER, Alignment.ALIGN_CENTER,
/* line= */ -11f, /* line= */ -11.0f,
/* lineType= */ Cue.LINE_TYPE_NUMBER, /* lineType= */ Cue.LINE_TYPE_NUMBER,
/* lineAnchor= */ Cue.TYPE_UNSET, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ Cue.DIMEN_UNSET, /* position= */ 0.5f,
/* positionAnchor= */ Cue.TYPE_UNSET, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ Cue.DIMEN_UNSET); /* size= */ 1.0f);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 8, /* eventTimeIndex= */ 8,
@ -276,11 +276,11 @@ public class WebvttDecoderTest {
"This is the fifth subtitle.", "This is the fifth subtitle.",
Alignment.ALIGN_OPPOSITE, Alignment.ALIGN_OPPOSITE,
/* line= */ Cue.DIMEN_UNSET, /* line= */ Cue.DIMEN_UNSET,
/* lineType= */ Cue.TYPE_UNSET, /* lineType= */ Cue.LINE_TYPE_NUMBER,
/* lineAnchor= */ Cue.TYPE_UNSET, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.1f, /* position= */ 1.0f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_END, /* positionAnchor= */ Cue.ANCHOR_TYPE_END,
/* size= */ 0.1f); /* size= */ 1.0f);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 10, /* eventTimeIndex= */ 10,
@ -291,8 +291,8 @@ public class WebvttDecoderTest {
/* line= */ 0.45f, /* line= */ 0.45f,
/* lineType= */ Cue.LINE_TYPE_FRACTION, /* lineType= */ Cue.LINE_TYPE_FRACTION,
/* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* lineAnchor= */ Cue.ANCHOR_TYPE_END,
/* position= */ Cue.DIMEN_UNSET, /* position= */ 0.5f,
/* positionAnchor= */ Cue.TYPE_UNSET, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ 0.35f); /* size= */ 0.35f);
} }
@ -412,13 +412,13 @@ public class WebvttDecoderTest {
startTimeUs, startTimeUs,
endTimeUs, endTimeUs,
text, text,
/* textAlignment= */ null, /* textAlignment= */ Alignment.ALIGN_CENTER,
/* line= */ Cue.DIMEN_UNSET, /* line= */ Cue.DIMEN_UNSET,
/* lineType= */ Cue.TYPE_UNSET, /* lineType= */ Cue.LINE_TYPE_NUMBER,
/* lineAnchor= */ Cue.TYPE_UNSET, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ Cue.DIMEN_UNSET, /* position= */ 0.5f,
/* positionAnchor= */ Cue.TYPE_UNSET, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ Cue.DIMEN_UNSET); /* size= */ 1.0f);
} }
private static void assertCue( private static void assertCue(