Commit c11fda04 by aquilescanta Committed by Oliver Woodman

Add CSS Specificity score system to WebvttCssStyle

This CL provides the necessary infrastructure to add styling by class. This was separated
into two different CLs to ease reviewing.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120336976
parent 0fc53f6e
...@@ -178,6 +178,36 @@ public final class CssParserTest extends InstrumentationTestCase { ...@@ -178,6 +178,36 @@ public final class CssParserTest extends InstrumentationTestCase {
assertEquals(CssParser.parseNextToken(input, builder), null); assertEquals(CssParser.parseNextToken(input, builder), null);
} }
public void testStyleScoreSystem() {
WebvttCssStyle style = new WebvttCssStyle();
// Universal selector.
assertEquals(1, style.getSpecificityScore(null, null, new String[0], null));
// Class match without tag match.
style.setTargetClasses(new String[] { "class1", "class2"});
assertEquals(8, style.getSpecificityScore(null, null,
new String[] { "class1", "class2", "class3" }, null));
// Class and tag match
style.setTargetTagName("b");
assertEquals(10, style.getSpecificityScore(null, "b",
new String[] { "class1", "class2", "class3" }, null));
// Class insufficiency.
assertEquals(0, style.getSpecificityScore(null, "b", new String[] { "class1", "class" }, null));
// Voice, classes and tag match.
style.setTargetVoice("Manuel Cráneo");
assertEquals(14, style.getSpecificityScore(null, "b",
new String[] { "class1", "class2", "class3" }, "Manuel Cráneo"));
// Voice mismatch.
assertEquals(0, style.getSpecificityScore(null, "b",
new String[] { "class1", "class2", "class3" }, "Manuel Craneo"));
// Id, voice, classes and tag match.
style.setTargetId("id");
assertEquals(0x40000000 + 14, style.getSpecificityScore("id", "b",
new String[] { "class1", "class2", "class3" }, "Manuel Cráneo"));
// Id mismatch.
assertEquals(0, style.getSpecificityScore("id1", "b",
new String[] { "class1", "class2", "class3" }, null));
}
// Utility methods. // Utility methods.
private void assertSkipsToEndOfSkip(String expectedLine, String s) { private void assertSkipsToEndOfSkip(String expectedLine, String s) {
......
...@@ -20,6 +20,10 @@ import com.google.android.exoplayer.util.Util; ...@@ -20,6 +20,10 @@ import com.google.android.exoplayer.util.Util;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.text.Layout; import android.text.Layout;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/** /**
* Style object of a Css style block in a Webvtt file. * Style object of a Css style block in a Webvtt file.
* *
...@@ -42,6 +46,13 @@ import android.text.Layout; ...@@ -42,6 +46,13 @@ import android.text.Layout;
private static final int OFF = 0; private static final int OFF = 0;
private static final int ON = 1; private static final int ON = 1;
// Selector properties.
private String targetId;
private String targetTag;
private List<String> targetClasses;
private String targetVoice;
// Style properties.
private String fontFamily; private String fontFamily;
private int fontColor; private int fontColor;
private boolean hasFontColor; private boolean hasFontColor;
...@@ -60,6 +71,10 @@ import android.text.Layout; ...@@ -60,6 +71,10 @@ import android.text.Layout;
} }
public void reset() { public void reset() {
targetId = "";
targetTag = "";
targetClasses = Collections.emptyList();
targetVoice = "";
fontFamily = null; fontFamily = null;
hasFontColor = false; hasFontColor = false;
hasBackgroundColor = false; hasBackgroundColor = false;
...@@ -71,6 +86,59 @@ import android.text.Layout; ...@@ -71,6 +86,59 @@ import android.text.Layout;
textAlign = null; textAlign = null;
} }
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public void setTargetTagName(String targetTag) {
this.targetTag = targetTag;
}
public void setTargetClasses(String[] targetClasses) {
this.targetClasses = Arrays.asList(targetClasses);
}
public void setTargetVoice(String targetVoice) {
this.targetVoice = targetVoice;
}
/**
* Returns a value in a score system compliant with the CSS Specificity rules.
*
* @see <a href="https://www.w3.org/TR/CSS2/cascade.html">CSS Cascading</a>
*
* The score works as follows:
* <ul>
* <li> Id match adds 0x40000000 to the score.
* <li> Each class and voice match adds 4 to the score.
* <li> Tag matching adds 2 to the score.
* <li> Universal selector matching scores 1.
* </ul>
*
* @param id The id of the cue if present, {@code null} otherwise.
* @param tag Name of the tag, {@code null} if it refers to the entire cue.
* @param classes An array containing the classes the tag belongs to. Must not be null.
* @param voice Annotated voice if present, {@code null} otherwise.
* @return The score of the match, zero if there is no match.
*/
public int getSpecificityScore(String id, String tag, String[] classes, String voice) {
if (targetId.isEmpty() && targetTag.isEmpty() && targetClasses.isEmpty()
&& targetVoice.isEmpty()) {
// The selector is universal. It matches with the minimum score.
return 1;
}
int score = 0;
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)) {
return 0;
} else {
score += targetClasses.size() * 4;
}
return score;
}
/** /**
* Returns the style or {@link #UNSPECIFIED} when no style information is given. * Returns the style or {@link #UNSPECIFIED} when no style information is given.
* *
...@@ -214,5 +282,12 @@ import android.text.Layout; ...@@ -214,5 +282,12 @@ import android.text.Layout;
} }
} }
private static int updateScoreForMatch(int currentScore, String target, String actual,
int score) {
if (target.isEmpty() || currentScore == -1) {
return currentScore;
}
return target.equals(actual) ? currentScore + score : -1;
}
} }
...@@ -211,10 +211,10 @@ import java.util.regex.Pattern; ...@@ -211,10 +211,10 @@ import java.util.regex.Pattern;
} }
} }
// apply unclosed tags // apply unclosed tags
applyStyleToText(spannedText, styleMap.get(UNIVERSAL_CUE_ID), 0, spannedText.length());
while (!startTagStack.isEmpty()) { while (!startTagStack.isEmpty()) {
applySpansForTag(startTagStack.pop(), spannedText, styleMap); applySpansForTag(startTagStack.pop(), spannedText, styleMap);
} }
applyStyleToText(spannedText, styleMap.get(UNIVERSAL_CUE_ID), 0, spannedText.length());
applyStyleToText(spannedText, styleMap.get(CUE_ID_PREFIX + id), 0, spannedText.length()); applyStyleToText(spannedText, styleMap.get(CUE_ID_PREFIX + id), 0, spannedText.length());
builder.setText(spannedText); builder.setText(spannedText);
} }
......
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