Search in sources :

Example 6 with RubySpan

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);
}
Also used : SpannableString(android.text.SpannableString) RubySpan(com.google.android.exoplayer2.text.span.RubySpan) Test(org.junit.Test)

Example 7 with RubySpan

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;
    }
}
Also used : RubySpan(com.google.android.exoplayer2.text.span.RubySpan) ForegroundColorSpan(android.text.style.ForegroundColorSpan) TextEmphasisSpan(com.google.android.exoplayer2.text.span.TextEmphasisSpan) RelativeSizeSpan(android.text.style.RelativeSizeSpan) UnderlineSpan(android.text.style.UnderlineSpan) AbsoluteSizeSpan(android.text.style.AbsoluteSizeSpan) HorizontalTextInVerticalContextSpan(com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan) StyleSpan(android.text.style.StyleSpan) BackgroundColorSpan(android.text.style.BackgroundColorSpan) Nullable(androidx.annotation.Nullable) StrikethroughSpan(android.text.style.StrikethroughSpan) TypefaceSpan(android.text.style.TypefaceSpan)

Example 8 with RubySpan

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;
    }
}
Also used : RubySpan(com.google.android.exoplayer2.text.span.RubySpan) ArrayList(java.util.ArrayList)

Example 9 with RubySpan

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'");
}
Also used : SpannableString(android.text.SpannableString) RubySpan(com.google.android.exoplayer2.text.span.RubySpan) Test(org.junit.Test)

Example 10 with RubySpan

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());
}
Also used : RubySpan(com.google.android.exoplayer2.text.span.RubySpan) Cue(com.google.android.exoplayer2.text.Cue) HorizontalTextInVerticalContextSpan(com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan) TextEmphasisSpan(com.google.android.exoplayer2.text.span.TextEmphasisSpan) Spanned(android.text.Spanned) Test(org.junit.Test)

Aggregations

RubySpan (com.google.android.exoplayer2.text.span.RubySpan)11 Test (org.junit.Test)7 SpannableString (android.text.SpannableString)6 HorizontalTextInVerticalContextSpan (com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan)5 TextEmphasisSpan (com.google.android.exoplayer2.text.span.TextEmphasisSpan)5 UnderlineSpan (android.text.style.UnderlineSpan)4 AbsoluteSizeSpan (android.text.style.AbsoluteSizeSpan)3 RelativeSizeSpan (android.text.style.RelativeSizeSpan)3 Cue (com.google.android.exoplayer2.text.Cue)3 Spanned (android.text.Spanned)2 BackgroundColorSpan (android.text.style.BackgroundColorSpan)2 ForegroundColorSpan (android.text.style.ForegroundColorSpan)2 StrikethroughSpan (android.text.style.StrikethroughSpan)2 StyleSpan (android.text.style.StyleSpan)2 TypefaceSpan (android.text.style.TypefaceSpan)2 Nullable (androidx.annotation.Nullable)2 ArrayList (java.util.ArrayList)1