mirror of
https://github.com/androidx/media.git
synced 2025-05-16 20:19:57 +08:00
allow multiple style rules in a STYLE block of a webvtt file
PiperOrigin-RevId: 253959976
This commit is contained in:
parent
1952988f84
commit
aaf57c76cf
@ -20,6 +20,8 @@ import android.text.TextUtils;
|
||||
import com.google.android.exoplayer2.util.ColorParser;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -35,8 +37,8 @@ import java.util.regex.Pattern;
|
||||
private static final String PROPERTY_TEXT_DECORATION = "text-decoration";
|
||||
private static final String VALUE_BOLD = "bold";
|
||||
private static final String VALUE_UNDERLINE = "underline";
|
||||
private static final String BLOCK_START = "{";
|
||||
private static final String BLOCK_END = "}";
|
||||
private static final String RULE_START = "{";
|
||||
private static final String RULE_END = "}";
|
||||
private static final String PROPERTY_FONT_STYLE = "font-style";
|
||||
private static final String VALUE_ITALIC = "italic";
|
||||
|
||||
@ -53,38 +55,46 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Takes a CSS style block and consumes up to the first empty line. Attempts to parse the contents
|
||||
* of the style block and returns a {@link WebvttCssStyle} instance if successful, or {@code null}
|
||||
* otherwise.
|
||||
* of the style block and returns a list of {@link WebvttCssStyle} instances if successful. If
|
||||
* parsing fails, it returns a list including only the styles which have been successfully parsed
|
||||
* up to the style rule which was malformed.
|
||||
*
|
||||
* @param input The input from which the style block should be read.
|
||||
* @return A {@link WebvttCssStyle} that represents the parsed block, or {@code null} if parsing
|
||||
* failed.
|
||||
* @return A list of {@link WebvttCssStyle}s that represents the parsed block, or a list
|
||||
* containing the styles up to the parsing failure.
|
||||
*/
|
||||
@Nullable
|
||||
public WebvttCssStyle parseBlock(ParsableByteArray input) {
|
||||
public List<WebvttCssStyle> parseBlock(ParsableByteArray input) {
|
||||
stringBuilder.setLength(0);
|
||||
int initialInputPosition = input.getPosition();
|
||||
skipStyleBlock(input);
|
||||
styleInput.reset(input.data, input.getPosition());
|
||||
styleInput.setPosition(initialInputPosition);
|
||||
String selector = parseSelector(styleInput, stringBuilder);
|
||||
if (selector == null || !BLOCK_START.equals(parseNextToken(styleInput, stringBuilder))) {
|
||||
return null;
|
||||
}
|
||||
WebvttCssStyle style = new WebvttCssStyle();
|
||||
applySelectorToStyle(style, selector);
|
||||
String token = null;
|
||||
boolean blockEndFound = false;
|
||||
while (!blockEndFound) {
|
||||
int position = styleInput.getPosition();
|
||||
token = parseNextToken(styleInput, stringBuilder);
|
||||
blockEndFound = token == null || BLOCK_END.equals(token);
|
||||
if (!blockEndFound) {
|
||||
styleInput.setPosition(position);
|
||||
parseStyleDeclaration(styleInput, style, stringBuilder);
|
||||
|
||||
List<WebvttCssStyle> styles = new ArrayList<>();
|
||||
String selector;
|
||||
while ((selector = parseSelector(styleInput, stringBuilder)) != null) {
|
||||
if (!RULE_START.equals(parseNextToken(styleInput, stringBuilder))) {
|
||||
return styles;
|
||||
}
|
||||
WebvttCssStyle style = new WebvttCssStyle();
|
||||
applySelectorToStyle(style, selector);
|
||||
String token = null;
|
||||
boolean blockEndFound = false;
|
||||
while (!blockEndFound) {
|
||||
int position = styleInput.getPosition();
|
||||
token = parseNextToken(styleInput, stringBuilder);
|
||||
blockEndFound = token == null || RULE_END.equals(token);
|
||||
if (!blockEndFound) {
|
||||
styleInput.setPosition(position);
|
||||
parseStyleDeclaration(styleInput, style, stringBuilder);
|
||||
}
|
||||
}
|
||||
// Check that the style rule ended correctly.
|
||||
if (RULE_END.equals(token)) {
|
||||
styles.add(style);
|
||||
}
|
||||
}
|
||||
return BLOCK_END.equals(token) ? style : null; // Check that the style block ended correctly.
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,7 +120,7 @@ import java.util.regex.Pattern;
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
if (BLOCK_START.equals(token)) {
|
||||
if (RULE_START.equals(token)) {
|
||||
input.setPosition(position);
|
||||
return "";
|
||||
}
|
||||
@ -159,7 +169,7 @@ import java.util.regex.Pattern;
|
||||
String token = parseNextToken(input, stringBuilder);
|
||||
if (";".equals(token)) {
|
||||
// The style declaration is well formed.
|
||||
} else if (BLOCK_END.equals(token)) {
|
||||
} else if (RULE_END.equals(token)) {
|
||||
// The style declaration is well formed and we can go on, but the closing bracket had to be
|
||||
// fed back.
|
||||
input.setPosition(position);
|
||||
@ -255,7 +265,7 @@ import java.util.regex.Pattern;
|
||||
// Syntax error.
|
||||
return null;
|
||||
}
|
||||
if (BLOCK_END.equals(token) || ";".equals(token)) {
|
||||
if (RULE_END.equals(token) || ";".equals(token)) {
|
||||
input.setPosition(position);
|
||||
expressionEndFound = true;
|
||||
} else {
|
||||
|
@ -80,10 +80,7 @@ public final class WebvttDecoder extends SimpleSubtitleDecoder {
|
||||
throw new SubtitleDecoderException("A style block was found after the first cue.");
|
||||
}
|
||||
parsableWebvttData.readLine(); // Consume the "STYLE" header.
|
||||
WebvttCssStyle styleBlock = cssParser.parseBlock(parsableWebvttData);
|
||||
if (styleBlock != null) {
|
||||
definedStyles.add(styleBlock);
|
||||
}
|
||||
definedStyles.addAll(cssParser.parseBlock(parsableWebvttData));
|
||||
} else if (event == EVENT_CUE) {
|
||||
if (cueParser.parseCue(parsableWebvttData, webvttCueBuilder, definedStyles)) {
|
||||
subtitles.add(webvttCueBuilder.build());
|
||||
|
@ -13,8 +13,6 @@ STYLE
|
||||
::cue(#id2) {
|
||||
color: peachpuff;
|
||||
}
|
||||
|
||||
STYLE
|
||||
::cue(v[voice="LaGord"]) { background-color: lime }
|
||||
|
||||
STYLE
|
||||
|
@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -87,21 +88,32 @@ public final class CssParserTest {
|
||||
|
||||
@Test
|
||||
public void testParseMethodSimpleInput() {
|
||||
String styleBlock1 = " ::cue { color : black; background-color: PapayaWhip }";
|
||||
WebvttCssStyle expectedStyle = new WebvttCssStyle();
|
||||
String styleBlock1 = " ::cue { color : black; background-color: PapayaWhip }";
|
||||
expectedStyle.setFontColor(0xFF000000);
|
||||
expectedStyle.setBackgroundColor(0xFFFFEFD5);
|
||||
assertParserProduces(expectedStyle, styleBlock1);
|
||||
assertParserProduces(styleBlock1, expectedStyle);
|
||||
|
||||
String styleBlock2 = " ::cue { color : black }\n\n::cue { color : invalid }";
|
||||
expectedStyle = new WebvttCssStyle();
|
||||
expectedStyle.setFontColor(0xFF000000);
|
||||
assertParserProduces(expectedStyle, styleBlock2);
|
||||
assertParserProduces(styleBlock2, expectedStyle);
|
||||
|
||||
String styleBlock3 = " \n::cue {\n background-color\n:#00fFFe}";
|
||||
String styleBlock3 = "::cue {\n background-color\n:#00fFFe}";
|
||||
expectedStyle = new WebvttCssStyle();
|
||||
expectedStyle.setBackgroundColor(0xFF00FFFE);
|
||||
assertParserProduces(expectedStyle, styleBlock3);
|
||||
assertParserProduces(styleBlock3, expectedStyle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMethodMultipleRulesInBlockInput() {
|
||||
String styleBlock =
|
||||
"::cue {\n background-color\n:#00fFFe} \n::cue {\n background-color\n:#00000000}\n";
|
||||
WebvttCssStyle expectedStyle = new WebvttCssStyle();
|
||||
expectedStyle.setBackgroundColor(0xFF00FFFE);
|
||||
WebvttCssStyle secondExpectedStyle = new WebvttCssStyle();
|
||||
secondExpectedStyle.setBackgroundColor(0x000000);
|
||||
assertParserProduces(styleBlock, expectedStyle, secondExpectedStyle);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -116,7 +128,7 @@ public final class CssParserTest {
|
||||
expectedStyle.setFontFamily("courier");
|
||||
expectedStyle.setBold(true);
|
||||
|
||||
assertParserProduces(expectedStyle, styleBlock);
|
||||
assertParserProduces(styleBlock, expectedStyle);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -128,7 +140,7 @@ public final class CssParserTest {
|
||||
expectedStyle.setBackgroundColor(0x190A0B0C);
|
||||
expectedStyle.setFontColor(0xFF010101);
|
||||
|
||||
assertParserProduces(expectedStyle, styleBlock);
|
||||
assertParserProduces(styleBlock, expectedStyle);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -203,25 +215,29 @@ public final class CssParserTest {
|
||||
assertThat(input.readLine()).isEqualTo(expectedLine);
|
||||
}
|
||||
|
||||
private void assertParserProduces(WebvttCssStyle expected,
|
||||
String styleBlock){
|
||||
private void assertParserProduces(String styleBlock, WebvttCssStyle... expectedStyles) {
|
||||
ParsableByteArray input = new ParsableByteArray(Util.getUtf8Bytes(styleBlock));
|
||||
WebvttCssStyle actualElem = parser.parseBlock(input);
|
||||
assertThat(actualElem.hasBackgroundColor()).isEqualTo(expected.hasBackgroundColor());
|
||||
if (expected.hasBackgroundColor()) {
|
||||
assertThat(actualElem.getBackgroundColor()).isEqualTo(expected.getBackgroundColor());
|
||||
List<WebvttCssStyle> styles = parser.parseBlock(input);
|
||||
assertThat(styles.size()).isEqualTo(expectedStyles.length);
|
||||
for (int i = 0; i < expectedStyles.length; i++) {
|
||||
WebvttCssStyle expected = expectedStyles[i];
|
||||
WebvttCssStyle actualElem = styles.get(i);
|
||||
assertThat(actualElem.hasBackgroundColor()).isEqualTo(expected.hasBackgroundColor());
|
||||
if (expected.hasBackgroundColor()) {
|
||||
assertThat(actualElem.getBackgroundColor()).isEqualTo(expected.getBackgroundColor());
|
||||
}
|
||||
assertThat(actualElem.hasFontColor()).isEqualTo(expected.hasFontColor());
|
||||
if (expected.hasFontColor()) {
|
||||
assertThat(actualElem.getFontColor()).isEqualTo(expected.getFontColor());
|
||||
}
|
||||
assertThat(actualElem.getFontFamily()).isEqualTo(expected.getFontFamily());
|
||||
assertThat(actualElem.getFontSize()).isEqualTo(expected.getFontSize());
|
||||
assertThat(actualElem.getFontSizeUnit()).isEqualTo(expected.getFontSizeUnit());
|
||||
assertThat(actualElem.getStyle()).isEqualTo(expected.getStyle());
|
||||
assertThat(actualElem.isLinethrough()).isEqualTo(expected.isLinethrough());
|
||||
assertThat(actualElem.isUnderline()).isEqualTo(expected.isUnderline());
|
||||
assertThat(actualElem.getTextAlign()).isEqualTo(expected.getTextAlign());
|
||||
}
|
||||
assertThat(actualElem.hasFontColor()).isEqualTo(expected.hasFontColor());
|
||||
if (expected.hasFontColor()) {
|
||||
assertThat(actualElem.getFontColor()).isEqualTo(expected.getFontColor());
|
||||
}
|
||||
assertThat(actualElem.getFontFamily()).isEqualTo(expected.getFontFamily());
|
||||
assertThat(actualElem.getFontSize()).isEqualTo(expected.getFontSize());
|
||||
assertThat(actualElem.getFontSizeUnit()).isEqualTo(expected.getFontSizeUnit());
|
||||
assertThat(actualElem.getStyle()).isEqualTo(expected.getStyle());
|
||||
assertThat(actualElem.isLinethrough()).isEqualTo(expected.isLinethrough());
|
||||
assertThat(actualElem.isUnderline()).isEqualTo(expected.isUnderline());
|
||||
assertThat(actualElem.getTextAlign()).isEqualTo(expected.getTextAlign());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user