Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
aaf57c76
authored
Jun 19, 2019
by
bachinger
Committed by
Oliver Woodman
Jun 19, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
allow multiple style rules in a STYLE block of a webvtt file
PiperOrigin-RevId: 253959976
parent
1952988f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
78 additions
and
57 deletions
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/CssParser.java
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java
library/core/src/test/assets/webvtt/with_css_styles
library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/CssParser.java
View file @
aaf57c76
...
@@ -20,6 +20,8 @@ import android.text.TextUtils;
...
@@ -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;
...
@@ -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,38 +55,46 @@ import java.util.regex.Pattern;
...
@@ -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
* 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
)
{
WebvttCssStyle
style
=
new
WebvttCssStyle
();
if
(!
RULE_START
.
equals
(
parseNextToken
(
styleInput
,
stringBuilder
)))
{
applySelectorToStyle
(
style
,
selector
);
return
styles
;
String
token
=
null
;
}
boolean
blockEndFound
=
false
;
WebvttCssStyle
style
=
new
WebvttCssStyle
();
while
(!
blockEndFound
)
{
applySelectorToStyle
(
style
,
selector
);
int
position
=
styleInput
.
getPosition
();
String
token
=
null
;
token
=
parseNextToken
(
styleInput
,
stringBuilder
);
boolean
blockEndFound
=
false
;
blockEndFound
=
token
==
null
||
BLOCK_END
.
equals
(
token
);
while
(!
blockEndFound
)
{
if
(!
blockEndFound
)
{
int
position
=
styleInput
.
getPosition
();
styleInput
.
setPosition
(
position
);
token
=
parseNextToken
(
styleInput
,
stringBuilder
);
parseStyleDeclaration
(
styleInput
,
style
,
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;
...
@@ -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;
...
@@ -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;
...
@@ -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
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java
View file @
aaf57c76
...
@@ -80,10 +80,7 @@ public final class WebvttDecoder extends SimpleSubtitleDecoder {
...
@@ -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
());
...
...
library/core/src/test/assets/webvtt/with_css_styles
View file @
aaf57c76
...
@@ -13,8 +13,6 @@ STYLE
...
@@ -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
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/CssParserTest.java
View file @
aaf57c76
...
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
...
@@ -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 {
...
@@ -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 {
...
@@ -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 {
...
@@ -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,25 +215,29 @@ public final class CssParserTest {
...
@@ -203,25 +215,29 @@ 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
(
actualElem
.
hasBackgroundColor
()).
isEqualTo
(
expected
.
hasBackgroundColor
());
assertThat
(
styles
.
size
()).
isEqualTo
(
expectedStyles
.
length
);
if
(
expected
.
hasBackgroundColor
())
{
for
(
int
i
=
0
;
i
<
expectedStyles
.
length
;
i
++)
{
assertThat
(
actualElem
.
getBackgroundColor
()).
isEqualTo
(
expected
.
getBackgroundColor
());
WebvttCssStyle
expected
=
expectedStyles
[
i
];
}
WebvttCssStyle
actualElem
=
styles
.
get
(
i
);
assertThat
(
actualElem
.
hasFontColor
()).
isEqualTo
(
expected
.
hasFontColor
());
assertThat
(
actualElem
.
hasBackgroundColor
()).
isEqualTo
(
expected
.
hasBackgroundColor
());
if
(
expected
.
hasFontColor
())
{
if
(
expected
.
hasBackgroundColor
())
{
assertThat
(
actualElem
.
getFontColor
()).
isEqualTo
(
expected
.
getFontColor
());
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
.
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
());
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment