Remove TTML package from null-checking blacklist

PiperOrigin-RevId: 290629644
This commit is contained in:
ibaker 2020-01-20 18:05:04 +00:00 committed by Ian Baker
parent 8a2a527129
commit 37908dd4df
4 changed files with 123 additions and 84 deletions

View file

@ -16,11 +16,13 @@
package com.google.android.exoplayer2.text.ttml;
import android.text.Layout;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.SimpleSubtitleDecoder;
import com.google.android.exoplayer2.text.Subtitle;
import com.google.android.exoplayer2.text.SubtitleDecoderException;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ColorParser;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
@ -32,6 +34,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.PolyNull;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
@ -110,18 +113,18 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
Map<String, TtmlStyle> globalStyles = new HashMap<>();
Map<String, TtmlRegion> regionMap = new HashMap<>();
Map<String, String> imageMap = new HashMap<>();
regionMap.put(TtmlNode.ANONYMOUS_REGION_ID, new TtmlRegion(null));
regionMap.put(TtmlNode.ANONYMOUS_REGION_ID, new TtmlRegion(TtmlNode.ANONYMOUS_REGION_ID));
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes, 0, length);
xmlParser.setInput(inputStream, null);
TtmlSubtitle ttmlSubtitle = null;
@Nullable TtmlSubtitle ttmlSubtitle = null;
ArrayDeque<TtmlNode> nodeStack = new ArrayDeque<>();
int unsupportedNodeDepth = 0;
int eventType = xmlParser.getEventType();
FrameAndTickRate frameAndTickRate = DEFAULT_FRAME_AND_TICK_RATE;
CellResolution cellResolution = DEFAULT_CELL_RESOLUTION;
TtsExtent ttsExtent = null;
@Nullable TtsExtent ttsExtent = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
TtmlNode parent = nodeStack.peek();
@Nullable TtmlNode parent = nodeStack.peek();
if (unsupportedNodeDepth == 0) {
String name = xmlParser.getName();
if (eventType == XmlPullParser.START_TAG) {
@ -149,10 +152,12 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
}
} else if (eventType == XmlPullParser.TEXT) {
parent.addChild(TtmlNode.buildTextNode(xmlParser.getText()));
Assertions.checkNotNull(parent).addChild(TtmlNode.buildTextNode(xmlParser.getText()));
} else if (eventType == XmlPullParser.END_TAG) {
if (xmlParser.getName().equals(TtmlNode.TAG_TT)) {
ttmlSubtitle = new TtmlSubtitle(nodeStack.peek(), globalStyles, regionMap, imageMap);
ttmlSubtitle =
new TtmlSubtitle(
Assertions.checkNotNull(nodeStack.peek()), globalStyles, regionMap, imageMap);
}
nodeStack.pop();
}
@ -166,7 +171,11 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
xmlParser.next();
eventType = xmlParser.getEventType();
}
return ttmlSubtitle;
if (ttmlSubtitle != null) {
return ttmlSubtitle;
} else {
throw new SubtitleDecoderException("No TTML subtitles found");
}
} catch (XmlPullParserException xppe) {
throw new SubtitleDecoderException("Unable to decode source", xppe);
} catch (IOException e) {
@ -221,8 +230,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return defaultValue;
}
try {
int columns = Integer.parseInt(cellResolutionMatcher.group(1));
int rows = Integer.parseInt(cellResolutionMatcher.group(2));
int columns = Integer.parseInt(Assertions.checkNotNull(cellResolutionMatcher.group(1)));
int rows = Integer.parseInt(Assertions.checkNotNull(cellResolutionMatcher.group(2)));
if (columns == 0 || rows == 0) {
throw new SubtitleDecoderException("Invalid cell resolution " + columns + " " + rows);
}
@ -233,7 +242,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
}
@Nullable
private TtsExtent parseTtsExtent(XmlPullParser xmlParser) {
@Nullable
String ttsExtent = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_EXTENT);
if (ttsExtent == null) {
return null;
@ -245,8 +256,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return null;
}
try {
int width = Integer.parseInt(extentMatcher.group(1));
int height = Integer.parseInt(extentMatcher.group(2));
int width = Integer.parseInt(Assertions.checkNotNull(extentMatcher.group(1)));
int height = Integer.parseInt(Assertions.checkNotNull(extentMatcher.group(2)));
return new TtsExtent(width, height);
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring malformed tts extent: " + ttsExtent);
@ -258,24 +269,26 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
XmlPullParser xmlParser,
Map<String, TtmlStyle> globalStyles,
CellResolution cellResolution,
TtsExtent ttsExtent,
@Nullable TtsExtent ttsExtent,
Map<String, TtmlRegion> globalRegions,
Map<String, String> imageMap)
throws IOException, XmlPullParserException {
do {
xmlParser.next();
if (XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_STYLE)) {
String parentStyleId = XmlPullParserUtil.getAttributeValue(xmlParser, ATTR_STYLE);
@Nullable String parentStyleId = XmlPullParserUtil.getAttributeValue(xmlParser, ATTR_STYLE);
TtmlStyle style = parseStyleAttributes(xmlParser, new TtmlStyle());
if (parentStyleId != null) {
for (String id : parseStyleIds(parentStyleId)) {
style.chain(globalStyles.get(id));
}
}
if (style.getId() != null) {
globalStyles.put(style.getId(), style);
String styleId = style.getId();
if (styleId != null) {
globalStyles.put(styleId, style);
}
} else if (XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_REGION)) {
@Nullable
TtmlRegion ttmlRegion = parseRegionAttributes(xmlParser, cellResolution, ttsExtent);
if (ttmlRegion != null) {
globalRegions.put(ttmlRegion.id, ttmlRegion);
@ -292,7 +305,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
do {
xmlParser.next();
if (XmlPullParserUtil.isStartTag(xmlParser, TtmlNode.TAG_IMAGE)) {
String id = XmlPullParserUtil.getAttributeValue(xmlParser, "id");
@Nullable String id = XmlPullParserUtil.getAttributeValue(xmlParser, "id");
if (id != null) {
String encodedBitmapData = xmlParser.nextText();
imageMap.put(id, encodedBitmapData);
@ -309,9 +322,10 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
* fractions. In case of missing tts:extent the pixel defined regions can't be parsed, and null is
* returned.
*/
@Nullable
private TtmlRegion parseRegionAttributes(
XmlPullParser xmlParser, CellResolution cellResolution, TtsExtent ttsExtent) {
String regionId = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_ID);
XmlPullParser xmlParser, CellResolution cellResolution, @Nullable TtsExtent ttsExtent) {
@Nullable String regionId = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_ID);
if (regionId == null) {
return null;
}
@ -319,14 +333,16 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
float position;
float line;
@Nullable
String regionOrigin = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_ORIGIN);
if (regionOrigin != null) {
Matcher originPercentageMatcher = PERCENTAGE_COORDINATES.matcher(regionOrigin);
Matcher originPixelMatcher = PIXEL_COORDINATES.matcher(regionOrigin);
if (originPercentageMatcher.matches()) {
try {
position = Float.parseFloat(originPercentageMatcher.group(1)) / 100f;
line = Float.parseFloat(originPercentageMatcher.group(2)) / 100f;
position =
Float.parseFloat(Assertions.checkNotNull(originPercentageMatcher.group(1))) / 100f;
line = Float.parseFloat(Assertions.checkNotNull(originPercentageMatcher.group(2))) / 100f;
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring region with malformed origin: " + regionOrigin);
return null;
@ -337,8 +353,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return null;
}
try {
int width = Integer.parseInt(originPixelMatcher.group(1));
int height = Integer.parseInt(originPixelMatcher.group(2));
int width = Integer.parseInt(Assertions.checkNotNull(originPixelMatcher.group(1)));
int height = Integer.parseInt(Assertions.checkNotNull(originPixelMatcher.group(2)));
// Convert pixel values to fractions.
position = width / (float) ttsExtent.width;
line = height / (float) ttsExtent.height;
@ -362,14 +378,17 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
float width;
float height;
@Nullable
String regionExtent = XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_EXTENT);
if (regionExtent != null) {
Matcher extentPercentageMatcher = PERCENTAGE_COORDINATES.matcher(regionExtent);
Matcher extentPixelMatcher = PIXEL_COORDINATES.matcher(regionExtent);
if (extentPercentageMatcher.matches()) {
try {
width = Float.parseFloat(extentPercentageMatcher.group(1)) / 100f;
height = Float.parseFloat(extentPercentageMatcher.group(2)) / 100f;
width =
Float.parseFloat(Assertions.checkNotNull(extentPercentageMatcher.group(1))) / 100f;
height =
Float.parseFloat(Assertions.checkNotNull(extentPercentageMatcher.group(2))) / 100f;
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring region with malformed extent: " + regionOrigin);
return null;
@ -380,8 +399,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return null;
}
try {
int extentWidth = Integer.parseInt(extentPixelMatcher.group(1));
int extentHeight = Integer.parseInt(extentPixelMatcher.group(2));
int extentWidth = Integer.parseInt(Assertions.checkNotNull(extentPixelMatcher.group(1)));
int extentHeight = Integer.parseInt(Assertions.checkNotNull(extentPixelMatcher.group(2)));
// Convert pixel values to fractions.
width = extentWidth / (float) ttsExtent.width;
height = extentHeight / (float) ttsExtent.height;
@ -404,8 +423,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
@Cue.AnchorType int lineAnchor = Cue.ANCHOR_TYPE_START;
String displayAlign = XmlPullParserUtil.getAttributeValue(xmlParser,
TtmlNode.ATTR_TTS_DISPLAY_ALIGN);
@Nullable
String displayAlign =
XmlPullParserUtil.getAttributeValue(xmlParser, TtmlNode.ATTR_TTS_DISPLAY_ALIGN);
if (displayAlign != null) {
switch (Util.toLowerInvariant(displayAlign)) {
case "center":
@ -440,7 +460,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return parentStyleIds.isEmpty() ? new String[0] : Util.split(parentStyleIds, "\\s+");
}
private TtmlStyle parseStyleAttributes(XmlPullParser parser, TtmlStyle style) {
@PolyNull
private TtmlStyle parseStyleAttributes(XmlPullParser parser, @PolyNull TtmlStyle style) {
int attributeCount = parser.getAttributeCount();
for (int i = 0; i < attributeCount; i++) {
String attributeValue = parser.getAttributeValue(i);
@ -527,21 +548,24 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
return style;
}
private TtmlStyle createIfNull(TtmlStyle style) {
private TtmlStyle createIfNull(@Nullable TtmlStyle style) {
return style == null ? new TtmlStyle() : style;
}
private TtmlNode parseNode(XmlPullParser parser, TtmlNode parent,
Map<String, TtmlRegion> regionMap, FrameAndTickRate frameAndTickRate)
private TtmlNode parseNode(
XmlPullParser parser,
@Nullable TtmlNode parent,
Map<String, TtmlRegion> regionMap,
FrameAndTickRate frameAndTickRate)
throws SubtitleDecoderException {
long duration = C.TIME_UNSET;
long startTime = C.TIME_UNSET;
long endTime = C.TIME_UNSET;
String regionId = TtmlNode.ANONYMOUS_REGION_ID;
String imageId = null;
String[] styleIds = null;
@Nullable String imageId = null;
@Nullable String[] styleIds = null;
int attributeCount = parser.getAttributeCount();
TtmlStyle style = parseStyleAttributes(parser, null);
@Nullable TtmlStyle style = parseStyleAttributes(parser, null);
for (int i = 0; i < attributeCount; i++) {
String attr = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
@ -636,7 +660,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
if (matcher.matches()) {
String unit = matcher.group(3);
String unit = Assertions.checkNotNull(matcher.group(3));
switch (unit) {
case "px":
out.setFontSizeUnit(TtmlStyle.FONT_SIZE_UNIT_PIXEL);
@ -650,7 +674,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
default:
throw new SubtitleDecoderException("Invalid unit for fontSize: '" + unit + "'.");
}
out.setFontSize(Float.valueOf(matcher.group(1)));
out.setFontSize(Float.parseFloat(Assertions.checkNotNull(matcher.group(1))));
} else {
throw new SubtitleDecoderException("Invalid expression for fontSize: '" + expression + "'.");
}
@ -671,18 +695,18 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
throws SubtitleDecoderException {
Matcher matcher = CLOCK_TIME.matcher(time);
if (matcher.matches()) {
String hours = matcher.group(1);
String hours = Assertions.checkNotNull(matcher.group(1));
double durationSeconds = Long.parseLong(hours) * 3600;
String minutes = matcher.group(2);
String minutes = Assertions.checkNotNull(matcher.group(2));
durationSeconds += Long.parseLong(minutes) * 60;
String seconds = matcher.group(3);
String seconds = Assertions.checkNotNull(matcher.group(3));
durationSeconds += Long.parseLong(seconds);
String fraction = matcher.group(4);
@Nullable String fraction = matcher.group(4);
durationSeconds += (fraction != null) ? Double.parseDouble(fraction) : 0;
String frames = matcher.group(5);
@Nullable String frames = matcher.group(5);
durationSeconds += (frames != null)
? Long.parseLong(frames) / frameAndTickRate.effectiveFrameRate : 0;
String subframes = matcher.group(6);
@Nullable String subframes = matcher.group(6);
durationSeconds += (subframes != null)
? ((double) Long.parseLong(subframes)) / frameAndTickRate.subFrameRate
/ frameAndTickRate.effectiveFrameRate
@ -691,9 +715,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
matcher = OFFSET_TIME.matcher(time);
if (matcher.matches()) {
String timeValue = matcher.group(1);
String timeValue = Assertions.checkNotNull(matcher.group(1));
double offsetSeconds = Double.parseDouble(timeValue);
String unit = matcher.group(2);
String unit = Assertions.checkNotNull(matcher.group(2));
switch (unit) {
case "h":
offsetSeconds *= 3600;

View file

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.TreeSet;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* A package internal representation of TTML node.
@ -93,7 +94,7 @@ import java.util.TreeSet;
private final HashMap<String, Integer> nodeStartsByRegion;
private final HashMap<String, Integer> nodeEndsByRegion;
private List<TtmlNode> children;
@MonotonicNonNull private List<TtmlNode> children;
public static TtmlNode buildTextNode(String text) {
return new TtmlNode(
@ -196,6 +197,7 @@ import java.util.TreeSet;
}
}
@Nullable
public String[] getStyleIds() {
return styleIds;
}
@ -217,7 +219,7 @@ import java.util.TreeSet;
// Create image based cues.
for (Pair<String, String> regionImagePair : regionImageOutputs) {
String encodedBitmapData = imageMap.get(regionImagePair.second);
@Nullable String encodedBitmapData = imageMap.get(regionImagePair.second);
if (encodedBitmapData == null) {
// Image reference points to an invalid image. Do nothing.
continue;
@ -225,7 +227,7 @@ import java.util.TreeSet;
byte[] bitmapData = Base64.decode(encodedBitmapData, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, /* offset= */ 0, bitmapData.length);
TtmlRegion region = regionMap.get(regionImagePair.first);
TtmlRegion region = Assertions.checkNotNull(regionMap.get(regionImagePair.first));
cues.add(
new Cue.Builder()
@ -241,7 +243,7 @@ import java.util.TreeSet;
// Create text based cues.
for (Entry<String, SpannableStringBuilder> entry : regionTextOutputs.entrySet()) {
TtmlRegion region = regionMap.get(entry.getKey());
TtmlRegion region = Assertions.checkNotNull(regionMap.get(entry.getKey()));
cues.add(
new Cue(
cleanUpText(entry.getValue()),
@ -286,7 +288,7 @@ import java.util.TreeSet;
String resolvedRegionId = ANONYMOUS_REGION_ID.equals(regionId) ? inheritedRegion : regionId;
if (isTextNode && descendsPNode) {
getRegionOutput(resolvedRegionId, regionOutputs).append(text);
getRegionOutput(resolvedRegionId, regionOutputs).append(Assertions.checkNotNull(text));
} else if (TAG_BR.equals(tag) && descendsPNode) {
getRegionOutput(resolvedRegionId, regionOutputs).append('\n');
} else if (isActive(timeUs)) {
@ -330,7 +332,7 @@ import java.util.TreeSet;
int start = nodeStartsByRegion.containsKey(regionId) ? nodeStartsByRegion.get(regionId) : 0;
int end = entry.getValue();
if (start != end) {
SpannableStringBuilder regionOutput = regionOutputs.get(regionId);
SpannableStringBuilder regionOutput = Assertions.checkNotNull(regionOutputs.get(regionId));
applyStyleToOutput(globalStyles, regionOutput, start, end);
}
}
@ -344,7 +346,7 @@ import java.util.TreeSet;
SpannableStringBuilder regionOutput,
int start,
int end) {
TtmlStyle resolvedStyle = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
@Nullable TtmlStyle resolvedStyle = TtmlRenderUtil.resolveStyle(style, styleIds, globalStyles);
if (resolvedStyle != null) {
TtmlRenderUtil.applyStylesToSpan(regionOutput, start, end, resolvedStyle);
}

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.text.ttml;
import android.text.Layout.Alignment;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
@ -26,6 +27,7 @@ import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.text.SpanUtil;
import java.util.Map;
@ -34,30 +36,35 @@ import java.util.Map;
*/
/* package */ final class TtmlRenderUtil {
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 (String id : styleIds) {
chainedStyle.chain(globalStyles.get(id));
@Nullable
public static TtmlStyle resolveStyle(
@Nullable TtmlStyle style, @Nullable String[] styleIds, Map<String, TtmlStyle> globalStyles) {
if (style == null) {
if (styleIds == null) {
// No styles at all.
return null;
} else if (styleIds.length == 1) {
// Only one single referential style present.
return globalStyles.get(styleIds[0]);
} else if (styleIds.length > 1) {
// Only multiple referential styles present.
TtmlStyle chainedStyle = new TtmlStyle();
for (String id : styleIds) {
chainedStyle.chain(globalStyles.get(id));
}
return chainedStyle;
}
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 (String id : styleIds) {
style.chain(globalStyles.get(id));
} else /* style != null */ {
if (styleIds != null && styleIds.length == 1) {
// Merge a single referential style into inline style.
return style.chain(globalStyles.get(styleIds[0]));
} else if (styleIds != null && styleIds.length > 1) {
// Merge multiple referential styles into inline style.
for (String id : styleIds) {
style.chain(globalStyles.get(id));
}
return style;
}
return style;
}
// Only inline styles available.
return style;
@ -100,10 +107,11 @@ import java.util.Map;
end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextAlign() != null) {
@Nullable Alignment textAlign = style.getTextAlign();
if (textAlign != null) {
SpanUtil.addOrReplaceSpan(
builder,
new AlignmentSpan.Standard(style.getTextAlign()),
new AlignmentSpan.Standard(textAlign),
start,
end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

View file

@ -18,9 +18,11 @@ package com.google.android.exoplayer2.text.ttml;
import android.graphics.Typeface;
import android.text.Layout;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* Style object of a <code>TtmlNode</code>
@ -58,7 +60,7 @@ import java.lang.annotation.RetentionPolicy;
private static final int OFF = 0;
private static final int ON = 1;
private String fontFamily;
private @MonotonicNonNull String fontFamily;
private int fontColor;
private boolean hasFontColor;
private int backgroundColor;
@ -69,8 +71,8 @@ import java.lang.annotation.RetentionPolicy;
@OptionalBoolean private int italic;
@FontSizeUnit private int fontSizeUnit;
private float fontSize;
private String id;
private Layout.Alignment textAlign;
private @MonotonicNonNull String id;
private Layout.@MonotonicNonNull Alignment textAlign;
public TtmlStyle() {
linethrough = UNSPECIFIED;
@ -122,6 +124,7 @@ import java.lang.annotation.RetentionPolicy;
return this;
}
@Nullable
public String getFontFamily() {
return fontFamily;
}
@ -171,7 +174,7 @@ import java.lang.annotation.RetentionPolicy;
*
* @param ancestor the referential style to inherit from
*/
public TtmlStyle chain(TtmlStyle ancestor) {
public TtmlStyle chain(@Nullable TtmlStyle ancestor) {
return inherit(ancestor, true);
}
@ -182,11 +185,11 @@ import java.lang.annotation.RetentionPolicy;
*
* @param ancestor the ancestor style to inherit from
*/
public TtmlStyle inherit(TtmlStyle ancestor) {
public TtmlStyle inherit(@Nullable TtmlStyle ancestor) {
return inherit(ancestor, false);
}
private TtmlStyle inherit(TtmlStyle ancestor, boolean chaining) {
private TtmlStyle inherit(@Nullable TtmlStyle ancestor, boolean chaining) {
if (ancestor != null) {
if (!hasFontColor && ancestor.hasFontColor) {
setFontColor(ancestor.fontColor);
@ -197,7 +200,7 @@ import java.lang.annotation.RetentionPolicy;
if (italic == UNSPECIFIED) {
italic = ancestor.italic;
}
if (fontFamily == null) {
if (fontFamily == null && ancestor.fontFamily != null) {
fontFamily = ancestor.fontFamily;
}
if (linethrough == UNSPECIFIED) {
@ -206,7 +209,7 @@ import java.lang.annotation.RetentionPolicy;
if (underline == UNSPECIFIED) {
underline = ancestor.underline;
}
if (textAlign == null) {
if (textAlign == null && ancestor.textAlign != null) {
textAlign = ancestor.textAlign;
}
if (fontSizeUnit == UNSPECIFIED) {
@ -226,10 +229,12 @@ import java.lang.annotation.RetentionPolicy;
return this;
}
@Nullable
public String getId() {
return id;
}
@Nullable
public Layout.Alignment getTextAlign() {
return textAlign;
}