Skip to content

Commit 99b9779

Browse files
authored
* Impose positive length constraints on the data model to match the IMSC data model
* Fix WebVTT reader positioning algorithm * Fix SCC unit test that used non-existent row 0 #483 #487
1 parent aa3416d commit 99b9779

File tree

4 files changed

+329
-148
lines changed

4 files changed

+329
-148
lines changed

src/main/python/ttconv/style_properties.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ def __post_init__(self):
6969
if not isinstance(self.units, LengthType.Units):
7070
raise ValueError("Invalid units")
7171

72+
def is_non_negative(self):
73+
'''True if the length value is positive
74+
'''
75+
return self.value >= 0
76+
7277
@dataclass(frozen=True)
7378
class ColorType:
7479
'''<color> type as defined in TTML
@@ -541,7 +546,8 @@ def make_initial_value():
541546
def validate(value: ExtentType):
542547
return isinstance(value, ExtentType) \
543548
and value.width.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rw) \
544-
and value.height.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh)
549+
and value.height.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh) \
550+
and value.width.is_non_negative() and value.height.is_non_negative()
545551

546552

547553
class FillLineGap(StyleProperty):
@@ -586,7 +592,7 @@ def make_initial_value():
586592

587593
@staticmethod
588594
def validate(value):
589-
return isinstance(value, LengthType)
595+
return isinstance(value, LengthType) and value.is_non_negative()
590596

591597

592598
class FontStyle(StyleProperty):
@@ -631,7 +637,8 @@ def make_initial_value():
631637

632638
@staticmethod
633639
def validate(value):
634-
return value == SpecialValues.normal or (isinstance(value, LengthType) and value.units != LengthType.Units.c)
640+
return value == SpecialValues.normal or \
641+
(isinstance(value, LengthType) and value.units != LengthType.Units.c and value.is_non_negative())
635642

636643

637644
class LinePadding(StyleProperty):
@@ -647,8 +654,8 @@ def make_initial_value():
647654
@staticmethod
648655
def validate(value: LengthType):
649656
return isinstance(value, LengthType) and \
650-
value.units in (LengthType.Units.c, LengthType.Units.rh, LengthType.Units.rw)
651-
657+
value.units in (LengthType.Units.c, LengthType.Units.rh, LengthType.Units.rw) and \
658+
value.is_non_negative()
652659

653660
class LuminanceGain(StyleProperty):
654661
'''Corresponds to tts:luminanceGain.'''
@@ -662,8 +669,7 @@ def make_initial_value():
662669

663670
@staticmethod
664671
def validate(value: Numeric):
665-
return isinstance(value, numbers.Number)
666-
672+
return isinstance(value, numbers.Number) and value >= 0
667673

668674
class MultiRowAlign(StyleProperty):
669675
'''Corresponds to ebutts:multiRowAlign.'''
@@ -712,7 +718,8 @@ def make_initial_value():
712718
def validate(value: CoordinateType):
713719
return isinstance(value, CoordinateType) \
714720
and value.x.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rw) \
715-
and value.y.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh)
721+
and value.y.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh) \
722+
and value.x.is_non_negative() and value.y.is_non_negative()
716723

717724

718725
class Overflow(StyleProperty):
@@ -745,7 +752,8 @@ def validate(value):
745752
if not isinstance(value, PaddingType):
746753
return False
747754

748-
return LengthType.Units.c not in (value.before.units, value.end.units, value.after.units, value.start.units)
755+
return LengthType.Units.c not in (value.before.units, value.end.units, value.after.units, value.start.units) and \
756+
value.before.is_non_negative() and value.end.is_non_negative() and value.after.is_non_negative() and value.start.is_non_negative()
749757

750758
class Position(StyleProperty):
751759
'''Corresponds to tts:position.'''
@@ -764,7 +772,8 @@ def make_initial_value():
764772
def validate(value: PositionType):
765773
return isinstance(value, PositionType) \
766774
and value.h_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rw) \
767-
and value.v_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh)
775+
and value.v_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh) \
776+
and value.h_offset.is_non_negative() and value.v_offset.is_non_negative()
768777

769778
class RubyAlign(StyleProperty):
770779
'''Corresponds to tts:rubyAlign.'''
@@ -814,7 +823,7 @@ def validate(value):
814823
if not isinstance(value, RubyReserveType):
815824
return False
816825

817-
return value.length is None or value.length.units != LengthType.Units.c
826+
return value.length is None or (value.length.units != LengthType.Units.c and value.length.is_non_negative())
818827

819828
class Shear(StyleProperty):
820829
'''Corresponds to tts:shear.'''
@@ -828,7 +837,7 @@ def make_initial_value():
828837

829838
@staticmethod
830839
def validate(value: Numeric):
831-
return isinstance(value, numbers.Number)
840+
return isinstance(value, numbers.Number) and value >= -100.0 and value <= 100.0
832841

833842
class ShowBackground(StyleProperty):
834843
'''Corresponds to tts:showBackground.'''
@@ -931,7 +940,7 @@ def validate(value):
931940
if not isinstance(value, TextOutlineType):
932941
return False
933942

934-
return value.thickness.units != LengthType.Units.c
943+
return value.thickness.units != LengthType.Units.c and value.thickness.is_non_negative()
935944

936945

937946
class TextShadow(StyleProperty):
@@ -953,7 +962,7 @@ def validate(value):
953962
if not isinstance(value, TextShadowType):
954963
return False
955964

956-
return all(s.blur_radius is None or s.blur_radius.units != LengthType.Units.c for s in value.shadows)
965+
return len(value.shadows) <= 4 and all(s.blur_radius is None or s.blur_radius.units != LengthType.Units.c for s in value.shadows)
957966

958967

959968
class UnicodeBidi(StyleProperty):

0 commit comments

Comments
 (0)