use of com.google.android.exoplayer2.text.span.RubySpan in project ExoPlayer by google.
the class SpannedSubjectTest method noRubySpan_success.
@Test
public void noRubySpan_success() {
SpannableString spannable = createSpannableWithUnrelatedSpanAnd(new RubySpan("ruby text", TextAnnotation.POSITION_BEFORE));
assertThat(spannable).hasNoRubySpanBetween(UNRELATED_SPAN_START, UNRELATED_SPAN_END);
}
use of com.google.android.exoplayer2.text.span.RubySpan in project ExoPlayer by google.
the class TtmlRenderUtil method applyStylesToSpan.
public static void applyStylesToSpan(Spannable builder, int start, int end, TtmlStyle style, @Nullable TtmlNode parent, Map<String, TtmlStyle> globalStyles, @Cue.VerticalType int verticalType) {
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.hasFontColor()) {
SpanUtil.addOrReplaceSpan(builder, new ForegroundColorSpan(style.getFontColor()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.hasBackgroundColor()) {
SpanUtil.addOrReplaceSpan(builder, new BackgroundColorSpan(style.getBackgroundColor()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getFontFamily() != null) {
SpanUtil.addOrReplaceSpan(builder, new TypefaceSpan(style.getFontFamily()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.getTextEmphasis() != null) {
TextEmphasis textEmphasis = checkNotNull(style.getTextEmphasis());
@TextEmphasisSpan.MarkShape int markShape;
@TextEmphasisSpan.MarkFill int markFill;
if (textEmphasis.markShape == TextEmphasis.MARK_SHAPE_AUTO) {
// If a vertical writing mode applies, then 'auto' is equivalent to 'filled sesame';
// otherwise, it's equivalent to 'filled circle':
// https://www.w3.org/TR/ttml2/#style-value-emphasis-style
markShape = (verticalType == Cue.VERTICAL_TYPE_LR || verticalType == Cue.VERTICAL_TYPE_RL) ? TextEmphasisSpan.MARK_SHAPE_SESAME : TextEmphasisSpan.MARK_SHAPE_CIRCLE;
markFill = TextEmphasisSpan.MARK_FILL_FILLED;
} else {
markShape = textEmphasis.markShape;
markFill = textEmphasis.markFill;
}
@TextEmphasis.Position int position;
if (textEmphasis.position == TextEmphasis.POSITION_OUTSIDE) {
// 'outside' is not supported by TextEmphasisSpan, so treat it as 'before':
// https://www.w3.org/TR/ttml2/#style-value-annotation-position
position = TextAnnotation.POSITION_BEFORE;
} else {
position = textEmphasis.position;
}
SpanUtil.addOrReplaceSpan(builder, new TextEmphasisSpan(markShape, markFill, position), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
switch(style.getRubyType()) {
case TtmlStyle.RUBY_TYPE_BASE:
// look for the sibling RUBY_TEXT and add it as span between start & end.
@Nullable TtmlNode containerNode = findRubyContainerNode(parent, globalStyles);
if (containerNode == null) {
// No matching container node
break;
}
@Nullable TtmlNode textNode = findRubyTextNode(containerNode, globalStyles);
if (textNode == null) {
// no matching text node
break;
}
String rubyText;
if (textNode.getChildCount() == 1 && textNode.getChild(0).text != null) {
rubyText = Util.castNonNull(textNode.getChild(0).text);
} else {
Log.i(TAG, "Skipping rubyText node without exactly one text child.");
break;
}
@Nullable TtmlStyle textStyle = resolveStyle(textNode.style, textNode.getStyleIds(), globalStyles);
// Use position from ruby text node if defined.
@TextAnnotation.Position int rubyPosition = textStyle != null ? textStyle.getRubyPosition() : TextAnnotation.POSITION_UNKNOWN;
if (rubyPosition == TextAnnotation.POSITION_UNKNOWN) {
// If ruby position is not defined, use position info from container node.
@Nullable TtmlStyle containerStyle = resolveStyle(containerNode.style, containerNode.getStyleIds(), globalStyles);
rubyPosition = containerStyle != null ? containerStyle.getRubyPosition() : rubyPosition;
}
builder.setSpan(new RubySpan(rubyText, rubyPosition), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TtmlStyle.RUBY_TYPE_DELIMITER:
// fall through and delete the text.
case TtmlStyle.RUBY_TYPE_TEXT:
// We can't just remove the text directly from `builder` here because TtmlNode has fixed
// ideas of where every node starts and ends (nodeStartsByRegion and nodeEndsByRegion) so
// all these indices become invalid if we mutate the underlying string at this point.
// Instead we add a special span that's then handled in TtmlNode#cleanUpText.
builder.setSpan(new DeleteTextSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TtmlStyle.RUBY_TYPE_CONTAINER:
case TtmlStyle.UNSPECIFIED:
default:
// Do nothing
break;
}
if (style.getTextCombine()) {
SpanUtil.addOrReplaceSpan(builder, new HorizontalTextInVerticalContextSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
switch(style.getFontSizeUnit()) {
case TtmlStyle.FONT_SIZE_UNIT_PIXEL:
SpanUtil.addOrReplaceSpan(builder, new AbsoluteSizeSpan((int) style.getFontSize(), true), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TtmlStyle.FONT_SIZE_UNIT_EM:
SpanUtil.addOrReplaceSpan(builder, new RelativeSizeSpan(style.getFontSize()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TtmlStyle.FONT_SIZE_UNIT_PERCENT:
SpanUtil.addOrReplaceSpan(builder, new RelativeSizeSpan(style.getFontSize() / 100), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
break;
case TtmlStyle.UNSPECIFIED:
// Do nothing.
break;
}
}
use of com.google.android.exoplayer2.text.span.RubySpan in project ExoPlayer by google.
the class WebvttCueParser method applyRubySpans.
private static void applyRubySpans(SpannableStringBuilder text, @Nullable String cueId, StartTag startTag, List<Element> nestedElements, List<WebvttCssStyle> styles) {
@TextAnnotation.Position int rubyTagPosition = getRubyPosition(styles, cueId, startTag);
List<Element> sortedNestedElements = new ArrayList<>(nestedElements.size());
sortedNestedElements.addAll(nestedElements);
Collections.sort(sortedNestedElements, Element.BY_START_POSITION_ASC);
int deletedCharCount = 0;
int lastRubyTextEnd = startTag.position;
for (int i = 0; i < sortedNestedElements.size(); i++) {
if (!TAG_RUBY_TEXT.equals(sortedNestedElements.get(i).startTag.name)) {
continue;
}
Element rubyTextElement = sortedNestedElements.get(i);
// Use the <rt> element's ruby-position if set, otherwise the <ruby> element's and otherwise
// default to OVER.
@TextAnnotation.Position int rubyPosition = firstKnownRubyPosition(getRubyPosition(styles, cueId, rubyTextElement.startTag), rubyTagPosition, TextAnnotation.POSITION_BEFORE);
// Move the rubyText from spannedText into the RubySpan.
int adjustedRubyTextStart = rubyTextElement.startTag.position - deletedCharCount;
int adjustedRubyTextEnd = rubyTextElement.endPosition - deletedCharCount;
CharSequence rubyText = text.subSequence(adjustedRubyTextStart, adjustedRubyTextEnd);
text.delete(adjustedRubyTextStart, adjustedRubyTextEnd);
text.setSpan(new RubySpan(rubyText.toString(), rubyPosition), lastRubyTextEnd, adjustedRubyTextStart, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
deletedCharCount += rubyText.length();
// The ruby text has been deleted, so new-start == old-end.
lastRubyTextEnd = adjustedRubyTextStart;
}
}
use of com.google.android.exoplayer2.text.span.RubySpan in project ExoPlayer by google.
the class SpannedSubjectTest method rubySpan_wrongText.
@Test
public void rubySpan_wrongText() {
SpannableString spannable = createSpannable(new RubySpan("ruby text", TextAnnotation.POSITION_BEFORE));
AssertionError expected = expectFailure(whenTesting -> whenTesting.that(spannable).hasRubySpanBetween(SPAN_START, SPAN_END).withTextAndPosition("incorrect text", TextAnnotation.POSITION_BEFORE));
assertThat(expected).factValue("value of").contains("rubyTextAndPosition");
assertThat(expected).factValue("expected").contains("text='incorrect text'");
assertThat(expected).factValue("but was").contains("text='ruby text'");
}
use of com.google.android.exoplayer2.text.span.RubySpan in project ExoPlayer by google.
the class SubtitleViewUtilsTest method testRemoveAllEmbeddedStyling.
@Test
public void testRemoveAllEmbeddedStyling() {
Cue.Builder cueBuilder = CUE.buildUpon();
SubtitleViewUtils.removeAllEmbeddedStyling(cueBuilder);
Cue strippedCue = cueBuilder.build();
Spanned originalText = (Spanned) CUE.text;
Spanned strippedText = (Spanned) strippedCue.text;
// Assert all non styling properties and spans are kept
assertThat(strippedCue.textAlignment).isEqualTo(CUE.textAlignment);
assertThat(strippedCue.multiRowAlignment).isEqualTo(CUE.multiRowAlignment);
assertThat(strippedCue.line).isEqualTo(CUE.line);
assertThat(strippedCue.lineType).isEqualTo(CUE.lineType);
assertThat(strippedCue.position).isEqualTo(CUE.position);
assertThat(strippedCue.positionAnchor).isEqualTo(CUE.positionAnchor);
assertThat(strippedCue.textSize).isEqualTo(Cue.DIMEN_UNSET);
assertThat(strippedCue.textSizeType).isEqualTo(Cue.TYPE_UNSET);
assertThat(strippedCue.size).isEqualTo(CUE.size);
assertThat(strippedCue.verticalType).isEqualTo(CUE.verticalType);
assertThat(strippedCue.shearDegrees).isEqualTo(CUE.shearDegrees);
TextEmphasisSpan expectedTextEmphasisSpan = originalText.getSpans(0, originalText.length(), TextEmphasisSpan.class)[0];
assertThat(strippedText).hasTextEmphasisSpanBetween(originalText.getSpanStart(expectedTextEmphasisSpan), originalText.getSpanEnd(expectedTextEmphasisSpan));
RubySpan expectedRubySpan = originalText.getSpans(0, originalText.length(), RubySpan.class)[0];
assertThat(strippedText).hasRubySpanBetween(originalText.getSpanStart(expectedRubySpan), originalText.getSpanEnd(expectedRubySpan));
HorizontalTextInVerticalContextSpan expectedHorizontalTextInVerticalContextSpan = originalText.getSpans(0, originalText.length(), HorizontalTextInVerticalContextSpan.class)[0];
assertThat(strippedText).hasHorizontalTextInVerticalContextSpanBetween(originalText.getSpanStart(expectedHorizontalTextInVerticalContextSpan), originalText.getSpanEnd(expectedHorizontalTextInVerticalContextSpan));
// Assert all styling properties and spans are removed
assertThat(strippedCue.windowColorSet).isFalse();
assertThat(strippedText).hasNoUnderlineSpanBetween(0, strippedText.length());
assertThat(strippedText).hasNoRelativeSizeSpanBetween(0, strippedText.length());
assertThat(strippedText).hasNoAbsoluteSizeSpanBetween(0, strippedText.length());
}
Aggregations