Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/main/python/ttconv/imsc/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,9 @@ def from_xml(
model_prop, model_value = prop.to_model(style_ctx, xml_elem)
style_ctx.styles[model_prop] = model_value

except ValueError:
except ValueError as e:

LOGGER.error("Error reading style property: %s", prop.__name__)
LOGGER.error("Error reading style property %s with %s", prop.__name__, str(e))

# merge nested style attributes if the parent is a region element

Expand Down Expand Up @@ -683,9 +683,9 @@ def from_xml(

initial_ctx.doc.put_initial_value(model_prop, model_value)

except (ValueError, TypeError):
except (ValueError, TypeError) as e:

LOGGER.error("Error reading style property: %s", prop.__name__)
LOGGER.error("Error reading style property %s with %s", prop.__name__, str(e))

return initial_ctx

Expand Down Expand Up @@ -767,9 +767,9 @@ def process_specified_styling(self, xml_elem):

self.model_element.set_style(model_prop, model_value)

except ValueError:
except ValueError as e:

LOGGER.error("Error reading style property: %s", prop.__name__)
LOGGER.error("Error reading style property %s with %s", prop.__name__, str(e))

def process_set_style_properties(self, parent_ctx: ContentElement.ParsingContext, xml_elem):
'''Processes style properties on `<set>` element
Expand All @@ -796,8 +796,8 @@ def process_set_style_properties(self, parent_ctx: ContentElement.ParsingContext
)
)
break
except ValueError:
LOGGER.error("Error reading style property: %s", prop.__name__)
except ValueError as e:
LOGGER.error("Error reading style property %s with %s", prop.__name__, str(e))

def process_lang_attribute(self, parent_ctx: TTMLElement.ParsingContext, xml_elem):
super().process_lang_attribute(parent_ctx, xml_elem)
Expand Down
16 changes: 16 additions & 0 deletions src/main/python/ttconv/imsc/style_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,22 @@ def from_model(cls, xml_element, model_value: styles.FontStyleType):
xml_element.set(f"{{{cls.ns}}}{cls.local_name}", model_value.value)


class FontVariant(StyleProperty):
'''Corresponds to tts:fontVariant.'''

ns = xml_ns.TTS
local_name = "fontVariant"
model_prop = styles.StyleProperties.FontVariant

@classmethod
def extract(cls, context: StyleParsingContext, xml_attrib: str):
return styles.FontVariantType(xml_attrib)

@classmethod
def from_model(cls, xml_element, model_value: styles.FontVariantType):
xml_element.set(f"{{{cls.ns}}}{cls.local_name}", model_value.value)


class FontWeight(StyleProperty):
'''Corresponds to tts:fontWeight.'''

Expand Down
9 changes: 8 additions & 1 deletion src/main/python/ttconv/isd.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,11 @@ def get_region(self, region_id) -> typing.Optional[ISD.Region]:

def iter_regions(self) -> typing.Iterator[ISD.Region]:
'''Returns an iterator over regions.'''
return self._regions.values()
return iter(self._regions.values())

def __iter__(self) -> typing.Iterator[ISD.Region]:
'''Returns an iterator over the children of the element.'''
return iter(self.iter_regions())

def __len__(self) -> int:
'''Returns the number of regions of the ISD.'''
Expand Down Expand Up @@ -958,6 +962,9 @@ def compute(cls, parent: model.ContentElement, element: model.ContentElement):
class FontStyle(StyleProcessor):
style_prop = styles.StyleProperties.FontStyle

class FontVariant(StyleProcessor):
style_prop = styles.StyleProperties.FontVariant

class FontWeight(StyleProcessor):
style_prop = styles.StyleProperties.FontWeight

Expand Down
2 changes: 2 additions & 0 deletions src/main/python/ttconv/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ class P(ContentElement):
StyleProperties.FontFamily,
StyleProperties.FontSize,
StyleProperties.FontStyle,
StyleProperties.FontVariant,
StyleProperties.FontWeight,
StyleProperties.LineHeight,
StyleProperties.LinePadding,
Expand Down Expand Up @@ -525,6 +526,7 @@ class Span(ContentElement):
StyleProperties.FontFamily,
StyleProperties.FontSize,
StyleProperties.FontStyle,
StyleProperties.FontVariant,
StyleProperties.FontWeight,
StyleProperties.Opacity,
StyleProperties.TextCombine,
Expand Down
31 changes: 27 additions & 4 deletions src/main/python/ttconv/style_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ class FontStyleType(Enum):
oblique = "oblique"


class FontVariantType(Enum):
'''tts:fontVariant value
'''
normal = "normal"
superscript = "super"
subscript = "sub"


class FontWeightType(Enum):
'''tts:fontWeight value
'''
Expand Down Expand Up @@ -610,6 +618,21 @@ def validate(value):
return isinstance(value, FontStyleType)


class FontVariant(StyleProperty):
'''Corresponds to tts:fontVariant.'''

is_inherited = True
is_animatable = True

@staticmethod
def make_initial_value():
return FontVariantType.normal

@staticmethod
def validate(value):
return isinstance(value, FontVariantType)


class FontWeight(StyleProperty):
'''Corresponds to tts:fontWeight.'''

Expand Down Expand Up @@ -717,8 +740,8 @@ def make_initial_value():
@staticmethod
def validate(value: CoordinateType):
return isinstance(value, CoordinateType) \
and value.x.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rw) \
and value.y.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh) \
and value.x.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh, LengthType.Units.rw) \
and value.y.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh, LengthType.Units.rw) \
and value.x.is_non_negative() and value.y.is_non_negative()


Expand Down Expand Up @@ -771,8 +794,8 @@ def make_initial_value():
@staticmethod
def validate(value: PositionType):
return isinstance(value, PositionType) \
and value.h_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rw) \
and value.v_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh) \
and value.h_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh, LengthType.Units.rw) \
and value.v_offset.units in (LengthType.Units.pct, LengthType.Units.px, LengthType.Units.rh, LengthType.Units.rw) \
and value.h_offset.is_non_negative() and value.v_offset.is_non_negative()

class RubyAlign(StyleProperty):
Expand Down
12 changes: 12 additions & 0 deletions src/test/python/test_imsc11text_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,18 @@ def test_imsc_1_1_test_suite(self):
filt = IMSC11TextFilter()
filt.process(model)

def test_imsc_1_3_test_suite(self):
for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name):
tree = et.parse(os.path.join(root, filename))
model = imsc_reader.to_model(tree)
self.assertIsNotNone(model)
filt = IMSC11TextFilter()
with self.assertRaises(ValueError):
filt.process(model)

if __name__ == "__main__":
unittest.main()
9 changes: 9 additions & 0 deletions src/test/python/test_imsc_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ def test_imsc_1_1_test_suite(self):
tree = et.parse(os.path.join(root, filename))
self.assertIsNotNone(imsc_reader.to_model(tree))

def test_imsc_1_3_test_suite(self):
for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name):
tree = et.parse(os.path.join(root, filename))
self.assertIsNotNone(imsc_reader.to_model(tree))

def test_referential_styling(self):
tree = et.parse('src/test/resources/ttml/referential_styling.ttml')
doc = imsc_reader.to_model(tree)
Expand Down
31 changes: 31 additions & 0 deletions src/test/python/test_imsc_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,37 @@ def test_imsc_1_1_test_suite(self):
with open(os.path.join(base_path, "tests.json"), "w", encoding="utf8") as fp:
json.dump(manifest, fp)

def test_imsc_1_3_test_suite(self):
manifest = []
base_path = "build/imsc1_3"

for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name), self.assertLogs() as logs:
logging.getLogger().info("*****dummy*****") # dummy log
tree = et.parse(os.path.join(root, filename))
test_model = imsc_reader.to_model(tree)
tree_from_model = imsc_writer.from_model(test_model)

test_dir_relative_path = os.path.basename(root)

test_relative_path = os.path.join(test_dir_relative_path, filename)

os.makedirs(os.path.join(base_path, "ttml", test_dir_relative_path), exist_ok=True)

with open(os.path.join(base_path, "ttml", test_relative_path), "wb") as f:
f.write(et.tostring(tree_from_model.getroot(), 'utf-8'))

manifest.append({"path" : str(test_relative_path).replace('\\', '/')})

if len(logs.output) > 1:
self.fail(logs.output)

with open(os.path.join(base_path, "tests.json"), "w", encoding="utf8") as fp:
json.dump(manifest, fp)


class FromModelBodyWriterTest(unittest.TestCase):

Expand Down
22 changes: 22 additions & 0 deletions src/test/python/test_isd.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ def setUp(self):
t1 = model.Text(self.doc, "hello")
span1.push_child(t1)

def test_iter(self):
isd = ISD.from_model(self.doc, 2)
r_ids = sorted(r.get_id() for r in isd)
self.assertSequenceEqual(r_ids, sorted(("r1", "r2")))

def test_significant_times(self):
self.assertSequenceEqual(ISD.significant_times(self.doc), sorted((0, 2, 3, 9, 1, 10, 4)))

Expand Down Expand Up @@ -273,6 +278,23 @@ def test_imsc_1_1_test_suite(self):
self.assertIsNotNone(isd)
if len(logs.output) > 1:
self.fail(logs.output)

def test_imsc_1_3_test_suite(self):
for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name), self.assertLogs() as logs:
logging.getLogger().info("*****dummy*****") # dummy log
tree = et.parse(os.path.join(root, filename))
m = imsc_reader.to_model(tree)
self.assertIsNotNone(m)
sig_times = ISD.significant_times(m)
for t in sig_times:
isd = ISD.from_model(m, t)
self.assertIsNotNone(isd)
if len(logs.output) > 1:
self.fail(logs.output)

class ComputeStyleTest(unittest.TestCase):

Expand Down
43 changes: 42 additions & 1 deletion src/test/python/test_model_style_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,53 @@

# pylint: disable=R0201,C0115,C0116

from fractions import Fraction
import unittest
from ttconv import model
from ttconv.style_properties import ExtentType, LengthType, StyleProperties, TextShadowType
from ttconv.isd import ISD
from ttconv.style_properties import ExtentType, FontVariantType, LengthType, NamedColors, StyleProperties, TextShadowType

class TestModelStyleProperties(unittest.TestCase):

def setUp(self):
self.doc = model.ContentDocument()

self.r1 = model.Region("r1", self.doc)
self.doc.put_region(self.r1)

self.b = model.Body(self.doc)
self.doc.set_body(self.b)

self.div1 = model.Div(self.doc)
self.div1.set_region(self.r1)
self.b.push_child(self.div1)

self.p1 = model.P(self.doc)
self.div1.push_child(self.p1)

self.span1 = model.Span(self.doc)
self.p1.push_child(self.span1)

self.text1 = model.Text(self.doc, "span1")
self.span1.push_child(self.text1)

def test_fontVariant(self):
self.b.set_style(StyleProperties.FontVariant, FontVariantType.subscript)
self.assertFalse(self.b.is_style_applicable(StyleProperties.FontVariant))

a = model.DiscreteAnimationStep(StyleProperties.FontVariant, 1, None, FontVariantType.superscript)
self.p1.add_animation_step(a)

isd = ISD.from_model(self.doc, 0)
r = list(isd)[0]
self.assertIsNone(r[0][0].get_style(StyleProperties.FontVariant))
self.assertEqual(r[0][0][0][0].get_style(StyleProperties.FontVariant), FontVariantType.subscript)

isd = ISD.from_model(self.doc, 1)
r = list(isd)[0]
self.assertIsNone(r[0][0].get_style(StyleProperties.FontVariant))
self.assertEqual(r[0][0][0][0].get_style(StyleProperties.FontVariant), FontVariantType.superscript)

def test_make_initial(self):
for style in StyleProperties.ALL:
with self.subTest(style.__name__):
Expand Down
14 changes: 14 additions & 0 deletions src/test/python/test_srt_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ def test_imsc_1_2_test_suite(self):
srt_from_model = srt_writer.from_model(test_model)
self._check_output_srt(test_model, srt_from_model, path)

@unittest.skip("IMSC 1.3 is not supported")
def test_imsc_1_3_test_suite(self):
for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name):
path = os.path.join(root, filename)
tree = et.parse(path)
test_model = imsc_reader.to_model(tree)
srt_from_model = srt_writer.from_model(test_model)
self._check_output_srt(test_model, srt_from_model, path)


#
# Utility functions
#
Expand Down
12 changes: 12 additions & 0 deletions src/test/python/test_vtt_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,18 @@ def test_imsc_1_2_test_suite(self):
vtt_from_model =vtt_writer.from_model(test_model, None)
self._check_output_vtt(test_model, vtt_from_model, path)

@unittest.skip("IMSC 1.3 is not supported")
def test_imsc_1_3_test_suite(self):
for root, _subdirs, files in os.walk("src/test/resources/ttml/imsc-tests/imsc1_3/ttml"):
for filename in files:
(name, ext) = os.path.splitext(filename)
if ext == ".ttml":
with self.subTest(name):
path = os.path.join(root, filename)
tree = et.parse(path)
test_model = imsc_reader.to_model(tree)
vtt_from_model =vtt_writer.from_model(test_model, None)
self._check_output_vtt(test_model, vtt_from_model, path)
#
# Utility functions
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0.0 +
1.0 -
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0.0 +
1.0 -
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.0 +
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0.0 +
30.0 -