Commit ab66dfa7 by Oliver Woodman

Parsing embedded TTML styling.

parent 95fcb3b4
<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:backgroundColor="blue"
tts:color="black"
tts:fontWeight="bold" />
<style id="s1"
tts:backgroundColor="black"
tts:color="red"
tts:fontFamily="sansSerif"
tts:fontStyle="italic"
tts:textDecoration="lineThrough" />
<!-- multiple ids defined -->
<style style="s0 s1" id="s2"
tts:fontFamily="serif"
tts:backgroundColor="red" />
</styling>
</head>
<body>
<div>
<p style="s2" begin="10s" end="18s">text 1</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">
<head>
<styling>
<style id="s0"
tts:fontWeight="bold"
tts:fontStyle="italic"
tts:fontFamily="serif"
tts:textDecoration="underline"
tts:backgroundColor="blue"
tts:color="yellow"/>
</styling>
</head>
<body>
<div>
<p style="s0" begin="10s" end="18s">text 1</p>
</div>
<div>
<p style="s0" begin="20s" end="28s"
tts:fontWeight="normal"
tts:fontFamily="sansSerif"
tts:backgroundColor="red"
tts:color="yellow"
>text 2</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">
<head>
<styling>
<style id="s0"
tts:fontWeight="bold"
tts:fontStyle="italic"
tts:fontFamily="serif"
tts:textDecoration="underline"
tts:backgroundColor="blue"
tts:color="yellow"/>
</styling>
</head>
<body tts:textAlign="center">
<div tts:fontWeight="normal"
tts:fontStyle="normal"
tts:fontFamily="sansSerif"
tts:textDecoration="lineThrough"
tts:backgroundColor="red"
tts:color="lime">
<p begin="10s" end="18s">text 1</p>
</div>
<div tts:fontWeight="normal"
tts:fontStyle="normal"
tts:fontFamily="sansSerif"
tts:textDecoration="lineThrough"
tts:backgroundColor="red"
tts:color="lime">
<p style="s0" begin="20s" end="28s">text 2</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:backgroundColor="blue"
tts:color="black"
tts:fontWeight="bold" />
<style id="s1"
tts:backgroundColor="black"
tts:color="red"
tts:fontFamily="sansSerif"
tts:fontStyle="italic"
tts:textDecoration="lineThrough" />
<style id="s2"
tts:backgroundColor="red" />
<style id="s3"
tts:backgroundColor="green"
tts:textDecoration="lineThrough" />
</styling>
</head>
<body>
<div>
<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>
</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>
</div>
<div>
<!-- empty style attribute -->
<p style=" " begin="40s" end="48s">text 1</p>
</div>
<div>
<p style="not_existing" begin="50s" end="58s">text 1</p>
</div>
<div>
<p style="not_existing s2" begin="60s" end="68s">text 1</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">
<head>
<styling>
<style id="s0"
tts:fontWeight="bold"
tts:fontStyle="italic"
tts:fontFamily="serif"
tts:textDecoration="underline"
tts:backgroundColor="blue"
tts:color="yellow"/>
</styling>
</head>
<body>
<div>
<p style="s0" begin="10s" end="18s">text 1</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">text 1</p>
</div>
<div tts:fontWeight="normal"
tts:fontStyle="italic"
tts:fontFamily="sansSerif"
tts:textDecoration="lineThrough"
tts:backgroundColor="cyan"
tts:color="lime">
<p begin="20s" end="28s">text 2</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: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:textDecoration="underline"/>
<style id="s1"
tts:textDecoration="lineThrough"/>
</styling>
</head>
<body>
<div>
<p style="s0" begin="10s" end="18s" tts:textDecoration="noUnderline">text 1</p>
</div>
<div>
<p style="s1" begin="20s" end="28s" tts:textDecoration="noLineThrough">text 1</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>
/*
* Copyright (C) 2014 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.graphics.Color;
import android.test.InstrumentationTestCase;
/**
* Unit test for {@link TtmlStyle}.
*/
public final class TtmlStyleTest extends InstrumentationTestCase {
private static final String FONT_FAMILY = "serif";
private static final String ID = "id";
public static final int FOREGROUND_COLOR = Color.WHITE;
public static final int BACKGROUND_COLOR = Color.BLACK;
private TtmlStyle style;
@Override
public void setUp() throws Exception {
super.setUp();
style = new TtmlStyle();
}
public void testInheritStyle() {
style.inherit(createAncestorStyle());
assertNull("id must not be inherited", style.getId());
assertTrue(style.isUnderline());
assertTrue(style.isLinethrough());
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle());
assertEquals(FONT_FAMILY, style.getFontFamily());
assertEquals(Color.WHITE, style.getColor());
assertFalse("do not inherit backgroundColor", style.hasBackgroundColorSpecified());
}
public void testChainStyle() {
style.chain(createAncestorStyle());
assertNull("id must not be inherited", style.getId());
assertTrue(style.isUnderline());
assertTrue(style.isLinethrough());
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle());
assertEquals(FONT_FAMILY, style.getFontFamily());
assertEquals(FOREGROUND_COLOR, style.getColor());
// do inherit backgroundColor when chaining
assertEquals("do not inherit backgroundColor when chaining",
BACKGROUND_COLOR, style.getBackgroundColor());
}
public void testGetInheritableStyle() {
// same instance as long as everything can be inherited
assertSame(style, style.getInheritableStyle());
style.inherit(createAncestorStyle());
assertSame(style, style.getInheritableStyle());
// after setting a property which is not inheritable
// we expect the inheritable style to be another instance
style.setBackgroundColor(0);
TtmlStyle inheritableStyle = style.getInheritableStyle();
assertNotSame(style, inheritableStyle);
// and subsequent call give always the same instance
assertSame(inheritableStyle, style.getInheritableStyle());
boolean exceptionThrown = false;
try {
// setting properties after calling getInheritableStyle gives an exception
style.setItalic(true);
} catch (IllegalStateException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
}
private TtmlStyle createAncestorStyle() {
TtmlStyle ancestor = new TtmlStyle();
ancestor.setId(ID);
ancestor.setItalic(true);
ancestor.setBold(true);
ancestor.setBackgroundColor(BACKGROUND_COLOR);
ancestor.setColor(FOREGROUND_COLOR);
ancestor.setLinethrough(true);
ancestor.setUnderline(true);
ancestor.setFontFamily(FONT_FAMILY);
return ancestor;
}
public void testStyle() {
assertEquals(TtmlStyle.UNSPECIFIED, style.getStyle());
style.setItalic(true);
assertEquals(TtmlStyle.STYLE_ITALIC, style.getStyle());
style.setBold(true);
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle());
style.setItalic(false);
assertEquals(TtmlStyle.STYLE_BOLD, style.getStyle());
style.setBold(false);
assertEquals(TtmlStyle.STYLE_NORMAL, style.getStyle());
}
public void testLinethrough() {
assertFalse(style.isLinethrough());
style.setLinethrough(true);
assertTrue(style.isLinethrough());
style.setLinethrough(false);
assertFalse(style.isLinethrough());
}
public void testUnderline() {
assertFalse(style.isUnderline());
style.setUnderline(true);
assertTrue(style.isUnderline());
style.setUnderline(false);
assertFalse(style.isUnderline());
}
public void testFontFamily() {
assertNull(style.getFontFamily());
style.setFontFamily(FONT_FAMILY);
assertEquals(FONT_FAMILY, style.getFontFamily());
style.setFontFamily(null);
assertNull(style.getFontFamily());
}
public void testColor() {
assertFalse(style.hasColorSpecified());
style.setColor(Color.BLACK);
assertEquals(Color.BLACK, style.getColor());
assertTrue(style.hasColorSpecified());
}
public void testBackgroundColor() {
assertFalse(style.hasBackgroundColorSpecified());
style.setBackgroundColor(Color.BLACK);
assertEquals(Color.BLACK, style.getBackgroundColor());
assertTrue(style.hasBackgroundColorSpecified());
}
public void testId() {
assertNull(style.getId());
style.setId(ID);
assertEquals(ID, style.getId());
style.setId(null);
assertNull(style.getId());
}
}
...@@ -15,7 +15,16 @@ ...@@ -15,7 +15,16 @@
*/ */
package com.google.android.exoplayer.text.ttml; package com.google.android.exoplayer.text.ttml;
import android.text.Spannable;
import android.text.SpannableStringBuilder; 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.ArrayList;
import java.util.Iterator; import java.util.Iterator;
...@@ -28,7 +37,6 @@ import java.util.TreeSet; ...@@ -28,7 +37,6 @@ import java.util.TreeSet;
/* package */ final class TtmlNode { /* package */ final class TtmlNode {
public static final long UNDEFINED_TIME = -1; public static final long UNDEFINED_TIME = -1;
public static final String TAG_TT = "tt"; public static final String TAG_TT = "tt";
public static final String TAG_HEAD = "head"; public static final String TAG_HEAD = "head";
public static final String TAG_BODY = "body"; public static final String TAG_BODY = "body";
...@@ -45,25 +53,51 @@ import java.util.TreeSet; ...@@ -45,25 +53,51 @@ import java.util.TreeSet;
public static final String TAG_SMPTE_DATA = "smpte:data"; public static final String TAG_SMPTE_DATA = "smpte:data";
public static final String TAG_SMPTE_INFORMATION = "smpte:information"; public static final String TAG_SMPTE_INFORMATION = "smpte:information";
public static final String ATTR_ID = "id";
public static final String ATTR_TTS_BACKGROUND_COLOR = "backgroundColor";
public static final String ATTR_TTS_FONT_STYLE = "fontStyle";
public static final String ATTR_TTS_FONT_SIZE = "fontSize";
public static final String ATTR_TTS_FONT_FAMILY = "fontFamily";
public static final String ATTR_TTS_FONT_WEIGHT = "fontWeight";
public static final String ATTR_TTS_COLOR = "color";
public static final String ATTR_TTS_TEXT_DECORATION = "textDecoration";
public static final String ATTR_TTS_TEXT_ALIGN = "textAlign";
public static final String LINETHROUGH = "linethrough";
public static final String NO_LINETHROUGH = "nolinethrough";
public static final String UNDERLINE = "underline";
public static final String NO_UNDERLINE = "nounderline";
public static final String ITALIC = "italic";
public static final String BOLD = "bold";
public static final String LEFT = "left";
public static final String CENTER = "center";
public static final String RIGHT = "right";
public static final String START = "start";
public static final String END = "end";
public final String tag; public final String tag;
public final String text; public final String text;
public final boolean isTextNode; public final boolean isTextNode;
public final long startTimeUs; public final long startTimeUs;
public final long endTimeUs; public final long endTimeUs;
public final TtmlStyle style;
private List<TtmlNode> children; private List<TtmlNode> children;
public static TtmlNode buildTextNode(String text) { public static TtmlNode buildTextNode(String text, TtmlStyle style) {
return new TtmlNode(null, applyTextElementSpacePolicy(text), UNDEFINED_TIME, UNDEFINED_TIME); return new TtmlNode(null, applyTextElementSpacePolicy(text), UNDEFINED_TIME,
UNDEFINED_TIME, style);
} }
public static TtmlNode buildNode(String tag, long startTimeUs, long endTimeUs) { public static TtmlNode buildNode(String tag, long startTimeUs, long endTimeUs, TtmlStyle style) {
return new TtmlNode(tag, null, startTimeUs, endTimeUs); return new TtmlNode(tag, null, startTimeUs, endTimeUs, style);
} }
private TtmlNode(String tag, String text, long startTimeUs, long endTimeUs) { private TtmlNode(String tag, String text, long startTimeUs, long endTimeUs, TtmlStyle style) {
this.tag = tag; this.tag = tag;
this.text = text; this.text = text;
this.style = style;
this.isTextNode = text != null; this.isTextNode = text != null;
this.startTimeUs = startTimeUs; this.startTimeUs = startTimeUs;
this.endTimeUs = endTimeUs; this.endTimeUs = endTimeUs;
...@@ -168,15 +202,18 @@ import java.util.TreeSet; ...@@ -168,15 +202,18 @@ import java.util.TreeSet;
// 4. Trim a trailing newline, if there is one. // 4. Trim a trailing newline, if there is one.
if (builderLength > 0 && builder.charAt(builderLength - 1) == '\n') { if (builderLength > 0 && builder.charAt(builderLength - 1) == '\n') {
builder.delete(builderLength - 1, builderLength); builder.delete(builderLength - 1, builderLength);
builderLength--; /*builderLength--;*/
} }
return builder.subSequence(0, builderLength);
return builder;
} }
private SpannableStringBuilder getText(long timeUs, SpannableStringBuilder builder, private SpannableStringBuilder getText(long timeUs, SpannableStringBuilder builder,
boolean descendsPNode) { boolean descendsPNode) {
if (isTextNode && descendsPNode) { if (isTextNode && descendsPNode) {
int start = builder.length();
builder.append(text); builder.append(text);
applyStylesToSpan(builder, start, builder.length(), style);
} else if (TAG_BR.equals(tag) && descendsPNode) { } else if (TAG_BR.equals(tag) && descendsPNode) {
builder.append('\n'); builder.append('\n');
} else if (TAG_METADATA.equals(tag)) { } else if (TAG_METADATA.equals(tag)) {
...@@ -193,6 +230,37 @@ import java.util.TreeSet; ...@@ -193,6 +230,37 @@ import java.util.TreeSet;
return builder; 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 * 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. * non-space characters since the previous newline.
......
/*
* 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 com.google.android.exoplayer.util.Assertions;
import android.graphics.Typeface;
import android.text.Layout;
/**
* Style object of a <code>TtmlNode</code>
*/
public final class TtmlStyle {
public static final short UNSPECIFIED = -1;
public static final short STYLE_NORMAL = Typeface.NORMAL;
public static final short STYLE_BOLD = Typeface.BOLD;
public static final short STYLE_ITALIC = Typeface.ITALIC;
public static final short STYLE_BOLD_ITALIC = Typeface.BOLD_ITALIC;
private static final short OFF = 0;
private static final short ON = 1;
private String fontFamily;
private int color;
private boolean colorSpecified;
private int backgroundColor;
private boolean backgroundColorSpecified;
private short linethrough = UNSPECIFIED;
private short underline = UNSPECIFIED;
private short bold = UNSPECIFIED;
private short italic = UNSPECIFIED;
private String id;
private TtmlStyle inheritableStyle;
private Layout.Alignment textAlign;
/**
* Returns the style or <code>UNSPECIFIED</code> when no style information is given.
*
* @return UNSPECIFIED, STYLE_NORMAL, STYLE_BOLD, STYLE_BOLD or STYLE_BOLD_ITALIC
*/
public short getStyle() {
if (bold == UNSPECIFIED && italic == UNSPECIFIED) {
return UNSPECIFIED;
}
short style = STYLE_NORMAL;
if (bold != UNSPECIFIED) {
style += bold;
}
if (italic != UNSPECIFIED){
style += italic;
}
return style;
}
public boolean isLinethrough() {
return linethrough == ON;
}
public TtmlStyle setLinethrough(boolean linethrough) {
Assertions.checkState(inheritableStyle == null);
this.linethrough = linethrough ? ON : OFF;
return this;
}
public boolean isUnderline() {
return underline == ON;
}
public TtmlStyle setUnderline(boolean underline) {
Assertions.checkState(inheritableStyle == null);
this.underline = underline ? ON : OFF;
return this;
}
public String getFontFamily() {
return fontFamily;
}
public TtmlStyle setFontFamily(String fontFamily) {
Assertions.checkState(inheritableStyle == null);
this.fontFamily = fontFamily;
return this;
}
public int getColor() {
return color;
}
public TtmlStyle setColor(int color) {
Assertions.checkState(inheritableStyle == null);
this.color = color;
colorSpecified = true;
return this;
}
public boolean hasColorSpecified() {
return colorSpecified;
}
public int getBackgroundColor() {
return backgroundColor;
}
public TtmlStyle setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
backgroundColorSpecified = true;
return this;
}
public boolean hasBackgroundColorSpecified() {
return backgroundColorSpecified;
}
public TtmlStyle setBold(boolean isBold) {
Assertions.checkState(inheritableStyle == null);
bold = isBold ? STYLE_BOLD : STYLE_NORMAL;
return this;
}
public TtmlStyle setItalic(boolean isItalic) {
Assertions.checkState(inheritableStyle == null);
italic = isItalic ? STYLE_ITALIC : STYLE_NORMAL;
return this;
}
public TtmlStyle getInheritableStyle() {
if (isFullyInheritable()) {
return this;
} else if (inheritableStyle == null) {
inheritableStyle = new TtmlStyle().inherit(this);
}
return inheritableStyle;
}
private boolean isFullyInheritable() {
return !backgroundColorSpecified;
}
/**
* Inherits from an ancestor style. Properties like <i>tts:backgroundColor</i> which
* are not inheritable are not inherited as well as properties which are already set locally
* are never overridden.
*
* @param ancestor the ancestor style to inherit from
*/
public TtmlStyle inherit(TtmlStyle ancestor) {
return inherit(ancestor, false);
}
/**
* Chains this style to referential style. Local properties which are already set
* are never overridden.
*
* @param ancestor the referential style to inherit from
*/
public TtmlStyle chain(TtmlStyle ancestor) {
return inherit(ancestor, true);
}
private TtmlStyle inherit(TtmlStyle ancestor, boolean chaining) {
if (ancestor != null) {
if (!colorSpecified && ancestor.colorSpecified) {
setColor(ancestor.color);
}
if (bold == UNSPECIFIED) {
bold = ancestor.bold;
}
if (italic == UNSPECIFIED) {
italic = ancestor.italic;
}
if (fontFamily == null) {
fontFamily = ancestor.fontFamily;
}
if (linethrough == UNSPECIFIED) {
linethrough = ancestor.linethrough;
}
if (underline == UNSPECIFIED) {
underline = ancestor.underline;
}
if (textAlign == null) {
textAlign = ancestor.textAlign;
}
// attributes not inherited as of http://www.w3.org/TR/ttml1/
if (chaining && !backgroundColorSpecified && ancestor.backgroundColorSpecified) {
setBackgroundColor(ancestor.backgroundColor);
}
}
return this;
}
public TtmlStyle setId(String id) {
this.id = id;
return this;
}
public String getId() {
return id;
}
public Layout.Alignment getTextAlign() {
return textAlign;
}
public TtmlStyle setTextAlign(Layout.Alignment textAlign) {
this.textAlign = textAlign;
return this;
}
}
...@@ -56,6 +56,11 @@ public final class TtmlSubtitle implements Subtitle { ...@@ -56,6 +56,11 @@ public final class TtmlSubtitle implements Subtitle {
return (eventTimesUs.length == 0 ? -1 : eventTimesUs[eventTimesUs.length - 1]); return (eventTimesUs.length == 0 ? -1 : eventTimesUs[eventTimesUs.length - 1]);
} }
/* @VisibleForTesting */
/* package */ TtmlNode getRoot() {
return root;
}
@Override @Override
public List<Cue> getCues(long timeUs) { public List<Cue> getCues(long timeUs) {
CharSequence cueText = root.getText(timeUs); CharSequence cueText = root.getText(timeUs);
......
/*
* Copyright (C) 2014 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.util;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
/**
* Parser utility functions.
*/
public final class ParserUtil {
private ParserUtil() {}
public static boolean isEndTag(XmlPullParser xpp, String name) throws XmlPullParserException {
return xpp.getEventType() == XmlPullParser.END_TAG && name.equals(xpp.getName());
}
public static boolean isStartTag(XmlPullParser xpp, String name)
throws XmlPullParserException {
return xpp.getEventType() == XmlPullParser.START_TAG && name.equals(xpp.getName());
}
public static boolean isStartTag(XmlPullParser xpp) throws XmlPullParserException {
return xpp.getEventType() == XmlPullParser.START_TAG;
}
/**
* Removes the namespace part ('^.*:') of the attributeName.
*
* @param attributeName the string to remove the namespace prefix from
* @return the name of the attribute without the prefix
*/
public static String removeNamespacePrefix(String attributeName) {
return attributeName.replaceFirst("^.*:", "");
}
}
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