Parse TTML's tts:textAlign into Cue.textAlign, not an AlignmentSpan
The tts:textAlign property only applies to <p> elements, which correspond 1:1 with ExoPlayer Cue objects, so we can use Cue.textAlignment to store this info instead of encoding it in the span-styled text. This will mean that TTML subtitles used with SubtitleView#setApplyEmbeddedStyles(false) will start respecting the tts:textAlign properties from the source data (currently this information is stripped when we remove all span styling). I think this is working-as-intended, we respect alignment of other subtitle types (e.g. WebVTT) when applyEmbeddedStyles=false. We also respect all other 'positioning' related properties in this case e.g. Cue.position and Cue.line. PiperOrigin-RevId: 310895499
This commit is contained in:
parent
19d639eb9a
commit
0dd57de1f1
@ -380,7 +380,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
if (resolvedStyle != null) {
|
if (resolvedStyle != null) {
|
||||||
TtmlRenderUtil.applyStylesToSpan(text, start, end, resolvedStyle, parent);
|
TtmlRenderUtil.applyStylesToSpan(text, start, end, resolvedStyle, parent);
|
||||||
regionOutput.setVerticalType(resolvedStyle.getVerticalType());
|
regionOutput
|
||||||
|
.setTextAlignment(resolvedStyle.getTextAlign())
|
||||||
|
.setVerticalType(resolvedStyle.getVerticalType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.text.ttml;
|
package com.google.android.exoplayer2.text.ttml;
|
||||||
|
|
||||||
import android.text.Layout.Alignment;
|
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.style.AbsoluteSizeSpan;
|
import android.text.style.AbsoluteSizeSpan;
|
||||||
import android.text.style.AlignmentSpan;
|
|
||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.RelativeSizeSpan;
|
import android.text.style.RelativeSizeSpan;
|
||||||
@ -162,16 +160,6 @@ import java.util.Map;
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable Alignment textAlign = style.getTextAlign();
|
|
||||||
if (textAlign != null) {
|
|
||||||
SpanUtil.addOrReplaceSpan(
|
|
||||||
builder,
|
|
||||||
new AlignmentSpan.Standard(textAlign),
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
}
|
|
||||||
if (style.getTextCombine()) {
|
if (style.getTextCombine()) {
|
||||||
SpanUtil.addOrReplaceSpan(
|
SpanUtil.addOrReplaceSpan(
|
||||||
builder,
|
builder,
|
||||||
|
@ -60,6 +60,7 @@ public final class TtmlDecoderTest {
|
|||||||
private static final String BITMAP_REGION_FILE = "ttml/bitmap_percentage_region.xml";
|
private static final String BITMAP_REGION_FILE = "ttml/bitmap_percentage_region.xml";
|
||||||
private static final String BITMAP_PIXEL_REGION_FILE = "ttml/bitmap_pixel_region.xml";
|
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 BITMAP_UNSUPPORTED_REGION_FILE = "ttml/bitmap_unsupported_region.xml";
|
||||||
|
private static final String TEXT_ALIGN_FILE = "ttml/text_align.xml";
|
||||||
private static final String VERTICAL_TEXT_FILE = "ttml/vertical_text.xml";
|
private static final String VERTICAL_TEXT_FILE = "ttml/vertical_text.xml";
|
||||||
private static final String TEXT_COMBINE_FILE = "ttml/text_combine.xml";
|
private static final String TEXT_COMBINE_FILE = "ttml/text_combine.xml";
|
||||||
private static final String RUBIES_FILE = "ttml/rubies.xml";
|
private static final String RUBIES_FILE = "ttml/rubies.xml";
|
||||||
@ -194,9 +195,6 @@ public final class TtmlDecoderTest {
|
|||||||
assertThat(firstCueText)
|
assertThat(firstCueText)
|
||||||
.hasForegroundColorSpanBetween(0, firstCueText.length())
|
.hasForegroundColorSpanBetween(0, firstCueText.length())
|
||||||
.withColor(ColorParser.parseTtmlColor("lime"));
|
.withColor(ColorParser.parseTtmlColor("lime"));
|
||||||
assertThat(firstCueText)
|
|
||||||
.hasAlignmentSpanBetween(0, firstCueText.length())
|
|
||||||
.withAlignment(Layout.Alignment.ALIGN_CENTER);
|
|
||||||
|
|
||||||
Spanned secondCueText = getOnlyCueTextAtTimeUs(subtitle, 20_000_000);
|
Spanned secondCueText = getOnlyCueTextAtTimeUs(subtitle, 20_000_000);
|
||||||
assertThat(secondCueText.toString()).isEqualTo("text 2");
|
assertThat(secondCueText.toString()).isEqualTo("text 2");
|
||||||
@ -210,9 +208,6 @@ public final class TtmlDecoderTest {
|
|||||||
assertThat(secondCueText)
|
assertThat(secondCueText)
|
||||||
.hasForegroundColorSpanBetween(0, secondCueText.length())
|
.hasForegroundColorSpanBetween(0, secondCueText.length())
|
||||||
.withColor(0xFFFFFF00);
|
.withColor(0xFFFFFF00);
|
||||||
assertThat(secondCueText)
|
|
||||||
.hasAlignmentSpanBetween(0, secondCueText.length())
|
|
||||||
.withAlignment(Layout.Alignment.ALIGN_CENTER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -575,6 +570,39 @@ public final class TtmlDecoderTest {
|
|||||||
assertThat(cue.bitmapHeight).isEqualTo(Cue.DIMEN_UNSET);
|
assertThat(cue.bitmapHeight).isEqualTo(Cue.DIMEN_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void textAlign() throws IOException, SubtitleDecoderException {
|
||||||
|
TtmlSubtitle subtitle = getSubtitle(TEXT_ALIGN_FILE);
|
||||||
|
|
||||||
|
Cue firstCue = getOnlyCueAtTimeUs(subtitle, 10_000_000);
|
||||||
|
assertThat(firstCue.text.toString()).isEqualTo("Start alignment");
|
||||||
|
assertThat(firstCue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_NORMAL);
|
||||||
|
|
||||||
|
Cue secondCue = getOnlyCueAtTimeUs(subtitle, 20_000_000);
|
||||||
|
assertThat(secondCue.text.toString()).isEqualTo("Left alignment");
|
||||||
|
assertThat(secondCue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_NORMAL);
|
||||||
|
|
||||||
|
Cue thirdCue = getOnlyCueAtTimeUs(subtitle, 30_000_000);
|
||||||
|
assertThat(thirdCue.text.toString()).isEqualTo("Center alignment");
|
||||||
|
assertThat(thirdCue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_CENTER);
|
||||||
|
|
||||||
|
Cue fourthCue = getOnlyCueAtTimeUs(subtitle, 40_000_000);
|
||||||
|
assertThat(fourthCue.text.toString()).isEqualTo("Right alignment");
|
||||||
|
assertThat(fourthCue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_OPPOSITE);
|
||||||
|
|
||||||
|
Cue fifthCue = getOnlyCueAtTimeUs(subtitle, 50_000_000);
|
||||||
|
assertThat(fifthCue.text.toString()).isEqualTo("End alignment");
|
||||||
|
assertThat(fifthCue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_OPPOSITE);
|
||||||
|
|
||||||
|
Cue sixthCue = getOnlyCueAtTimeUs(subtitle, 60_000_000);
|
||||||
|
assertThat(sixthCue.text.toString()).isEqualTo("Justify alignment (unsupported)");
|
||||||
|
assertThat(sixthCue.textAlignment).isNull();
|
||||||
|
|
||||||
|
Cue seventhCue = getOnlyCueAtTimeUs(subtitle, 70_000_000);
|
||||||
|
assertThat(seventhCue.text.toString()).isEqualTo("No textAlign property");
|
||||||
|
assertThat(seventhCue.textAlignment).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void verticalText() throws IOException, SubtitleDecoderException {
|
public void verticalText() throws IOException, SubtitleDecoderException {
|
||||||
TtmlSubtitle subtitle = getSubtitle(VERTICAL_TEXT_FILE);
|
TtmlSubtitle subtitle = getSubtitle(VERTICAL_TEXT_FILE);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
tts:color="yellow"/>
|
tts:color="yellow"/>
|
||||||
</styling>
|
</styling>
|
||||||
</head>
|
</head>
|
||||||
<body tts:textAlign="center">
|
<body>
|
||||||
<div tts:fontWeight="normal"
|
<div tts:fontWeight="normal"
|
||||||
tts:fontStyle="normal"
|
tts:fontStyle="normal"
|
||||||
tts:fontFamily="sansSerif"
|
tts:fontFamily="sansSerif"
|
||||||
|
29
testdata/src/test/assets/ttml/text_align.xml
vendored
Normal file
29
testdata/src/test/assets/ttml/text_align.xml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<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" tts:textAlign="start">Start alignment</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="20s" end="28s" tts:textAlign="left">Left alignment</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="30s" end="38s" tts:textAlign="center">Center alignment</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="40s" end="48s" tts:textAlign="right">Right alignment</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="50s" end="58s" tts:textAlign="end">End alignment</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="60s" end="68s" tts:textAlign="justify">Justify alignment (unsupported)</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p begin="70s" end="78s">No textAlign property</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</tt>
|
Loading…
x
Reference in New Issue
Block a user