def ordered_styles(self, dataset):
        """
        This function figures out the chain of styles.
        WARNING: Do not call this before the semantic validation of tt/head/styling is finished. Otherwise your style
        may not have been found yet!
        :param dataset: Semantic dataset
        :return: a list of styles applicable in order
        """

        if self._styling_lock.locked():
            raise SemanticValidationError(ERR_SEMANTIC_STYLE_CIRCLE.format(
                style=self.id
            ))

        with self._styling_lock:
            if self._ordered_styles is not None:
                return self._ordered_styles
            ordered_styles = [self]
            if self.style is not None:
                for style_id in self.style:
                    try:
                        style_elem = dataset['tt_element'].get_element_by_id(elem_id=style_id, elem_type=style_type)
                        cascading_styles = style_elem.ordered_styles(dataset=dataset)
                        for style_elem in cascading_styles:
                            if style_elem in ordered_styles:
                                continue
                            ordered_styles.append(style_elem)
                    except LookupError:
                        raise SemanticValidationError(ERR_SEMANTIC_STYLE_MISSING.format(
                            style=style_id
                        ))

            self._ordered_styles = ordered_styles
            return ordered_styles
Esempio n. 2
0
 def _semantic_register_id(self, dataset):
     ebid = dataset['elements_by_id']
     if self.id is not None:
         if self.id in ebid:
             raise SemanticValidationError(
                 ERR_SEMANTIC_ID_UNIQUENESS.format(id=self.id))
         ebid[self.id] = self
Esempio n. 3
0
 def _semantic_set_region(self, dataset, region_type):
     if self.region is not None:
         try:
             region = dataset['tt_element'].get_element_by_id(self.region, region_type)
             dataset['region'] = region
             self._validated_region = region
         except LookupError:
             raise SemanticValidationError(ERR_SEMANTIC_REGION_MISSING.format(
                 region=self.region
             ))
 def __semantic_test_time_base_clock_attrs_absent(self):
     clock_attrs = [
         'clockMode'
     ]
     extra_attrs = self._semantic_attributes_present(clock_attrs)
     if extra_attrs:
         raise SemanticValidationError(
             ERR_SEMANTIC_VALIDATION_MISSING_ATTRIBUTES.format(
                 elem_name='tt:tt',
                 attr_names=extra_attrs
             )
         )
 def get_element_by_id(self, elem_id, elem_type=None):
     """
     Lookup an element and return it. Optionally type is checked as well.
     :param elem_id:
     :param elem_type:
     :return:
     """
     if self._elements_by_id is None:
         raise SemanticValidationError(ERR_SEMANTIC_VALIDATION_EXPECTED)
     element = self._elements_by_id.get(elem_id, None)
     if element is None or elem_type is not None and not isinstance(element, elem_type):
         raise LookupError(ERR_SEMANTIC_ELEMENT_BY_ID_MISSING.format(id=elem_id))
     return element
 def __semantic_test_smpte_attrs_absent(self):
     smpte_attrs = [
         'dropMode',
         'markerMode'
     ]
     extra_attrs = self._semantic_attributes_present(smpte_attrs)
     if extra_attrs:
         raise SemanticValidationError(
             ERR_SEMANTIC_VALIDATION_INVALID_ATTRIBUTES.format(
                 elem_name='tt:tt',
                 attr_names=extra_attrs
             )
         )
 def __semantic_test_smpte_attrs_present(self):
     smpte_attrs = [
         'frameRate',
         # 'frameRateMultiplier',
         'dropMode',
         'markerMode'
     ]
     missing_attrs = self._semantic_attributes_missing(smpte_attrs)
     if missing_attrs:
         raise SemanticValidationError(
             ERR_SEMANTIC_VALIDATION_MISSING_ATTRIBUTES.format(
                 elem_name='tt:tt',
                 attr_names=missing_attrs
             )
         )
Esempio n. 8
0
 def _semantic_timebase_validation(self, dataset, element_content):
     time_base = dataset['tt_element'].timeBase
     if self.begin is not None:
         if hasattr(self.begin, 'compatible_timebases'):
             # Check typing of begin attribute against the timebase
             timebases = self.begin.compatible_timebases()
             if time_base not in timebases['begin']:
                 raise SemanticValidationError(
                     ERR_SEMANTIC_VALIDATION_TIMING_TYPE.format(
                         attr_type=type(self.begin),
                         attr_value=self.begin,
                         attr_name='begin',
                         time_base=time_base))
     if self.end is not None:
         if hasattr(self.end, 'compatible_timebases'):
             # Check typing of end attribute against the timebase
             timebases = self.end.compatible_timebases()
             if time_base not in timebases['end']:
                 raise SemanticValidationError(
                     ERR_SEMANTIC_VALIDATION_TIMING_TYPE.format(
                         attr_type=type(self.end),
                         attr_value=self.end,
                         attr_name='end',
                         time_base=time_base))
Esempio n. 9
0
    def _semantic_timebase_validation(self, dataset, element_content):

        super(BodyTimingValidationMixin,
              self)._semantic_timebase_validation(dataset, element_content)
        time_base = dataset['tt_element'].timeBase

        if self.dur is not None:
            if hasattr(self.dur, 'compatible_timebases'):
                # Check typing of dur attribute against the timebase
                timebases = self.dur.compatible_timebases()
                if time_base not in timebases['dur']:
                    raise SemanticValidationError(
                        ERR_SEMANTIC_VALIDATION_TIMING_TYPE.format(
                            attr_type=type(self.dur),
                            attr_value=self.dur,
                            attr_name='dur',
                            time_base=time_base))
    def _semantic_collect_applicable_styles(self, dataset, style_type):
        referenced_styles = []
        inherited_styles = []
        region_styles = []
        if self.style is not None:
            # Styles cascade
            for style_id in self.style:
                try:
                    style = dataset['tt_element'].get_element_by_id(
                        elem_id=style_id, elem_type=style_type)
                    for style_binding in style.ordered_styles(dataset=dataset):
                        if style_binding not in referenced_styles:
                            referenced_styles.append(style_binding)
                except LookupError:
                    raise SemanticValidationError(
                        ERR_SEMANTIC_STYLE_MISSING.format(style=style_id))

            # Push this validated set onto the stack for children to use

        for style_list in dataset['styles_stack']:
            # Traverse all the styles encountered at our parent elements
            for inh_style in style_list:
                if inh_style not in referenced_styles and inh_style not in inherited_styles:
                    inherited_styles.append(inh_style)

        region = dataset.get('region', None)
        self._inherited_region = region

        if region is not None:
            # At last apply any region styles we may find
            for region_style in region.validated_styles:
                if region_style not in referenced_styles and region_style not in inherited_styles:
                    region_styles.append(region_style)

        self._referenced_styles = referenced_styles
        self._validated_styles = referenced_styles + inherited_styles + region_styles
Esempio n. 11
0
    def _semantic_collect_applicable_styles(self, dataset, style_type, parent_binding, defer_font_size=False,
                                            extra_referenced_styles=None):
        """
        This function identifies the styling dependency chain for the styled element in question.

        :param dataset: Semantic dataset
        :param style_type: the style_type to be used in the process (there are different style types for EBU-TT D and live).
        :param parent_binding: The immediate parent of the styled element in the document structure
        :param defer_font_size: If True then fontsize can stay percentage in case it could not be calculated
        :param extra_referenced_styles: Used by region to inject its extra style attributes

        :return:
        """

        self._specified_style = None
        self._computed_style = None
        self._parent_computed_style = None
        referenced_styles = []
        inherited_styles = []
        region_styles = []
        if extra_referenced_styles is None:
            extra_referenced_styles = []

        if self.style is not None:
            # Styles cascade
            for style_id in self.style:
                try:
                    style = dataset['tt_element'].get_element_by_id(elem_id=style_id, elem_type=style_type)
                    for style_binding in style.ordered_styles(dataset=dataset):
                        if style_binding not in referenced_styles:
                            referenced_styles.append(style_binding)
                except LookupError:
                    raise SemanticValidationError(ERR_SEMANTIC_STYLE_MISSING.format(style=style_id))

            # Push this validated set onto the stack for children to use

        for style_list in dataset['styles_stack']:
            # Traverse all the styles encountered at our parent elements
            for inh_style in style_list:
                if inh_style not in referenced_styles and inh_style not in inherited_styles:
                    inherited_styles.append(inh_style)

        region = dataset.get('region', None)
        self._inherited_region = region

        if region is not None:
            # At last apply any region styles we may find
            for region_style in region.validated_styles:
                if region_style not in referenced_styles and region_style not in inherited_styles:
                    region_styles.append(region_style)

        self._referenced_styles = referenced_styles
        self._inherited_styles = inherited_styles
        self._region_styles = region_styles
        self._validated_styles = referenced_styles + inherited_styles + region_styles

        if parent_binding is not None and hasattr(parent_binding, 'computed_style'):
            parent_computed_style = parent_binding.computed_style
        else:
            parent_computed_style = None

        if region is not None and hasattr(region, 'computed_style'):
            region_computed_style = region.computed_style
        else:
            region_computed_style = None

        # Let's resolve the specified styles
        # Make sure the extra style attributes supersede the rest of the referenced styles
        self._specified_style = self._compatible_style_type.resolve_styles(extra_referenced_styles + referenced_styles)

        # Let's generate the computed style of the element
        self._computed_style = self._compatible_style_type.compute_style(
            self._specified_style,
            parent_computed_style,
            region_computed_style,
            dataset,
            defer_font_size
        )
Esempio n. 12
0
 def validated_styles(self):
     if self._validated_styles is None:
         raise SemanticValidationError(ERR_SEMANTIC_VALIDATION_EXPECTED)
     return self._validated_styles