Allow signed TTML region origins

The origin may be negative if the subtitle starts off-screen
but extends into the screen for example.

TTML1 defines `tts:origin` in terms of
[`length`](https://www.w3.org/TR/2018/REC-ttml1-20181108/#style-value-length),
which allows a prefix of `+`, `-` or nothing, and it's the
[same in TTML2](https://www.w3.org/TR/2018/REC-ttml2-20181108/#style-value-length).

PiperOrigin-RevId: 682379845
This commit is contained in:
tonihei 2024-10-04 10:56:12 -07:00 committed by Copybara-Service
parent af6ad43ca0
commit f7af58951d
5 changed files with 16 additions and 16 deletions

View File

@ -505,8 +505,8 @@ public final class DelegatingSubtitleDecoderTtmlParserTest {
Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000); Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(24f / 100f); assertThat(cue.position).isEqualTo(-24.2f / 100f);
assertThat(cue.line).isEqualTo(28f / 100f); assertThat(cue.line).isEqualTo(28.5f / 100f);
assertThat(cue.size).isEqualTo(51f / 100f); assertThat(cue.size).isEqualTo(51f / 100f);
assertThat(cue.bitmapHeight).isEqualTo(12f / 100f); assertThat(cue.bitmapHeight).isEqualTo(12f / 100f);
@ -521,8 +521,8 @@ public final class DelegatingSubtitleDecoderTtmlParserTest {
cue = getOnlyCueAtTimeUs(subtitle, 7_500_000); cue = getOnlyCueAtTimeUs(subtitle, 7_500_000);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(24f / 100f); assertThat(cue.position).isEqualTo(-24.2f / 100f);
assertThat(cue.line).isEqualTo(28f / 100f); assertThat(cue.line).isEqualTo(28.5f / 100f);
assertThat(cue.size).isEqualTo(51f / 100f); assertThat(cue.size).isEqualTo(51f / 100f);
assertThat(cue.bitmapHeight).isEqualTo(12f / 100f); assertThat(cue.bitmapHeight).isEqualTo(12f / 100f);
} }
@ -534,7 +534,7 @@ public final class DelegatingSubtitleDecoderTtmlParserTest {
Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000); Cue cue = getOnlyCueAtTimeUs(subtitle, 1_000_000);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(307f / 1280f); assertThat(cue.position).isEqualTo(-307f / 1280f);
assertThat(cue.line).isEqualTo(562f / 720f); assertThat(cue.line).isEqualTo(562f / 720f);
assertThat(cue.size).isEqualTo(653f / 1280f); assertThat(cue.size).isEqualTo(653f / 1280f);
assertThat(cue.bitmapHeight).isEqualTo(86f / 720f); assertThat(cue.bitmapHeight).isEqualTo(86f / 720f);

View File

@ -105,9 +105,9 @@ public final class TtmlParser implements SubtitleParser {
private static final Pattern FONT_SIZE = Pattern.compile("^(([0-9]*.)?[0-9]+)(px|em|%)$"); private static final Pattern FONT_SIZE = Pattern.compile("^(([0-9]*.)?[0-9]+)(px|em|%)$");
static final Pattern SIGNED_PERCENTAGE = Pattern.compile("^([-+]?\\d+\\.?\\d*?)%$"); static final Pattern SIGNED_PERCENTAGE = Pattern.compile("^([-+]?\\d+\\.?\\d*?)%$");
static final Pattern PERCENTAGE_COORDINATES = static final Pattern PERCENTAGE_COORDINATES =
Pattern.compile("^(\\d+\\.?\\d*?)% (\\d+\\.?\\d*?)%$"); Pattern.compile("^([-+]?\\d+\\.?\\d*?)% ([-+]?\\d+\\.?\\d*?)%$");
private static final Pattern PIXEL_COORDINATES = private static final Pattern PIXEL_COORDINATES =
Pattern.compile("^(\\d+\\.?\\d*?)px (\\d+\\.?\\d*?)px$"); Pattern.compile("^([-+]?\\d+\\.?\\d*?)px ([-+]?\\d+\\.?\\d*?)px$");
private static final Pattern CELL_RESOLUTION = Pattern.compile("^(\\d+) (\\d+)$"); private static final Pattern CELL_RESOLUTION = Pattern.compile("^(\\d+) (\\d+)$");
private static final int DEFAULT_FRAME_RATE = 30; private static final int DEFAULT_FRAME_RATE = 30;

View File

@ -693,8 +693,8 @@ public final class TtmlParserTest {
Cue cue = Iterables.getOnlyElement(allCues.get(0).cues); Cue cue = Iterables.getOnlyElement(allCues.get(0).cues);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(24f / 100f); assertThat(cue.position).isEqualTo(-24.2f / 100f);
assertThat(cue.line).isEqualTo(28f / 100f); assertThat(cue.line).isEqualTo(28.5f / 100f);
assertThat(cue.size).isEqualTo(51f / 100f); assertThat(cue.size).isEqualTo(51f / 100f);
assertThat(cue.bitmapHeight).isEqualTo(12f / 100f); assertThat(cue.bitmapHeight).isEqualTo(12f / 100f);
@ -713,8 +713,8 @@ public final class TtmlParserTest {
cue = Iterables.getOnlyElement(allCues.get(2).cues); cue = Iterables.getOnlyElement(allCues.get(2).cues);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(24f / 100f); assertThat(cue.position).isEqualTo(-24.2f / 100f);
assertThat(cue.line).isEqualTo(28f / 100f); assertThat(cue.line).isEqualTo(28.5f / 100f);
assertThat(cue.size).isEqualTo(51f / 100f); assertThat(cue.size).isEqualTo(51f / 100f);
assertThat(cue.bitmapHeight).isEqualTo(12f / 100f); assertThat(cue.bitmapHeight).isEqualTo(12f / 100f);
} }
@ -730,7 +730,7 @@ public final class TtmlParserTest {
Cue cue = Iterables.getOnlyElement(allCues.get(0).cues); Cue cue = Iterables.getOnlyElement(allCues.get(0).cues);
assertThat(cue.text).isNull(); assertThat(cue.text).isNull();
assertThat(cue.bitmap).isNotNull(); assertThat(cue.bitmap).isNotNull();
assertThat(cue.position).isEqualTo(307f / 1280f); assertThat(cue.position).isEqualTo(-307f / 1280f);
assertThat(cue.line).isEqualTo(562f / 720f); assertThat(cue.line).isEqualTo(562f / 720f);
assertThat(cue.size).isEqualTo(653f / 1280f); assertThat(cue.size).isEqualTo(653f / 1280f);
assertThat(cue.bitmapHeight).isEqualTo(86f / 720f); assertThat(cue.bitmapHeight).isEqualTo(86f / 720f);

View File

@ -14,8 +14,8 @@
<layout> <layout>
<region xml:id="region_0" tts:extent="51% 12%" tts:origin="24% 78%"/> <region xml:id="region_0" tts:extent="51% 12%" tts:origin="24% 78%"/>
<region xml:id="region_1" tts:extent="57% 6%" tts:origin="21% 85%"/> <region xml:id="region_1" tts:extent="57% 6%" tts:origin="21% 85%"/>
<region xml:id="region_2" tts:extent="51% 12%" tts:origin="24% 28%"/> <region xml:id="region_2" tts:extent="51% 12%" tts:origin="-24.2% 28.5%"/>
<region xml:id="region_3" tts:extent="57% 6%" tts:origin="21% 35%"/> <region xml:id="region_3" tts:extent="57% 6%" tts:origin="21% +35%"/>
</layout> </layout>
</head> </head>
<body> <body>

View File

@ -12,8 +12,8 @@
<style/> <style/>
</styling> </styling>
<layout> <layout>
<region xml:id="region_0" tts:extent="653px 86px" tts:origin="307px 562px"/> <region xml:id="region_0" tts:extent="653px 86px" tts:origin="-307px 562px"/>
<region xml:id="region_1" tts:extent="730px 43px" tts:origin="269px 612px"/> <region xml:id="region_1" tts:extent="730px 43px" tts:origin="269px +612px"/>
</layout> </layout>
</head> </head>
<body> <body>