WebVTT CSS Styling -- Support for element selectors

This CL allows style blocks to reference elements. For example: we could style
a cue with text "Sometimes <b>bold</b> is not enough" with the style block
::cue(b) { ... }.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=119734779
This commit is contained in:
aquilescanta 2016-04-13 04:50:42 -07:00 committed by Oliver Woodman
parent f963c626af
commit c2beffc6c5
8 changed files with 136 additions and 125 deletions

View File

@ -14,6 +14,9 @@ STYLE
color: peachpuff; color: peachpuff;
} }
STYLE
::cue(v){text-decoration:underline}
id1 id1
00:00.000 --> 00:01.234 00:00.000 --> 00:01.234
This is the first subtitle. This is the first subtitle.
@ -21,3 +24,6 @@ This is the first subtitle.
id2 id2
00:02.345 --> 00:03.456 00:02.345 --> 00:03.456
This is the second subtitle. This is the second subtitle.
00:20.000 --> 00:21.000
This is a <v Mary>reference by element</v>

View File

@ -21,6 +21,8 @@ import android.text.Spanned;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan;
import java.util.Collections;
/** /**
* Unit test for {@link WebvttCueParser}. * Unit test for {@link WebvttCueParser}.
*/ */
@ -221,7 +223,8 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
private static Spanned parseCueText(String string) { private static Spanned parseCueText(String string) {
WebvttCue.Builder builder = new WebvttCue.Builder(); WebvttCue.Builder builder = new WebvttCue.Builder();
WebvttCueParser.parseCueText(string, builder); WebvttCueParser.parseCueText(null, string, builder,
Collections.<String, WebvttCssStyle>emptyMap());
return (Spanned) builder.build().text; return (Spanned) builder.build().text;
} }

View File

@ -24,6 +24,7 @@ import android.text.Layout.Alignment;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.BackgroundColorSpan; import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -154,7 +155,7 @@ public class WebvttParserTest extends InstrumentationTestCase {
WebvttSubtitle subtitle = parser.decode(bytes, bytes.length); WebvttSubtitle subtitle = parser.decode(bytes, bytes.length);
// Test event count. // Test event count.
assertEquals(4, subtitle.getEventTimeCount()); assertEquals(6, subtitle.getEventTimeCount());
// Test cues. // Test cues.
assertCue(subtitle, 0, 0, 1234000, "This is the first subtitle."); assertCue(subtitle, 0, 0, 1234000, "This is the first subtitle.");
@ -162,11 +163,14 @@ public class WebvttParserTest extends InstrumentationTestCase {
Cue cue1 = subtitle.getCues(0).get(0); Cue cue1 = subtitle.getCues(0).get(0);
Cue cue2 = subtitle.getCues(2345000).get(0); Cue cue2 = subtitle.getCues(2345000).get(0);
Cue cue3 = subtitle.getCues(20000000).get(0);
Spanned s1 = (Spanned) cue1.text; Spanned s1 = (Spanned) cue1.text;
Spanned s2 = (Spanned) cue2.text; Spanned s2 = (Spanned) cue2.text;
Spanned s3 = (Spanned) cue3.text;
assertEquals(1, s1.getSpans(0, s1.length(), ForegroundColorSpan.class).length); assertEquals(1, s1.getSpans(0, s1.length(), ForegroundColorSpan.class).length);
assertEquals(1, s1.getSpans(0, s1.length(), BackgroundColorSpan.class).length); assertEquals(1, s1.getSpans(0, s1.length(), BackgroundColorSpan.class).length);
assertEquals(2, s2.getSpans(0, s2.length(), ForegroundColorSpan.class).length); assertEquals(2, s2.getSpans(0, s2.length(), ForegroundColorSpan.class).length);
assertEquals(1, s3.getSpans(10, s3.length(), UnderlineSpan.class).length);
} }
private static void assertCue(WebvttSubtitle subtitle, int eventTimeIndex, long startTimeUs, private static void assertCue(WebvttSubtitle subtitle, int eventTimeIndex, long startTimeUs,

View File

@ -86,20 +86,22 @@ import java.util.Map;
} }
/** /**
* Returns a string containing the selector. Empty string is the universal selector, and null * Returns a string containing the selector. {@link WebvttCueParser#UNIVERSAL_CUE_ID} is the
* means syntax error. * universal selector, and null means syntax error.
* *
* <p> Expected inputs are: * <p>Expected inputs are:
* ::cue * <ul>
* ::cue(#id) * <li>::cue
* ::cue(elem) * <li>::cue(#id)
* ::cue(.class) * <li>::cue(elem)
* ::cue(elem.class) * <li>::cue(.class)
* ::cue(v[voice="Someone"]) * <li>::cue(elem.class)
* <li>::cue(v[voice="Someone"])
* </ul>
* *
* @param input From which the selector is obtained. * @param input From which the selector is obtained.
* @return A string containing the target, {@link WebvttCue#UNIVERSAL_CUE_ID} if targets all cues * @return A string containing the target, {@link WebvttCueParser#UNIVERSAL_CUE_ID} if the
* and null if an error was encountered. * selector is universal (targets all cues) or null if an error was encountered.
*/ */
private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) { private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) {
skipWhitespaceAndComments(input); skipWhitespaceAndComments(input);
@ -117,7 +119,7 @@ import java.util.Map;
} }
if ("{".equals(token)) { if ("{".equals(token)) {
input.setPosition(position); input.setPosition(position);
return WebvttCue.UNIVERSAL_CUE_ID; return WebvttCueParser.UNIVERSAL_CUE_ID;
} }
String target = null; String target = null;
if ("(".equals(token)) { if ("(".equals(token)) {

View File

@ -22,6 +22,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -82,7 +83,8 @@ public final class Mp4WebvttParser extends SubtitleParser {
if (boxType == TYPE_sttg) { if (boxType == TYPE_sttg) {
WebvttCueParser.parseCueSettingsList(boxPayload, builder); WebvttCueParser.parseCueSettingsList(boxPayload, builder);
} else if (boxType == TYPE_payl) { } else if (boxType == TYPE_payl) {
WebvttCueParser.parseCueText(boxPayload.trim(), builder); WebvttCueParser.parseCueText(null, boxPayload.trim(), builder,
Collections.<String, WebvttCssStyle>emptyMap());
} else { } else {
// Other VTTCueBox children are still not supported and are ignored. // Other VTTCueBox children are still not supported and are ignored.
} }

View File

@ -18,32 +18,14 @@ package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
import android.text.Layout.Alignment; import android.text.Layout.Alignment;
import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import android.util.Log; import android.util.Log;
import java.util.Collections;
import java.util.Map;
/** /**
* A representation of a WebVTT cue. * A representation of a WebVTT cue.
*/ */
/* package */ final class WebvttCue extends Cue { /* package */ final class WebvttCue extends Cue {
public static final String UNIVERSAL_CUE_ID = "";
public static final String CUE_ID_PREFIX = "#";
public final String id;
public final long startTime; public final long startTime;
public final long endTime; public final long endTime;
@ -52,15 +34,13 @@ import java.util.Map;
} }
public WebvttCue(long startTime, long endTime, CharSequence text) { public WebvttCue(long startTime, long endTime, CharSequence text) {
this(null, startTime, endTime, text, null, Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.TYPE_UNSET, this(startTime, endTime, text, null, Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.TYPE_UNSET,
Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.DIMEN_UNSET); Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.DIMEN_UNSET);
} }
public WebvttCue(String id, long startTime, long endTime, CharSequence text, public WebvttCue(long startTime, long endTime, CharSequence text, Alignment textAlignment,
Alignment textAlignment, float line, int lineType, int lineAnchor, float position, float line, int lineType, int lineAnchor, float position, int positionAnchor, float width) {
int positionAnchor, float width) {
super(text, textAlignment, line, lineType, lineAnchor, position, positionAnchor, width); super(text, textAlignment, line, lineType, lineAnchor, position, positionAnchor, width);
this.id = id;
this.startTime = startTime; this.startTime = startTime;
this.endTime = endTime; this.endTime = endTime;
} }
@ -83,7 +63,6 @@ import java.util.Map;
private static final String TAG = "WebvttCueBuilder"; private static final String TAG = "WebvttCueBuilder";
private String id;
private long startTime; private long startTime;
private long endTime; private long endTime;
private SpannableStringBuilder text; private SpannableStringBuilder text;
@ -117,25 +96,13 @@ import java.util.Map;
// Construction methods. // Construction methods.
public WebvttCue build() { public WebvttCue build() {
return build(Collections.<String, WebvttCssStyle>emptyMap());
}
public WebvttCue build(Map<String, WebvttCssStyle> styleMap) {
// TODO: Add support for inner spans.
maybeApplyStyleToText(styleMap.get(UNIVERSAL_CUE_ID), 0, text.length());
maybeApplyStyleToText(styleMap.get(CUE_ID_PREFIX + id), 0, text.length());
if (position != Cue.DIMEN_UNSET && positionAnchor == Cue.TYPE_UNSET) { if (position != Cue.DIMEN_UNSET && positionAnchor == Cue.TYPE_UNSET) {
derivePositionAnchorFromAlignment(); derivePositionAnchorFromAlignment();
} }
return new WebvttCue(id, startTime, endTime, text, textAlignment, line, lineType, lineAnchor, return new WebvttCue(startTime, endTime, text, textAlignment, line, lineType, lineAnchor,
position, positionAnchor, width); position, positionAnchor, width);
} }
public Builder setId(String id) {
this.id = id;
return this;
}
public Builder setStartTime(long time) { public Builder setStartTime(long time) {
startTime = time; startTime = time;
return this; return this;
@ -209,54 +176,6 @@ import java.util.Map;
return this; return this;
} }
private void maybeApplyStyleToText(WebvttCssStyle style, int start, int end) {
if (style == null) {
return;
}
if (style.getStyle() != WebvttCssStyle.UNSPECIFIED) {
text.setSpan(new StyleSpan(style.getStyle()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isLinethrough()) {
text.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isUnderline()) {
text.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasFontColor()) {
text.setSpan(new ForegroundColorSpan(style.getFontColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasBackgroundColor()) {
text.setSpan(new BackgroundColorSpan(style.getBackgroundColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontFamily() != null) {
text.setSpan(new TypefaceSpan(style.getFontFamily()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextAlign() != null) {
text.setSpan(new AlignmentSpan.Standard(style.getTextAlign()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontSizeUnit() != WebvttCssStyle.UNSPECIFIED) {
switch (style.getFontSizeUnit()) {
case WebvttCssStyle.FONT_SIZE_UNIT_PIXEL:
text.setSpan(new AbsoluteSizeSpan((int) style.getFontSize(), true), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case WebvttCssStyle.FONT_SIZE_UNIT_EM:
text.setSpan(new RelativeSizeSpan(style.getFontSize()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case WebvttCssStyle.FONT_SIZE_UNIT_PERCENT:
text.setSpan(new RelativeSizeSpan(style.getFontSize() / 100), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
}
}
} }
} }

View File

@ -20,12 +20,21 @@ import com.google.android.exoplayer.util.ParsableByteArray;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.text.Layout.Alignment; import android.text.Layout.Alignment;
import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan;
import android.util.Log; import android.util.Log;
import java.util.Map;
import java.util.Stack; import java.util.Stack;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -35,6 +44,8 @@ import java.util.regex.Pattern;
*/ */
/* package */ final class WebvttCueParser { /* package */ final class WebvttCueParser {
public static final String UNIVERSAL_CUE_ID = "";
public static final String CUE_ID_PREFIX = "#";
public static final Pattern CUE_HEADER_PATTERN = Pattern public static final Pattern CUE_HEADER_PATTERN = Pattern
.compile("^(\\S+)\\s+-->\\s+(\\S+)(.*)?$"); .compile("^(\\S+)\\s+-->\\s+(\\S+)(.*)?$");
@ -76,22 +87,24 @@ import java.util.regex.Pattern;
* *
* @param webvttData Parsable WebVTT file data. * @param webvttData Parsable WebVTT file data.
* @param builder Builder for WebVTT Cues. * @param builder Builder for WebVTT Cues.
* @param styleMap Maps selector to style as referenced by the CSS ::cue pseudo-element.
* @return True if a valid Cue was found, false otherwise. * @return True if a valid Cue was found, false otherwise.
*/ */
/* package */ boolean parseCue(ParsableByteArray webvttData, WebvttCue.Builder builder) { /* package */ boolean parseCue(ParsableByteArray webvttData, WebvttCue.Builder builder,
Map<String, WebvttCssStyle> styleMap) {
String firstLine = webvttData.readLine(); String firstLine = webvttData.readLine();
Matcher cueHeaderMatcher = WebvttCueParser.CUE_HEADER_PATTERN.matcher(firstLine); Matcher cueHeaderMatcher = WebvttCueParser.CUE_HEADER_PATTERN.matcher(firstLine);
if (cueHeaderMatcher.matches()) { if (cueHeaderMatcher.matches()) {
// We have found the timestamps in the first line. No id present. // We have found the timestamps in the first line. No id present.
return parseCue(cueHeaderMatcher, webvttData, builder, textBuilder); return parseCue(null, cueHeaderMatcher, webvttData, builder, textBuilder, styleMap);
} else { } else {
// The first line is not the timestamps, but could be the cue id. // The first line is not the timestamps, but could be the cue id.
String secondLine = webvttData.readLine(); String secondLine = webvttData.readLine();
cueHeaderMatcher = WebvttCueParser.CUE_HEADER_PATTERN.matcher(secondLine); cueHeaderMatcher = WebvttCueParser.CUE_HEADER_PATTERN.matcher(secondLine);
if (cueHeaderMatcher.matches()) { if (cueHeaderMatcher.matches()) {
// We can do the rest of the parsing, including the id. // We can do the rest of the parsing, including the id.
builder.setId(firstLine.trim()); return parseCue(firstLine.trim(), cueHeaderMatcher, webvttData, builder, textBuilder,
return parseCue(cueHeaderMatcher, webvttData, builder, textBuilder); styleMap);
} }
} }
return false; return false;
@ -131,10 +144,13 @@ import java.util.regex.Pattern;
/** /**
* Parses the text payload of a WebVTT Cue and applies modifications on {@link WebvttCue.Builder}. * Parses the text payload of a WebVTT Cue and applies modifications on {@link WebvttCue.Builder}.
* *
* @param id Id of the cue, {@code null} if it is not present.
* @param markup The markup text to be parsed. * @param markup The markup text to be parsed.
* @param styleMap Maps selector to style as referenced by the CSS ::cue pseudo-element.
* @param builder Target builder. * @param builder Target builder.
*/ */
/* package */ static void parseCueText(String markup, WebvttCue.Builder builder) { /* package */ static void parseCueText(String id, String markup, WebvttCue.Builder builder,
Map<String, WebvttCssStyle> styleMap) {
SpannableStringBuilder spannedText = new SpannableStringBuilder(); SpannableStringBuilder spannedText = new SpannableStringBuilder();
Stack<StartTag> startTagStack = new Stack<>(); Stack<StartTag> startTagStack = new Stack<>();
String[] tagTokens; String[] tagTokens;
@ -164,7 +180,7 @@ import java.util.regex.Pattern;
break; break;
} }
startTag = startTagStack.pop(); startTag = startTagStack.pop();
applySpansForTag(startTag, spannedText); applySpansForTag(startTag, spannedText, styleMap);
} while(!startTag.name.equals(tagTokens[0])); } while(!startTag.name.equals(tagTokens[0]));
} else if (!isVoidTag) { } else if (!isVoidTag) {
startTagStack.push(new StartTag(tagTokens[0], spannedText.length())); startTagStack.push(new StartTag(tagTokens[0], spannedText.length()));
@ -194,13 +210,15 @@ import java.util.regex.Pattern;
} }
// apply unclosed tags // apply unclosed tags
while (!startTagStack.isEmpty()) { while (!startTagStack.isEmpty()) {
applySpansForTag(startTagStack.pop(), spannedText); applySpansForTag(startTagStack.pop(), spannedText, styleMap);
} }
applyStyleToText(spannedText, styleMap.get(UNIVERSAL_CUE_ID), 0, spannedText.length());
applyStyleToText(spannedText, styleMap.get(CUE_ID_PREFIX + id), 0, spannedText.length());
builder.setText(spannedText); builder.setText(spannedText);
} }
private static boolean parseCue(Matcher cueHeaderMatcher, ParsableByteArray webvttData, private static boolean parseCue(String id, Matcher cueHeaderMatcher, ParsableByteArray webvttData,
WebvttCue.Builder builder, StringBuilder textBuilder) { WebvttCue.Builder builder, StringBuilder textBuilder, Map<String, WebvttCssStyle> styleMap) {
try { try {
// Parse the cue start and end times. // Parse the cue start and end times.
builder.setStartTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1))) builder.setStartTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1)))
@ -221,7 +239,7 @@ import java.util.regex.Pattern;
} }
textBuilder.append(line.trim()); textBuilder.append(line.trim());
} }
parseCueText(textBuilder.toString(), builder); parseCueText(id, textBuilder.toString(), builder, styleMap);
return true; return true;
} }
@ -333,22 +351,79 @@ import java.util.regex.Pattern;
} }
} }
private static void applySpansForTag(StartTag startTag, SpannableStringBuilder spannedText) { private static void applySpansForTag(StartTag startTag, SpannableStringBuilder spannedText,
Map<String, WebvttCssStyle> styleMap) {
WebvttCssStyle styleForTag = styleMap.get(startTag.name);
int start = startTag.position;
int end = spannedText.length();
switch(startTag.name) { switch(startTag.name) {
case TAG_BOLD: case TAG_BOLD:
spannedText.setSpan(new StyleSpan(STYLE_BOLD), startTag.position, spannedText.setSpan(new StyleSpan(STYLE_BOLD), start, end,
spannedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return;
case TAG_ITALIC:
spannedText.setSpan(new StyleSpan(STYLE_ITALIC), startTag.position,
spannedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return;
case TAG_UNDERLINE:
spannedText.setSpan(new UnderlineSpan(), startTag.position,
spannedText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return;
default:
break; break;
case TAG_ITALIC:
spannedText.setSpan(new StyleSpan(STYLE_ITALIC), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TAG_UNDERLINE:
spannedText.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TAG_CLASS:
case TAG_LANG:
case TAG_VOICE:
break;
default:
return;
}
applyStyleToText(spannedText, styleForTag, start, end);
}
private static void applyStyleToText(SpannableStringBuilder spannedText,
WebvttCssStyle style, int start, int end) {
if (style == null) {
return;
}
if (style.getStyle() != WebvttCssStyle.UNSPECIFIED) {
spannedText.setSpan(new StyleSpan(style.getStyle()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isLinethrough()) {
spannedText.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isUnderline()) {
spannedText.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasFontColor()) {
spannedText.setSpan(new ForegroundColorSpan(style.getFontColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasBackgroundColor()) {
spannedText.setSpan(new BackgroundColorSpan(style.getBackgroundColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontFamily() != null) {
spannedText.setSpan(new TypefaceSpan(style.getFontFamily()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextAlign() != null) {
spannedText.setSpan(new AlignmentSpan.Standard(style.getTextAlign()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontSizeUnit() != WebvttCssStyle.UNSPECIFIED) {
switch (style.getFontSizeUnit()) {
case WebvttCssStyle.FONT_SIZE_UNIT_PIXEL:
spannedText.setSpan(new AbsoluteSizeSpan((int) style.getFontSize(), true), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case WebvttCssStyle.FONT_SIZE_UNIT_EM:
spannedText.setSpan(new RelativeSizeSpan(style.getFontSize()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case WebvttCssStyle.FONT_SIZE_UNIT_PERCENT:
spannedText.setSpan(new RelativeSizeSpan(style.getFontSize() / 100), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
}
} }
} }

View File

@ -76,8 +76,8 @@ public final class WebvttParser extends SubtitleParser {
parsableWebvttData.readLine(); // Consume the "STYLE" header. parsableWebvttData.readLine(); // Consume the "STYLE" header.
cssParser.parseBlock(parsableWebvttData, styleMap); cssParser.parseBlock(parsableWebvttData, styleMap);
} else if (eventFound == CUE_FOUND) { } else if (eventFound == CUE_FOUND) {
if (cueParser.parseCue(parsableWebvttData, webvttCueBuilder)) { if (cueParser.parseCue(parsableWebvttData, webvttCueBuilder, styleMap)) {
subtitles.add(webvttCueBuilder.build(styleMap)); subtitles.add(webvttCueBuilder.build());
webvttCueBuilder.reset(); webvttCueBuilder.reset();
} }
} }