Commit 64244039 by ibaker Committed by Oliver Woodman

Add tate-chu-yoko support to TtmlDecoder

PiperOrigin-RevId: 292161845
parent 6377e277
......@@ -19,6 +19,8 @@
later).
* Parse `text-combine-upright` CSS property (i.e. tate-chu-yoko) in WebVTT
subtitles (rendering is coming later).
* Parse `tts:combineText` property (i.e. tate-chu-yoko) in TTML subtitles
(rendering is coming later).
* DRM: Add support for attaching DRM sessions to clear content in the demo app.
* Downloads: Merge downloads in `SegmentDownloader` to improve overall download
speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
......
......@@ -524,6 +524,19 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
break;
}
break;
case TtmlNode.ATTR_TTS_TEXT_COMBINE:
switch (Util.toLowerInvariant(attributeValue)) {
case TtmlNode.COMBINE_NONE:
style = createIfNull(style).setTextCombine(false);
break;
case TtmlNode.COMBINE_ALL:
style = createIfNull(style).setTextCombine(true);
break;
default:
// ignore
break;
}
break;
case TtmlNode.ATTR_TTS_TEXT_DECORATION:
switch (Util.toLowerInvariant(attributeValue)) {
case TtmlNode.LINETHROUGH:
......
......@@ -66,6 +66,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public static final String ATTR_TTS_COLOR = "color";
public static final String ATTR_TTS_TEXT_DECORATION = "textDecoration";
public static final String ATTR_TTS_TEXT_ALIGN = "textAlign";
public static final String ATTR_TTS_TEXT_COMBINE = "textCombine";
public static final String ATTR_TTS_WRITING_MODE = "writingMode";
// Values for textDecoration
......@@ -83,6 +84,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
public static final String START = "start";
public static final String END = "end";
// Values for textCombine
public static final String COMBINE_NONE = "none";
public static final String COMBINE_ALL = "all";
// Values for writingMode
public static final String VERTICAL = "tb";
public static final String VERTICAL_LR = "tblr";
......
......@@ -29,6 +29,7 @@ import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.text.SpanUtil;
import com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan;
import java.util.Map;
/**
......@@ -116,6 +117,14 @@ import java.util.Map;
end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
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(
......
......@@ -75,6 +75,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private float fontSize;
private @MonotonicNonNull String id;
private Layout.@MonotonicNonNull Alignment textAlign;
@OptionalBoolean private int textCombine;
@Cue.VerticalType private int verticalType;
public TtmlStyle() {
......@@ -216,6 +217,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (textAlign == null && ancestor.textAlign != null) {
textAlign = ancestor.textAlign;
}
if (textCombine == UNSPECIFIED) {
textCombine = ancestor.textCombine;
}
if (fontSizeUnit == UNSPECIFIED) {
fontSizeUnit = ancestor.fontSizeUnit;
fontSize = ancestor.fontSize;
......@@ -251,6 +255,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return this;
}
/** Returns true if the source entity has {@code tts:textCombine=all}. */
public boolean getTextCombine() {
return textCombine == ON;
}
public TtmlStyle setTextCombine(boolean combine) {
this.textCombine = combine ? ON : OFF;
return this;
}
public TtmlStyle setFontSize(float fontSize) {
this.fontSize = fontSize;
return this;
......
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
-->
<tt xmlns:ttm="http://www.w3.org/2006/10/ttaf1#metadata"
xmlns:ttp="http://www.w3.org/2006/10/ttaf1#parameter"
xmlns:tts="http://www.w3.org/2006/10/ttaf1#style"
xmlns="http://www.w3.org/ns/ttml"
xmlns="http://www.w3.org/2006/10/ttaf1">
<body>
<div>
<p begin="10s" end="18s">Text with <span tts:textCombine="all">combined</span> section.</p>
</div>
<div>
<p begin="20s" end="28s">Text with <span tts:textCombine="none">un-combined</span> section.</p>
</div>
<div>
<p begin="30s" end="38s">"No textCombine"</p>
</div>
</body>
</tt>
......@@ -60,6 +60,7 @@ public final class TtmlDecoderTest {
private static final String BITMAP_PIXEL_REGION_FILE = "ttml/bitmap_pixel_region.xml";
private static final String BITMAP_UNSUPPORTED_REGION_FILE = "ttml/bitmap_unsupported_region.xml";
private static final String VERTICAL_TEXT_FILE = "ttml/vertical_text.xml";
private static final String TEXT_COMBINE_FILE = "ttml/text_combine.xml";
@Test
public void testInlineAttributes() throws IOException, SubtitleDecoderException {
......@@ -587,6 +588,24 @@ public final class TtmlDecoderTest {
assertThat(thirdCue.verticalType).isEqualTo(Cue.TYPE_UNSET);
}
@Test
public void testTextCombine() throws IOException, SubtitleDecoderException {
TtmlSubtitle subtitle = getSubtitle(TEXT_COMBINE_FILE);
Spanned firstCue = getOnlyCueTextAtTimeUs(subtitle, 10_000_000);
assertThat(firstCue)
.hasHorizontalTextInVerticalContextSpanBetween(
"text with ".length(), "text with combined".length());
Spanned secondCue = getOnlyCueTextAtTimeUs(subtitle, 20_000_000);
assertThat(secondCue)
.hasNoHorizontalTextInVerticalContextSpanBetween(
"text with ".length(), "text with un-combined".length());
Spanned thirdCue = getOnlyCueTextAtTimeUs(subtitle, 30_000_000);
assertThat(thirdCue).hasNoHorizontalTextInVerticalContextSpanBetween(0, thirdCue.length());
}
private static Spanned getOnlyCueTextAtTimeUs(Subtitle subtitle, long timeUs) {
Cue cue = getOnlyCueAtTimeUs(subtitle, timeUs);
assertThat(cue.text).isInstanceOf(Spanned.class);
......
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