mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
Remove TTML package from null-checking blacklist
PiperOrigin-RevId: 290629644
This commit is contained in:
parent
8a2a527129
commit
37908dd4df
4 changed files with 123 additions and 84 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue