mirror of
https://github.com/samsonjs/media.git
synced 2026-04-15 12:55:46 +00:00
Cleanup WebvttCueParser and WebvttCssStyle
- Remove scratchStyleMatches output parameter from WebvttCueParser. - Switch from String[] to Set<String> for representing classes. - In-line WebvttCssStyle.reset() since it's not used anywhere else. PiperOrigin-RevId: 312249552
This commit is contained in:
parent
0de9c007af
commit
6e02a81501
3 changed files with 74 additions and 64 deletions
|
|
@ -27,8 +27,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Style object of a Css style block in a Webvtt file.
|
||||
|
|
@ -80,7 +80,7 @@ public final class WebvttCssStyle {
|
|||
// Selector properties.
|
||||
private String targetId;
|
||||
private String targetTag;
|
||||
private List<String> targetClasses;
|
||||
private Set<String> targetClasses;
|
||||
private String targetVoice;
|
||||
|
||||
// Style properties.
|
||||
|
|
@ -96,18 +96,10 @@ public final class WebvttCssStyle {
|
|||
@RubySpan.Position private int rubyPosition;
|
||||
private boolean combineUpright;
|
||||
|
||||
// Calling reset() is forbidden because `this` isn't initialized. This can be safely suppressed
|
||||
// because reset() only assigns fields, it doesn't read any.
|
||||
@SuppressWarnings("nullness:method.invocation.invalid")
|
||||
public WebvttCssStyle() {
|
||||
reset();
|
||||
}
|
||||
|
||||
@EnsuresNonNull({"targetId", "targetTag", "targetClasses", "targetVoice"})
|
||||
public void reset() {
|
||||
targetId = "";
|
||||
targetTag = "";
|
||||
targetClasses = Collections.emptyList();
|
||||
targetClasses = Collections.emptySet();
|
||||
targetVoice = "";
|
||||
fontFamily = null;
|
||||
hasFontColor = false;
|
||||
|
|
@ -129,7 +121,7 @@ public final class WebvttCssStyle {
|
|||
}
|
||||
|
||||
public void setTargetClasses(String[] targetClasses) {
|
||||
this.targetClasses = Arrays.asList(targetClasses);
|
||||
this.targetClasses = new HashSet<>(Arrays.asList(targetClasses));
|
||||
}
|
||||
|
||||
public void setTargetVoice(String targetVoice) {
|
||||
|
|
@ -155,7 +147,7 @@ public final class WebvttCssStyle {
|
|||
* @return The score of the match, zero if there is no match.
|
||||
*/
|
||||
public int getSpecificityScore(
|
||||
@Nullable String id, @Nullable String tag, String[] classes, @Nullable String voice) {
|
||||
@Nullable String id, @Nullable String tag, Set<String> classes, @Nullable String voice) {
|
||||
if (targetId.isEmpty() && targetTag.isEmpty() && targetClasses.isEmpty()
|
||||
&& targetVoice.isEmpty()) {
|
||||
// The selector is universal. It matches with the minimum score if and only if the given
|
||||
|
|
@ -166,7 +158,7 @@ public final class WebvttCssStyle {
|
|||
score = updateScoreForMatch(score, targetId, id, 0x40000000);
|
||||
score = updateScoreForMatch(score, targetTag, tag, 2);
|
||||
score = updateScoreForMatch(score, targetVoice, voice, 4);
|
||||
if (score == -1 || !Arrays.asList(classes).containsAll(targetClasses)) {
|
||||
if (score == -1 || !classes.containsAll(targetClasses)) {
|
||||
return 0;
|
||||
} else {
|
||||
score += targetClasses.size() * 4;
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
|
@ -239,7 +241,6 @@ public final class WebvttCueParser {
|
|||
@Nullable String id, String markup, List<WebvttCssStyle> styles) {
|
||||
SpannableStringBuilder spannedText = new SpannableStringBuilder();
|
||||
ArrayDeque<StartTag> startTagStack = new ArrayDeque<>();
|
||||
List<StyleMatch> scratchStyleMatches = new ArrayList<>();
|
||||
int pos = 0;
|
||||
List<Element> nestedElements = new ArrayList<>();
|
||||
while (pos < markup.length()) {
|
||||
|
|
@ -270,8 +271,7 @@ public final class WebvttCueParser {
|
|||
break;
|
||||
}
|
||||
startTag = startTagStack.pop();
|
||||
applySpansForTag(
|
||||
id, startTag, nestedElements, spannedText, styles, scratchStyleMatches);
|
||||
applySpansForTag(id, startTag, nestedElements, spannedText, styles);
|
||||
if (!startTagStack.isEmpty()) {
|
||||
nestedElements.add(new Element(startTag, spannedText.length()));
|
||||
} else {
|
||||
|
|
@ -307,16 +307,14 @@ public final class WebvttCueParser {
|
|||
}
|
||||
// apply unclosed tags
|
||||
while (!startTagStack.isEmpty()) {
|
||||
applySpansForTag(
|
||||
id, startTagStack.pop(), nestedElements, spannedText, styles, scratchStyleMatches);
|
||||
applySpansForTag(id, startTagStack.pop(), nestedElements, spannedText, styles);
|
||||
}
|
||||
applySpansForTag(
|
||||
id,
|
||||
StartTag.buildWholeCueVirtualTag(),
|
||||
/* nestedElements= */ Collections.emptyList(),
|
||||
spannedText,
|
||||
styles,
|
||||
scratchStyleMatches);
|
||||
styles);
|
||||
return SpannedString.valueOf(spannedText);
|
||||
}
|
||||
|
||||
|
|
@ -534,8 +532,7 @@ public final class WebvttCueParser {
|
|||
StartTag startTag,
|
||||
List<Element> nestedElements,
|
||||
SpannableStringBuilder text,
|
||||
List<WebvttCssStyle> styles,
|
||||
List<StyleMatch> scratchStyleMatches) {
|
||||
List<WebvttCssStyle> styles) {
|
||||
int start = startTag.position;
|
||||
int end = text.length();
|
||||
|
||||
|
|
@ -565,10 +562,9 @@ public final class WebvttCueParser {
|
|||
return;
|
||||
}
|
||||
|
||||
scratchStyleMatches.clear();
|
||||
getApplicableStyles(styles, cueId, startTag, scratchStyleMatches);
|
||||
for (int i = 0; i < scratchStyleMatches.size(); i++) {
|
||||
applyStyleToText(text, scratchStyleMatches.get(i).style, start, end);
|
||||
List<StyleMatch> applicableStyles = getApplicableStyles(styles, cueId, startTag);
|
||||
for (int i = 0; i < applicableStyles.size(); i++) {
|
||||
applyStyleToText(text, applicableStyles.get(i).style, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -616,8 +612,7 @@ public final class WebvttCueParser {
|
|||
@RubySpan.Position
|
||||
private static int getRubyPosition(
|
||||
List<WebvttCssStyle> styles, @Nullable String cueId, StartTag startTag) {
|
||||
List<StyleMatch> styleMatches = new ArrayList<>();
|
||||
getApplicableStyles(styles, cueId, startTag, styleMatches);
|
||||
List<StyleMatch> styleMatches = getApplicableStyles(styles, cueId, startTag);
|
||||
for (int i = 0; i < styleMatches.size(); i++) {
|
||||
WebvttCssStyle style = styleMatches.get(i).style;
|
||||
if (style.getRubyPosition() != RubySpan.POSITION_UNKNOWN) {
|
||||
|
|
@ -652,7 +647,7 @@ public final class WebvttCueParser {
|
|||
* colors</a>.
|
||||
*/
|
||||
private static void applyDefaultColors(
|
||||
SpannableStringBuilder text, String[] classes, int start, int end) {
|
||||
SpannableStringBuilder text, Set<String> classes, int start, int end) {
|
||||
for (String className : classes) {
|
||||
if (DEFAULT_TEXT_COLORS.containsKey(className)) {
|
||||
int color = DEFAULT_TEXT_COLORS.get(className);
|
||||
|
|
@ -746,20 +741,18 @@ public final class WebvttCueParser {
|
|||
return Util.splitAtFirst(tagExpression, "[ \\.]")[0];
|
||||
}
|
||||
|
||||
private static void getApplicableStyles(
|
||||
List<WebvttCssStyle> declaredStyles,
|
||||
@Nullable String id,
|
||||
StartTag tag,
|
||||
List<StyleMatch> output) {
|
||||
int styleCount = declaredStyles.size();
|
||||
for (int i = 0; i < styleCount; i++) {
|
||||
private static List<StyleMatch> getApplicableStyles(
|
||||
List<WebvttCssStyle> declaredStyles, @Nullable String id, StartTag tag) {
|
||||
List<StyleMatch> applicableStyles = new ArrayList<>();
|
||||
for (int i = 0; i < declaredStyles.size(); i++) {
|
||||
WebvttCssStyle style = declaredStyles.get(i);
|
||||
int score = style.getSpecificityScore(id, tag.name, tag.classes, tag.voice);
|
||||
if (score > 0) {
|
||||
output.add(new StyleMatch(score, style));
|
||||
applicableStyles.add(new StyleMatch(score, style));
|
||||
}
|
||||
}
|
||||
Collections.sort(output);
|
||||
Collections.sort(applicableStyles);
|
||||
return applicableStyles;
|
||||
}
|
||||
|
||||
private static final class WebvttCueInfoBuilder {
|
||||
|
|
@ -929,14 +922,12 @@ public final class WebvttCueParser {
|
|||
|
||||
private static final class StartTag {
|
||||
|
||||
private static final String[] NO_CLASSES = new String[0];
|
||||
|
||||
public final String name;
|
||||
public final int position;
|
||||
public final String voice;
|
||||
public final String[] classes;
|
||||
public final Set<String> classes;
|
||||
|
||||
private StartTag(String name, int position, String voice, String[] classes) {
|
||||
private StartTag(String name, int position, String voice, Set<String> classes) {
|
||||
this.position = position;
|
||||
this.name = name;
|
||||
this.voice = voice;
|
||||
|
|
@ -956,17 +947,19 @@ public final class WebvttCueParser {
|
|||
}
|
||||
String[] nameAndClasses = Util.split(fullTagExpression, "\\.");
|
||||
String name = nameAndClasses[0];
|
||||
String[] classes;
|
||||
if (nameAndClasses.length > 1) {
|
||||
classes = Util.nullSafeArrayCopyOfRange(nameAndClasses, 1, nameAndClasses.length);
|
||||
} else {
|
||||
classes = NO_CLASSES;
|
||||
Set<String> classes = new HashSet<>();
|
||||
for (int i = 1; i < nameAndClasses.length; i++) {
|
||||
classes.add(nameAndClasses[i]);
|
||||
}
|
||||
return new StartTag(name, position, voice, classes);
|
||||
}
|
||||
|
||||
public static StartTag buildWholeCueVirtualTag() {
|
||||
return new StartTag("", 0, "", new String[0]);
|
||||
return new StartTag(
|
||||
/* name= */ "",
|
||||
/* position= */ 0,
|
||||
/* voice= */ "",
|
||||
/* classes= */ Collections.emptySet());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ import static com.google.common.truth.Truth.assertThat;
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -163,32 +166,54 @@ public final class CssParserTest {
|
|||
public void styleScoreSystem() {
|
||||
WebvttCssStyle style = new WebvttCssStyle();
|
||||
// Universal selector.
|
||||
assertThat(style.getSpecificityScore("", "", new String[0], "")).isEqualTo(1);
|
||||
assertThat(style.getSpecificityScore("", "", Collections.emptySet(), "")).isEqualTo(1);
|
||||
// Class match without tag match.
|
||||
style.setTargetClasses(new String[] { "class1", "class2"});
|
||||
assertThat(style.getSpecificityScore("", "", new String[]{"class1", "class2", "class3"},
|
||||
"")).isEqualTo(8);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
"", "", new HashSet<>(Arrays.asList("class1", "class2", "class3")), ""))
|
||||
.isEqualTo(8);
|
||||
// Class and tag match
|
||||
style.setTargetTagName("b");
|
||||
assertThat(style.getSpecificityScore("", "b",
|
||||
new String[]{"class1", "class2", "class3"}, "")).isEqualTo(10);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
"", "b", new HashSet<>(Arrays.asList("class1", "class2", "class3")), ""))
|
||||
.isEqualTo(10);
|
||||
// Class insufficiency.
|
||||
assertThat(style.getSpecificityScore("", "b", new String[]{"class1", "class"}, ""))
|
||||
assertThat(
|
||||
style.getSpecificityScore("", "b", new HashSet<>(Arrays.asList("class1", "class")), ""))
|
||||
.isEqualTo(0);
|
||||
// Voice, classes and tag match.
|
||||
style.setTargetVoice("Manuel Cráneo");
|
||||
assertThat(style.getSpecificityScore("", "b",
|
||||
new String[]{"class1", "class2", "class3"}, "Manuel Cráneo")).isEqualTo(14);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
"",
|
||||
"b",
|
||||
new HashSet<>(Arrays.asList("class1", "class2", "class3")),
|
||||
"Manuel Cráneo"))
|
||||
.isEqualTo(14);
|
||||
// Voice mismatch.
|
||||
assertThat(style.getSpecificityScore(null, "b",
|
||||
new String[]{"class1", "class2", "class3"}, "Manuel Craneo")).isEqualTo(0);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
null,
|
||||
"b",
|
||||
new HashSet<>(Arrays.asList("class1", "class2", "class3")),
|
||||
"Manuel Craneo"))
|
||||
.isEqualTo(0);
|
||||
// Id, voice, classes and tag match.
|
||||
style.setTargetId("id");
|
||||
assertThat(style.getSpecificityScore("id", "b",
|
||||
new String[]{"class1", "class2", "class3"}, "Manuel Cráneo")).isEqualTo(0x40000000 + 14);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
"id",
|
||||
"b",
|
||||
new HashSet<>(Arrays.asList("class1", "class2", "class3")),
|
||||
"Manuel Cráneo"))
|
||||
.isEqualTo(0x40000000 + 14);
|
||||
// Id mismatch.
|
||||
assertThat(style.getSpecificityScore("id1", "b",
|
||||
new String[]{"class1", "class2", "class3"}, "")).isEqualTo(0);
|
||||
assertThat(
|
||||
style.getSpecificityScore(
|
||||
"id1", "b", new HashSet<>(Arrays.asList("class1", "class2", "class3")), ""))
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
// Utility methods.
|
||||
|
|
|
|||
Loading…
Reference in a new issue