mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00: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
4 changed files with 78 additions and 57 deletions
|
|
@ -20,6 +20,8 @@ import android.text.TextUtils;
|
||||||
import com.google.android.exoplayer2.util.ColorParser;
|
import com.google.android.exoplayer2.util.ColorParser;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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 PROPERTY_TEXT_DECORATION = "text-decoration";
|
||||||
private static final String VALUE_BOLD = "bold";
|
private static final String VALUE_BOLD = "bold";
|
||||||
private static final String VALUE_UNDERLINE = "underline";
|
private static final String VALUE_UNDERLINE = "underline";
|
||||||
private static final String BLOCK_START = "{";
|
private static final String RULE_START = "{";
|
||||||
private static final String BLOCK_END = "}";
|
private static final String RULE_END = "}";
|
||||||
private static final String PROPERTY_FONT_STYLE = "font-style";
|
private static final String PROPERTY_FONT_STYLE = "font-style";
|
||||||
private static final String VALUE_ITALIC = "italic";
|
private static final String VALUE_ITALIC = "italic";
|
||||||
|
|
||||||
|
|
@ -53,23 +55,26 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a CSS style block and consumes up to the first empty line. Attempts to parse the contents
|
* 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}
|
* of the style block and returns a list of {@link WebvttCssStyle} instances if successful. If
|
||||||
* otherwise.
|
* 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.
|
* @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
|
* @return A list of {@link WebvttCssStyle}s that represents the parsed block, or a list
|
||||||
* failed.
|
* containing the styles up to the parsing failure.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
public List<WebvttCssStyle> parseBlock(ParsableByteArray input) {
|
||||||
public WebvttCssStyle parseBlock(ParsableByteArray input) {
|
|
||||||
stringBuilder.setLength(0);
|
stringBuilder.setLength(0);
|
||||||
int initialInputPosition = input.getPosition();
|
int initialInputPosition = input.getPosition();
|
||||||
skipStyleBlock(input);
|
skipStyleBlock(input);
|
||||||
styleInput.reset(input.data, input.getPosition());
|
styleInput.reset(input.data, input.getPosition());
|
||||||
styleInput.setPosition(initialInputPosition);
|
styleInput.setPosition(initialInputPosition);
|
||||||
String selector = parseSelector(styleInput, stringBuilder);
|
|
||||||
if (selector == null || !BLOCK_START.equals(parseNextToken(styleInput, stringBuilder))) {
|
List<WebvttCssStyle> styles = new ArrayList<>();
|
||||||
return null;
|
String selector;
|
||||||
|
while ((selector = parseSelector(styleInput, stringBuilder)) != null) {
|
||||||
|
if (!RULE_START.equals(parseNextToken(styleInput, stringBuilder))) {
|
||||||
|
return styles;
|
||||||
}
|
}
|
||||||
WebvttCssStyle style = new WebvttCssStyle();
|
WebvttCssStyle style = new WebvttCssStyle();
|
||||||
applySelectorToStyle(style, selector);
|
applySelectorToStyle(style, selector);
|
||||||
|
|
@ -78,13 +83,18 @@ import java.util.regex.Pattern;
|
||||||
while (!blockEndFound) {
|
while (!blockEndFound) {
|
||||||
int position = styleInput.getPosition();
|
int position = styleInput.getPosition();
|
||||||
token = parseNextToken(styleInput, stringBuilder);
|
token = parseNextToken(styleInput, stringBuilder);
|
||||||
blockEndFound = token == null || BLOCK_END.equals(token);
|
blockEndFound = token == null || RULE_END.equals(token);
|
||||||
if (!blockEndFound) {
|
if (!blockEndFound) {
|
||||||
styleInput.setPosition(position);
|
styleInput.setPosition(position);
|
||||||
parseStyleDeclaration(styleInput, style, stringBuilder);
|
parseStyleDeclaration(styleInput, style, stringBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BLOCK_END.equals(token) ? style : null; // Check that the style block ended correctly.
|
// Check that the style rule ended correctly.
|
||||||
|
if (RULE_END.equals(token)) {
|
||||||
|
styles.add(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -110,7 +120,7 @@ import java.util.regex.Pattern;
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (BLOCK_START.equals(token)) {
|
if (RULE_START.equals(token)) {
|
||||||
input.setPosition(position);
|
input.setPosition(position);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -159,7 +169,7 @@ import java.util.regex.Pattern;
|
||||||
String token = parseNextToken(input, stringBuilder);
|
String token = parseNextToken(input, stringBuilder);
|
||||||
if (";".equals(token)) {
|
if (";".equals(token)) {
|
||||||
// The style declaration is well formed.
|
// 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
|
// The style declaration is well formed and we can go on, but the closing bracket had to be
|
||||||
// fed back.
|
// fed back.
|
||||||
input.setPosition(position);
|
input.setPosition(position);
|
||||||
|
|
@ -255,7 +265,7 @@ import java.util.regex.Pattern;
|
||||||
// Syntax error.
|
// Syntax error.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (BLOCK_END.equals(token) || ";".equals(token)) {
|
if (RULE_END.equals(token) || ";".equals(token)) {
|
||||||
input.setPosition(position);
|
input.setPosition(position);
|
||||||
expressionEndFound = true;
|
expressionEndFound = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,7 @@ public final class WebvttDecoder extends SimpleSubtitleDecoder {
|
||||||
throw new SubtitleDecoderException("A style block was found after the first cue.");
|
throw new SubtitleDecoderException("A style block was found after the first cue.");
|
||||||
}
|
}
|
||||||
parsableWebvttData.readLine(); // Consume the "STYLE" header.
|
parsableWebvttData.readLine(); // Consume the "STYLE" header.
|
||||||
WebvttCssStyle styleBlock = cssParser.parseBlock(parsableWebvttData);
|
definedStyles.addAll(cssParser.parseBlock(parsableWebvttData));
|
||||||
if (styleBlock != null) {
|
|
||||||
definedStyles.add(styleBlock);
|
|
||||||
}
|
|
||||||
} else if (event == EVENT_CUE) {
|
} else if (event == EVENT_CUE) {
|
||||||
if (cueParser.parseCue(parsableWebvttData, webvttCueBuilder, definedStyles)) {
|
if (cueParser.parseCue(parsableWebvttData, webvttCueBuilder, definedStyles)) {
|
||||||
subtitles.add(webvttCueBuilder.build());
|
subtitles.add(webvttCueBuilder.build());
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@ STYLE
|
||||||
::cue(#id2) {
|
::cue(#id2) {
|
||||||
color: peachpuff;
|
color: peachpuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
STYLE
|
|
||||||
::cue(v[voice="LaGord"]) { background-color: lime }
|
::cue(v[voice="LaGord"]) { background-color: lime }
|
||||||
|
|
||||||
STYLE
|
STYLE
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
|
import java.util.List;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
@ -87,21 +88,32 @@ public final class CssParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMethodSimpleInput() {
|
public void testParseMethodSimpleInput() {
|
||||||
String styleBlock1 = " ::cue { color : black; background-color: PapayaWhip }";
|
|
||||||
WebvttCssStyle expectedStyle = new WebvttCssStyle();
|
WebvttCssStyle expectedStyle = new WebvttCssStyle();
|
||||||
|
String styleBlock1 = " ::cue { color : black; background-color: PapayaWhip }";
|
||||||
expectedStyle.setFontColor(0xFF000000);
|
expectedStyle.setFontColor(0xFF000000);
|
||||||
expectedStyle.setBackgroundColor(0xFFFFEFD5);
|
expectedStyle.setBackgroundColor(0xFFFFEFD5);
|
||||||
assertParserProduces(expectedStyle, styleBlock1);
|
assertParserProduces(styleBlock1, expectedStyle);
|
||||||
|
|
||||||
String styleBlock2 = " ::cue { color : black }\n\n::cue { color : invalid }";
|
String styleBlock2 = " ::cue { color : black }\n\n::cue { color : invalid }";
|
||||||
expectedStyle = new WebvttCssStyle();
|
expectedStyle = new WebvttCssStyle();
|
||||||
expectedStyle.setFontColor(0xFF000000);
|
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 = new WebvttCssStyle();
|
||||||
expectedStyle.setBackgroundColor(0xFF00FFFE);
|
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
|
@Test
|
||||||
|
|
@ -116,7 +128,7 @@ public final class CssParserTest {
|
||||||
expectedStyle.setFontFamily("courier");
|
expectedStyle.setFontFamily("courier");
|
||||||
expectedStyle.setBold(true);
|
expectedStyle.setBold(true);
|
||||||
|
|
||||||
assertParserProduces(expectedStyle, styleBlock);
|
assertParserProduces(styleBlock, expectedStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -128,7 +140,7 @@ public final class CssParserTest {
|
||||||
expectedStyle.setBackgroundColor(0x190A0B0C);
|
expectedStyle.setBackgroundColor(0x190A0B0C);
|
||||||
expectedStyle.setFontColor(0xFF010101);
|
expectedStyle.setFontColor(0xFF010101);
|
||||||
|
|
||||||
assertParserProduces(expectedStyle, styleBlock);
|
assertParserProduces(styleBlock, expectedStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -203,10 +215,13 @@ public final class CssParserTest {
|
||||||
assertThat(input.readLine()).isEqualTo(expectedLine);
|
assertThat(input.readLine()).isEqualTo(expectedLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertParserProduces(WebvttCssStyle expected,
|
private void assertParserProduces(String styleBlock, WebvttCssStyle... expectedStyles) {
|
||||||
String styleBlock){
|
|
||||||
ParsableByteArray input = new ParsableByteArray(Util.getUtf8Bytes(styleBlock));
|
ParsableByteArray input = new ParsableByteArray(Util.getUtf8Bytes(styleBlock));
|
||||||
WebvttCssStyle actualElem = parser.parseBlock(input);
|
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());
|
assertThat(actualElem.hasBackgroundColor()).isEqualTo(expected.hasBackgroundColor());
|
||||||
if (expected.hasBackgroundColor()) {
|
if (expected.hasBackgroundColor()) {
|
||||||
assertThat(actualElem.getBackgroundColor()).isEqualTo(expected.getBackgroundColor());
|
assertThat(actualElem.getBackgroundColor()).isEqualTo(expected.getBackgroundColor());
|
||||||
|
|
@ -223,5 +238,6 @@ public final class CssParserTest {
|
||||||
assertThat(actualElem.isUnderline()).isEqualTo(expected.isUnderline());
|
assertThat(actualElem.isUnderline()).isEqualTo(expected.isUnderline());
|
||||||
assertThat(actualElem.getTextAlign()).isEqualTo(expected.getTextAlign());
|
assertThat(actualElem.getTextAlign()).isEqualTo(expected.getTextAlign());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue