Commit b6f15a17 by Oliver Woodman

TTML improvements.

- do not denormalize styles at parsing time but only put normalized style info
into TtmlNode tree. Resolve styles on demand when Cues are requested for a
given timeUs.
- create TtmlRenderUtil to have static render functions separate
- added unit test for TtmlRenderUtil
- adjusted testing strategy for unit test to check resolved style on Spannables after rendering
parent 908e4dfd
......@@ -18,6 +18,9 @@
<style style="s0 s1" id="s2"
tts:fontFamily="serif"
tts:backgroundColor="red" />
<style style="s1 s0" id="s3"
tts:fontFamily="serif"
tts:backgroundColor="red" />
</styling>
</head>
<body>
......
......@@ -26,20 +26,20 @@
<p style="s0 s1" begin="10s" end="18s" tts:color="yellow">text 1</p>
</div>
<div>
<p style="s0 s1" begin="20s" end="28s">text 1</p>
<p style="s0 s1" begin="20s" end="28s">text 2</p>
</div>
<div tts:color="yellow" tts:textDecoration="underline" tts:fontStyle="italic" tts:fontFamily="sansSerifInline">
<p style="s2 s3" begin="30s" end="38s">text 1</p>
<p style="s2 s3" begin="30s" end="38s">text 2.5</p>
</div>
<div>
<!-- empty style attribute -->
<p style=" " begin="40s" end="48s">text 1</p>
<p style=" " begin="40s" end="48s">text 3</p>
</div>
<div>
<p style="not_existing" begin="50s" end="58s">text 1</p>
<p style="not_existing" begin="50s" end="58s">text 4</p>
</div>
<div>
<p style="not_existing s2" begin="60s" end="68s">text 1</p>
<p style="not_existing s2" begin="60s" end="68s">text 5</p>
</div>
</body>
</tt>
<tt xmlns:ttm="http://www.w3.org/2006/10/ttaf1#metadata" xmlns:ttp="http://www.w3.org/2006/10/ttaf1#parameter"
xmlns:tts="http://www.w3.org/2006/10/ttaf1#style"
xmlns="http://www.w3.org/ns/ttml"
xmlns="http://www.w3.org/2006/10/ttaf1">
<head>
<styling>
<style id="s0"
tts:color="blue"/>
<style id="s1"
tts:backgroundColor="red"/>
</styling>
</head>
<body style="s0">
<div>
<p style="s0" begin="10s" end="18s">text 1</p>
</div>
<div>
<p style="s0" begin="20s" end="28s">text <span style="s0">2</span></p>
</div>
<div>
<p style="s1" begin="20s" end="28s">text <span style="s1">3</span></p>
</div>
</body>
</tt>
<tt xmlns="http://www.w3.org/ns/ttml"
xmlns="http://www.w3.org/2006/10/ttaf1"
xmlns:ttp="http://www.w3.org/2006/10/ttaf1#parameter"
xmlns:tts="http://www.w3.org/2006/10/ttaf1#style"
xmlns:ttm="http://www.w3.org/2006/10/ttaf1#metadata">
<body>
<div>
<p begin="10s" end="18s"
tts:fontWeight="bold"
tts:fontStyle="italic"
tts:fontFamily="serif"
tts:textDecoration="underline"
tts:backgroundColor="blue"
tts:color="yellow">
<span>text 1</span>
</p>
</div>
</body>
</tt>
package com.google.android.exoplayer.text.ttml;
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.graphics.Color;
import android.test.InstrumentationTestCase;
import java.util.HashMap;
import java.util.Map;
/**
* Unit test for <code>TtmlRenderUtil</code>
*/
public class TtmlRenderUtilTest extends InstrumentationTestCase {
public void testResolveStyleNoStyleAtAll() {
assertNull(TtmlRenderUtil.resolveStyle(null, null, null));
}
public void testResolveStyleSingleReferentialStyle() {
Map<String, TtmlStyle> globalStyles = getGlobalStyles();
String[] styleIds = {"s0"};
assertSame(globalStyles.get("s0"),
TtmlRenderUtil.resolveStyle(null, styleIds, globalStyles));
}
public void testResolveStyleMultipleReferentialStyles() {
Map<String, TtmlStyle> globalStyles = getGlobalStyles();
String[] styleIds = {"s0", "s1"};
TtmlStyle resolved = TtmlRenderUtil.resolveStyle(null, styleIds, globalStyles);
assertNotSame(globalStyles.get("s0"), resolved);
assertNotSame(globalStyles.get("s1"), resolved);
assertNull(resolved.getId());
// inherited from s0
assertEquals(Color.BLACK, resolved.getBackgroundColor());
// inherited from s1
assertEquals(Color.RED, resolved.getColor());
// merged from s0 and s1
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, resolved.getStyle());
}
public void testResolveMergeSingleReferentialStyleIntoInlineStyle() {
Map<String, TtmlStyle> globalStyles = getGlobalStyles();
String[] styleIds = {"s0"};
TtmlStyle style = new TtmlStyle();
style.setBackgroundColor(Color.YELLOW);
TtmlStyle resolved = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
assertSame(style, resolved);
// inline attribute not overridden
assertEquals(Color.YELLOW, resolved.getBackgroundColor());
// inherited from referential style
assertEquals(TtmlStyle.STYLE_BOLD, resolved.getStyle());
}
public void testResolveMergeMultipleReferentialStylesIntoInlineStyle() {
Map<String, TtmlStyle> globalStyles = getGlobalStyles();
String[] styleIds = {"s0", "s1"};
TtmlStyle style = new TtmlStyle();
style.setBackgroundColor(Color.YELLOW);
TtmlStyle resolved = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
assertSame(style, resolved);
// inline attribute not overridden
assertEquals(Color.YELLOW, resolved.getBackgroundColor());
// inherited from both referential style
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, resolved.getStyle());
}
public void testResolveStyleOnlyInlineStyle() {
TtmlStyle inlineStyle = new TtmlStyle();
assertSame(inlineStyle, TtmlRenderUtil.resolveStyle(inlineStyle, null, null));
}
private Map<String, TtmlStyle> getGlobalStyles() {
Map<String, TtmlStyle> globalStyles = new HashMap<>();
TtmlStyle s0 = new TtmlStyle();
s0.setId("s0");
s0.setBackgroundColor(Color.BLACK);
s0.setBold(true);
globalStyles.put(s0.getId(), s0);
TtmlStyle s1 = new TtmlStyle();
s1.setId("s1");
s1.setBackgroundColor(Color.RED);
s1.setColor(Color.RED);
s1.setItalic(true);
globalStyles.put(s1.getId(), s1);
return globalStyles;
}
}
......@@ -15,20 +15,12 @@
*/
package com.google.android.exoplayer.text.ttml;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
/**
......@@ -82,22 +74,28 @@ import java.util.TreeSet;
public final long startTimeUs;
public final long endTimeUs;
public final TtmlStyle style;
private String[] styleIds;
private List<TtmlNode> children;
private int start;
private int end;
public static TtmlNode buildTextNode(String text, TtmlStyle style) {
return new TtmlNode(null, applyTextElementSpacePolicy(text), UNDEFINED_TIME,
UNDEFINED_TIME, style);
public static TtmlNode buildTextNode(String text) {
return new TtmlNode(null, TtmlRenderUtil.applyTextElementSpacePolicy(text), UNDEFINED_TIME,
UNDEFINED_TIME, null, null);
}
public static TtmlNode buildNode(String tag, long startTimeUs, long endTimeUs, TtmlStyle style) {
return new TtmlNode(tag, null, startTimeUs, endTimeUs, style);
public static TtmlNode buildNode(String tag, long startTimeUs, long endTimeUs,
TtmlStyle style, String[] styleIds) {
return new TtmlNode(tag, null, startTimeUs, endTimeUs, style, styleIds);
}
private TtmlNode(String tag, String text, long startTimeUs, long endTimeUs, TtmlStyle style) {
private TtmlNode(String tag, String text, long startTimeUs, long endTimeUs,
TtmlStyle style, String[] styleIds) {
this.tag = tag;
this.text = text;
this.style = style;
this.styleIds = styleIds;
this.isTextNode = text != null;
this.startTimeUs = startTimeUs;
this.endTimeUs = endTimeUs;
......@@ -159,8 +157,14 @@ import java.util.TreeSet;
}
}
public CharSequence getText(long timeUs) {
SpannableStringBuilder builder = getText(timeUs, new SpannableStringBuilder(), false);
public String[] getStyleIds() {
return styleIds;
}
public CharSequence getText(long timeUs, Map<String, TtmlStyle> globalStyles) {
SpannableStringBuilder builder = new SpannableStringBuilder();
traverseForText(timeUs, builder, false);
traverseForStyle(builder, globalStyles);
// Having joined the text elements, we need to do some final cleanup on the result.
// 1. Collapse multiple consecutive spaces into a single space.
int builderLength = builder.length();
......@@ -208,12 +212,12 @@ import java.util.TreeSet;
return builder;
}
private SpannableStringBuilder getText(long timeUs, SpannableStringBuilder builder,
private SpannableStringBuilder traverseForText(long timeUs, SpannableStringBuilder builder,
boolean descendsPNode) {
start = builder.length();
end = start;
if (isTextNode && descendsPNode) {
int start = builder.length();
builder.append(text);
applyStylesToSpan(builder, start, builder.length(), style);
} else if (TAG_BR.equals(tag) && descendsPNode) {
builder.append('\n');
} else if (TAG_METADATA.equals(tag)) {
......@@ -221,79 +225,27 @@ import java.util.TreeSet;
} else if (isActive(timeUs)) {
boolean isPNode = TAG_P.equals(tag);
for (int i = 0; i < getChildCount(); ++i) {
getChild(i).getText(timeUs, builder, descendsPNode || isPNode);
getChild(i).traverseForText(timeUs, builder, descendsPNode || isPNode);
}
if (isPNode) {
endParagraph(builder);
TtmlRenderUtil.endParagraph(builder);
}
end = builder.length();
}
return builder;
}
private static void applyStylesToSpan(SpannableStringBuilder builder,
int start, int end, TtmlStyle style) {
if (style.getStyle() != TtmlStyle.UNSPECIFIED) {
builder.setSpan(new StyleSpan(style.getStyle()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isLinethrough()) {
builder.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isUnderline()) {
builder.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasColorSpecified()) {
builder.setSpan(new ForegroundColorSpan(style.getColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasBackgroundColorSpecified()) {
builder.setSpan(new BackgroundColorSpan(style.getBackgroundColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontFamily() != null) {
builder.setSpan(new TypefaceSpan(style.getFontFamily()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextAlign() != null) {
builder.setSpan(new AlignmentSpan.Standard(style.getTextAlign()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
/**
* Invoked when the end of a paragraph is encountered. Adds a newline if there are one or more
* non-space characters since the previous newline.
*
* @param builder The builder.
*/
private static void endParagraph(SpannableStringBuilder builder) {
int position = builder.length() - 1;
while (position >= 0 && builder.charAt(position) == ' ') {
position--;
}
if (position >= 0 && builder.charAt(position) != '\n') {
builder.append('\n');
private void traverseForStyle(SpannableStringBuilder builder,
Map<String, TtmlStyle> globalStyles) {
if (start != end) {
TtmlStyle resolvedStyle = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
if (resolvedStyle != null) {
TtmlRenderUtil.applyStylesToSpan(builder, start, end, resolvedStyle);
}
for (int i = 0; i < getChildCount(); ++i) {
getChild(i).traverseForStyle(builder, globalStyles);
}
}
}
/**
* Applies the appropriate space policy to the given text element.
*
* @param in The text element to which the policy should be applied.
* @return The result of applying the policy to the text element.
*/
private static String applyTextElementSpacePolicy(String in) {
// Removes carriage return followed by line feed. See: http://www.w3.org/TR/xml/#sec-line-ends
String out = in.replaceAll("\r\n", "\n");
// Apply suppress-at-line-break="auto" and
// white-space-treatment="ignore-if-surrounding-linefeed"
out = out.replaceAll(" *\n *", "\n");
// Apply linefeed-treatment="treat-as-space"
out = out.replaceAll("\n", " ");
// Apply white-space-collapse="true"
out = out.replaceAll("[ \t\\x0B\f\r]+", " ");
return out;
}
}
......@@ -127,7 +127,7 @@ public final class TtmlParser implements SubtitleParser {
parseHeader(xmlParser, globalStyles);
} else {
try {
TtmlNode node = parseNode(xmlParser, parent, globalStyles);
TtmlNode node = parseNode(xmlParser, parent);
nodeStack.addLast(node);
if (parent != null) {
parent.addChild(node);
......@@ -143,10 +143,10 @@ public final class TtmlParser implements SubtitleParser {
}
}
} else if (eventType == XmlPullParser.TEXT) {
parent.addChild(TtmlNode.buildTextNode(xmlParser.getText(), parent.style));
parent.addChild(TtmlNode.buildTextNode(xmlParser.getText()));
} else if (eventType == XmlPullParser.END_TAG) {
if (xmlParser.getName().equals(TtmlNode.TAG_TT)) {
ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast());
ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast(), globalStyles);
}
nodeStack.removeLast();
}
......@@ -176,7 +176,7 @@ public final class TtmlParser implements SubtitleParser {
String parentStyleId = xmlParser.getAttributeValue(null, ATTR_STYLE);
TtmlStyle style = parseStyleAttributes(xmlParser, new TtmlStyle());
if (parentStyleId != null) {
String[] ids = parentStyleId.split(" ");
String[] ids = parseStyleIds(parentStyleId);
for (int i = 0; i < ids.length; i++) {
style.chain(globalStyles.get(ids[i]));
}
......@@ -189,6 +189,10 @@ public final class TtmlParser implements SubtitleParser {
return globalStyles;
}
private String[] parseStyleIds(String parentStyleIds) {
return parentStyleIds.split("\\s+");
}
private TtmlStyle parseStyleAttributes(XmlPullParser parser, TtmlStyle style) {
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; i++) {
......@@ -282,23 +286,14 @@ public final class TtmlParser implements SubtitleParser {
return MimeTypes.APPLICATION_TTML.equals(mimeType);
}
private TtmlNode parseNode(XmlPullParser parser, TtmlNode parent,
Map<String, TtmlStyle> globalStyles) throws ParserException {
private TtmlNode parseNode(XmlPullParser parser, TtmlNode parent) throws ParserException {
long duration = 0;
long startTime = TtmlNode.UNDEFINED_TIME;
long endTime = TtmlNode.UNDEFINED_TIME;
String[] styleIds = null;
int attributeCount = parser.getAttributeCount();
TtmlStyle style = parseStyleAttributes(parser, null);
boolean hasInlineStyles = style != null;
if (parent != null && parent.style != null) {
if (hasInlineStyles) {
style.inherit(parent.style);
} else {
style = parent.style.getInheritableStyle();
}
}
for (int i = 0; i < attributeCount; i++) {
// TODO: check if it is safe to remove the namespace prefix
String attr = ParserUtil.removeNamespacePrefix(parser.getAttributeName(i));
String value = parser.getAttributeValue(i);
if (attr.equals(ATTR_BEGIN)) {
......@@ -312,32 +307,10 @@ public final class TtmlParser implements SubtitleParser {
DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE);
} else if (attr.equals(ATTR_STYLE)) {
// IDREFS: potentially multiple space delimited ids
String[] ids = value.split(" ");
if (style == null) {
// use global style without overriding
if (ids.length == 1) {
style = globalStyles.get(value);
} else if (ids.length > 1){
style = new TtmlStyle();
for (int j = 0; j < ids.length; j++) {
style.chain(globalStyles.get(ids[j]));
}
}
} else if (hasInlineStyles) {
// local attributes inherits from global style
for (int j = 0; j < ids.length; j++) {
style.chain(globalStyles.get(ids[j]));
}
} else if (ids.length > 1 || (ids.length == 1 && style != globalStyles.get(ids[0]))) {
// merge global style and parent styles
TtmlStyle inheritedStyles = style;
style = new TtmlStyle();
for (int j = 0; j < ids.length; j++) {
style.chain(globalStyles.get(ids[j]));
}
style.inherit(inheritedStyles);
String[] ids = parseStyleIds(value);
if (ids.length > 0) {
styleIds = ids;
}
} else {
// Do nothing.
}
......@@ -359,7 +332,7 @@ public final class TtmlParser implements SubtitleParser {
endTime = parent.endTimeUs;
}
}
return TtmlNode.buildNode(parser.getName(), startTime, endTime, style);
return TtmlNode.buildNode(parser.getName(), startTime, endTime, style, styleIds);
}
private static boolean isSupportedTag(String tag) {
......
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.text.ttml;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import java.util.Map;
/**
* Package internal utility class to render styled <code>TtmlNode</code>s.
*/
/* package */ final class TtmlRenderUtil {
/* spans which are always the same can be reused to avoid object creation */
private static final StrikethroughSpan STRIKETHROUGH_SPAN = new StrikethroughSpan();
private static final UnderlineSpan UNDERLINE_SPAN = new UnderlineSpan();
private static final StyleSpan[] STYLE_SPANS = new StyleSpan[] {
new StyleSpan(TtmlStyle.STYLE_NORMAL),
new StyleSpan(TtmlStyle.STYLE_BOLD),
new StyleSpan(TtmlStyle.STYLE_ITALIC),
new StyleSpan(TtmlStyle.STYLE_BOLD_ITALIC),
};
public static TtmlStyle resolveStyle(TtmlStyle style, String[] styleIds,
Map<String, TtmlStyle> globalStyles) {
if (style == null && styleIds == null) {
// no styles at all
return null;
} else if (style == null && styleIds.length == 1) {
// only one single referential style present
return globalStyles.get(styleIds[0]);
} else if (style == null && styleIds.length > 1) {
// only multiple referential styles present
TtmlStyle chainedStyle = new TtmlStyle();
for (int i = 0; i < styleIds.length; i++) {
chainedStyle.chain(globalStyles.get(styleIds[i]));
}
return chainedStyle;
} else if (style != null && styleIds != null && styleIds.length == 1) {
// merge a single referential style into inline style
return style.chain(globalStyles.get(styleIds[0]));
} else if (style != null && styleIds != null && styleIds.length > 1) {
// merge multiple referential styles into inline style
for (int i = 0; i < styleIds.length; i++) {
style.chain(globalStyles.get(styleIds[i]));
}
return style;
}
// only inline styles available
return style;
}
public static void applyStylesToSpan(SpannableStringBuilder builder,
int start, int end, TtmlStyle style) {
if (style.getStyle() != TtmlStyle.UNSPECIFIED) {
builder.setSpan(STYLE_SPANS[style.getStyle()], start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isLinethrough()) {
builder.setSpan(STRIKETHROUGH_SPAN, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.isUnderline()) {
builder.setSpan(UNDERLINE_SPAN, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasColorSpecified()) {
builder.setSpan(new ForegroundColorSpan(style.getColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasBackgroundColorSpecified()) {
builder.setSpan(new BackgroundColorSpan(style.getBackgroundColor()), start, end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontFamily() != null) {
builder.setSpan(new TypefaceSpan(style.getFontFamily()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextAlign() != null) {
builder.setSpan(new AlignmentSpan.Standard(style.getTextAlign()), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
/**
* Invoked when the end of a paragraph is encountered. Adds a newline if there are one or more
* non-space characters since the previous newline.
*
* @param builder The builder.
*/
/* package */ static void endParagraph(SpannableStringBuilder builder) {
int position = builder.length() - 1;
while (position >= 0 && builder.charAt(position) == ' ') {
position--;
}
if (position >= 0 && builder.charAt(position) != '\n') {
builder.append('\n');
}
}
/**
* Applies the appropriate space policy to the given text element.
*
* @param in The text element to which the policy should be applied.
* @return The result of applying the policy to the text element.
*/
/* package */ static String applyTextElementSpacePolicy(String in) {
// Removes carriage return followed by line feed. See: http://www.w3.org/TR/xml/#sec-line-ends
String out = in.replaceAll("\r\n", "\n");
// Apply suppress-at-line-break="auto" and
// white-space-treatment="ignore-if-surrounding-linefeed"
out = out.replaceAll(" *\n *", "\n");
// Apply linefeed-treatment="treat-as-space"
out = out.replaceAll("\n", " ");
// Apply white-space-collapse="true"
out = out.replaceAll("[ \t\\x0B\f\r]+", " ");
return out;
}
private TtmlRenderUtil() {}
}
......@@ -21,6 +21,7 @@ import com.google.android.exoplayer.util.Util;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A representation of a TTML subtitle.
......@@ -29,9 +30,12 @@ public final class TtmlSubtitle implements Subtitle {
private final TtmlNode root;
private final long[] eventTimesUs;
private final Map<String, TtmlStyle> globalStyles;
public TtmlSubtitle(TtmlNode root) {
public TtmlSubtitle(TtmlNode root, Map<String, TtmlStyle> globalStyles) {
this.root = root;
this.globalStyles = globalStyles != null
? Collections.unmodifiableMap(globalStyles) : Collections.<String, TtmlStyle>emptyMap();
this.eventTimesUs = root.getEventTimesUs();
}
......@@ -63,7 +67,7 @@ public final class TtmlSubtitle implements Subtitle {
@Override
public List<Cue> getCues(long timeUs) {
CharSequence cueText = root.getText(timeUs);
CharSequence cueText = root.getText(timeUs, globalStyles);
if (cueText == null) {
return Collections.<Cue>emptyList();
} else {
......@@ -72,4 +76,8 @@ public final class TtmlSubtitle implements Subtitle {
}
}
/* @VisibleForTesting */
/* package */ Map<String, TtmlStyle> getGlobalStyles() {
return globalStyles;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment