Esempio n. 1
0
    def generate_css_value_mappings(self):
        mappings = {}

        for property_ in self._properties.values():
            if property_['field_template'] == 'keyword':
                mappings[property_['type_name']] = {
                    'default_value': 'k' + camel_case(property_['initial_keyword']),
                    'mapping': [('k' + camel_case(k), enum_for_css_keyword(k)) for k in property_['keywords']],
                }

        return {
            'include_paths': self._include_paths,
            'mappings': mappings,
        }
    def __init__(self, file_paths):
        in_generator.Writer.__init__(self, file_paths)

        properties = self.in_file.name_dictionaries
        self._descriptors = [property for property in properties if property['descriptor_only']]

        self._aliases = [property for property in properties if property['alias_for']]
        properties = [property for property in properties if not property['alias_for']]

        # 0: CSSPropertyInvalid
        # 1: CSSPropertyApplyAtRule
        # 2: CSSPropertyVariable
        self._first_enum_value = 3

        # StylePropertyMetadata additionally assumes there are under 1024 properties.
        assert self._first_enum_value + len(properties) < 512, 'Property aliasing expects there are under 512 properties.'

        for offset, property in enumerate(properties):
            property['property_id'] = name_utilities.enum_for_css_property(property['name'])
            property['upper_camel_name'] = name_utilities.camel_case(property['name'])
            property['lower_camel_name'] = name_utilities.lower_first(property['upper_camel_name'])
            property['enum_value'] = self._first_enum_value + offset
            property['is_internal'] = property['name'].startswith('-internal-')

        self._properties_including_aliases = properties
        self._properties = {property['property_id']: property for property in properties}

        # The generated code will only work with at most one alias per property
        assert len({property['alias_for'] for property in self._aliases}) == len(self._aliases)

        for property in self._aliases:
            property['property_id'] = name_utilities.enum_for_css_property_alias(property['name'])
            aliased_property = self._properties[name_utilities.enum_for_css_property(property['alias_for'])]
            property['enum_value'] = aliased_property['enum_value'] + 512
        self._properties_including_aliases += self._aliases
Esempio n. 3
0
    def __init__(self, file_paths):
        in_generator.Writer.__init__(self, file_paths)

        properties = self.in_file.name_dictionaries
        self._descriptors = [
            property for property in properties if property['descriptor_only']
        ]

        self._aliases = [
            property for property in properties if property['alias_for']
        ]
        properties = [
            property for property in properties if not property['alias_for']
        ]

        # 0: CSSPropertyInvalid
        # 1: CSSPropertyApplyAtRule
        # 2: CSSPropertyVariable
        self._first_enum_value = 3

        # StylePropertyMetadata additionally assumes there are under 1024 properties.
        assert self._first_enum_value + len(
            properties
        ) < 512, 'Property aliasing expects there are under 512 properties.'

        for offset, property in enumerate(properties):
            property['property_id'] = name_utilities.enum_for_css_property(
                property['name'])
            property['upper_camel_name'] = name_utilities.camel_case(
                property['name'])
            property['lower_camel_name'] = name_utilities.lower_first(
                property['upper_camel_name'])
            property['enum_value'] = self._first_enum_value + offset
            property['is_internal'] = property['name'].startswith('-internal-')

        self._properties_including_aliases = properties
        self._properties = {
            property['property_id']: property
            for property in properties
        }

        # The generated code will only work with at most one alias per property
        assert len({property['alias_for']
                    for property in self._aliases}) == len(self._aliases)

        for property in self._aliases:
            property[
                'property_id'] = name_utilities.enum_for_css_property_alias(
                    property['name'])
            aliased_property = self._properties[
                name_utilities.enum_for_css_property(property['alias_for'])]
            property['enum_value'] = aliased_property['enum_value'] + 512
        self._properties_including_aliases += self._aliases
def _create_property_field(property_):
    """
    Create a property field from a CSS property and return the Field object.
    """
    property_name = property_['name_for_methods']
    property_name_lower = lower_first(property_name)

    # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members]
    field_name = 'm_' + property_name_lower
    bits_needed = math.log(len(property_['keywords']), 2)

    # Separate the type path from the type name, if specified.
    if property_['field_storage_type']:
        type_path = property_['field_storage_type']
        type_name = type_path.split('/')[-1]
    else:
        type_name = property_['type_name']
        type_path = None

    # For now, the getter name should match the field name. Later, getter names
    # will start with an uppercase letter, so if they conflict with the type name,
    # add 'get' to the front.
    getter_method_name = property_name_lower
    if type_name == property_name:
        getter_method_name = 'get' + property_name

    assert property_['initial_keyword'] is not None, \
        ('MakeComputedStyleBase requires an initial keyword for keyword_only values, none specified '
         'for property ' + property_['name'])
    default_value = type_name + '::k' + camel_case(
        property_['initial_keyword'])

    # Add the property itself as a member variable.
    return Field(
        'property',
        name=field_name,
        property_name=property_['name'],
        inherited=property_['inherited'],
        independent=property_['independent'],
        storage_type=type_name,
        storage_type_path=type_path,
        size=int(math.ceil(bits_needed)),
        default_value=default_value,
        getter_method_name=getter_method_name,
        setter_method_name='set' + property_name,
        initial_method_name='initial' + property_name,
        resetter_method_name='reset' + property_name,
        is_inherited_method_name=property_name_lower + 'IsInherited',
    )
def _create_enums(properties):
    """
    Returns a dictionary of enums to be generated, enum name -> [list of enum values]
    """
    enums = {}
    for property_ in properties:
        # Only generate enums for keyword properties that use the default field_storage_type.
        if property_[
                'keyword_only'] and property_['field_storage_type'] is None:
            enum_name = property_['type_name']
            # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members]
            enum_values = [('k' + camel_case(k))
                           for k in property_['keywords']]
            enums[enum_name] = enum_values

    return enums
Esempio n. 6
0
def _create_property_field(property_):
    """
    Create a property field from a CSS property and return the Field object.
    """
    property_name = property_['name_for_methods']
    property_name_lower = lower_first(property_name)

    # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members]
    field_name = 'm_' + property_name_lower
    bits_needed = math.log(len(property_['keywords']), 2)  # TODO: implement for non-enums
    type_name = property_['type_name']

    # For now, the getter name should match the field name. Later, getter names
    # will start with an uppercase letter, so if they conflict with the type name,
    # add 'get' to the front.
    getter_method_name = property_name_lower
    if type_name == property_name:
        getter_method_name = 'get' + property_name

    assert property_['initial_keyword'] is not None, \
        ('MakeComputedStyleBase requires an initial keyword for keyword fields, none specified '
         'for property ' + property_['name'])
    default_value = type_name + '::k' + camel_case(property_['initial_keyword'])

    return Field(
        'property',
        name=field_name,
        property_name=property_['name'],
        inherited=property_['inherited'],
        independent=property_['independent'],
        type_name=type_name,
        field_template=property_['field_template'],
        size=int(math.ceil(bits_needed)),
        default_value=default_value,
        getter_method_name=getter_method_name,
        setter_method_name='set' + property_name,
        initial_method_name='initial' + property_name,
        resetter_method_name='reset' + property_name,
        is_inherited_method_name=property_name_lower + 'IsInherited',
    )
Esempio n. 7
0
def _create_enums(properties):
    """
    Returns a dictionary of enums to be generated, enum name -> [list of enum values]
    """
    enums = {}
    for property_ in properties:
        # Only generate enums for keyword properties that use the default field_type_path.
        if property_['field_template'] == 'keyword' and property_['field_type_path'] is None:
            enum_name = property_['type_name']
            # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members]
            enum_values = [('k' + camel_case(k)) for k in property_['keywords']]

            if enum_name in enums:
                # There's an enum with the same name, check if the enum values are the same
                assert set(enums[enum_name]) == set(enum_values), \
                    ("'" + property_['name'] + "' can't have type_name '" + enum_name + "' "
                     "because it was used by a previous property, but with a different set of keywords. "
                     "Either give it a different name or ensure the keywords are the same.")

            enums[enum_name] = enum_values

    return enums
    def __init__(self, in_file_path):
        super(ComputedStyleBaseWriter, self).__init__(in_file_path)
        self._outputs = {
            'ComputedStyleBase.h':
            self.generate_base_computed_style_h,
            'ComputedStyleBase.cpp':
            self.generate_base_computed_style_cpp,
            'ComputedStyleBaseConstants.h':
            self.generate_base_computed_style_constants,
        }

        # A map of enum name -> list of enum values
        self._computed_enums = {}
        for property in self._properties.values():
            # Only generate enums for keyword properties that use the default field_storage_type.
            if property[
                    'keyword_only'] and property['field_storage_type'] is None:
                enum_name = property['type_name']
                # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members]
                enum_values = [('k' + camel_case(k))
                               for k in property['keywords']]
                self._computed_enums[enum_name] = enum_values

        # A list of all the fields to be generated.
        all_fields = []
        for property in self._properties.values():
            if property['keyword_only']:
                property_name = property['name_for_methods']
                property_name_lower = property_name[0].lower(
                ) + property_name[1:]

                # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members]
                field_name = 'm_' + property_name_lower
                bits_needed = math.log(len(property['keywords']), 2)

                # Separate the type path from the type name, if specified.
                type_name = property['type_name']
                type_path = None
                if property['field_storage_type']:
                    type_path = property['field_storage_type']
                    type_name = type_path.split('/')[-1]

                # For now, the getter name should match the field name. Later, getter names
                # will start with an uppercase letter, so if they conflict with the type name,
                # add 'get' to the front.
                getter_method_name = property_name_lower
                if type_name == property_name:
                    getter_method_name = 'get' + property_name

                assert property['initial_keyword'] is not None, \
                    ('MakeComputedStyleBase requires an initial keyword for keyword_only values, none specified '
                     'for property ' + property['name'])
                default_value = type_name + '::k' + camel_case(
                    property['initial_keyword'])

                # If the property is independent, add the single-bit sized isInherited flag
                # to the list of Fields as well.
                if property['independent']:
                    field_name_suffix_upper = property_name + 'IsInherited'
                    field_name_suffix_lower = property_name_lower + 'IsInherited'
                    all_fields.append(
                        Field(
                            'inherited_flag',
                            name='m_' + field_name_suffix_lower,
                            property_name=property['name'],
                            storage_type='bool',
                            storage_type_path=None,
                            size=1,
                            default_value='true',
                            getter_method_name=field_name_suffix_lower,
                            setter_method_name='set' + field_name_suffix_upper,
                            initial_method_name='initial' +
                            field_name_suffix_upper,
                            resetter_method_name='reset' +
                            field_name_suffix_upper,
                        ))

                # Add the property itself as a member variable.
                all_fields.append(
                    Field(
                        'enum',
                        name=field_name,
                        property_name=property['name'],
                        inherited=property['inherited'],
                        independent=property['independent'],
                        storage_type=type_name,
                        storage_type_path=type_path,
                        size=int(math.ceil(bits_needed)),
                        default_value=default_value,
                        getter_method_name=getter_method_name,
                        setter_method_name='set' + property_name,
                        initial_method_name='initial' + property_name,
                        resetter_method_name='reset' + property_name,
                        is_inherited_method_name=property_name_lower +
                        'IsInherited',
                    ))

        # Since fields cannot cross word boundaries, in order to minimize
        # padding, group fields into buckets so that as many buckets as possible
        # that are exactly 32 bits. Although this greedy approach may not always
        # produce the optimal solution, we add a static_assert to the code to
        # ensure ComputedStyleBase results in the expected size. If that
        # static_assert fails, this code is falling into the small number of
        # cases that are suboptimal, and may need to be rethought.
        # For more details on packing bitfields to reduce padding, see:
        # http://www.catb.org/esr/structure-packing/#_bitfields
        field_buckets = []
        # Consider fields in descending order of size to reduce fragmentation
        # when they are selected.
        for field in sorted(all_fields, key=lambda f: f.size, reverse=True):
            added_to_bucket = False
            # Go through each bucket and add this field if it will not increase
            # the bucket's size to larger than 32 bits. Otherwise, make a new
            # bucket containing only this field.
            for bucket in field_buckets:
                if sum(f.size for f in bucket) + field.size <= 32:
                    bucket.append(field)
                    added_to_bucket = True
                    break
            if not added_to_bucket:
                field_buckets.append([field])

        # The expected size of ComputedStyleBase is equivalent to as many words
        # as the total number of buckets.
        self._expected_total_field_bytes = len(field_buckets)

        # The most optimal size of ComputedStyleBase is the total sum of all the
        # field sizes, rounded up to the nearest word. If this produces the
        # incorrect value, either the packing algorithm is not optimal or there
        # is no way to pack the fields such that excess padding space is not
        # added.
        # If this fails, increase extra_padding_bytes by 1, but be aware that
        # this also increases ComputedStyleBase by 1 word.
        # We should be able to bring extra_padding_bytes back to 0 from time to
        # time.
        extra_padding_bytes = 0
        optimal_total_field_bytes = int(
            math.ceil(sum(f.size for f in all_fields) / 32.0))
        real_total_field_bytes = optimal_total_field_bytes + extra_padding_bytes
        assert self._expected_total_field_bytes == real_total_field_bytes, \
            ('The field packing algorithm produced %s bytes, optimal is %s bytes' %
             (len(field_buckets), self._expected_total_field_bytes))

        # Order the fields so fields in each bucket are adjacent.
        self._fields = []
        for bucket in field_buckets:
            for field in bucket:
                self._fields.append(field)
Esempio n. 9
0
    def __init__(self, file_paths):
        json5_generator.Writer.__init__(self, file_paths)

        properties = self.json5_file.name_dictionaries

        # Sort properties by priority, then alphabetically.
        for property in properties:
            # This order must match the order in CSSPropertyPriority.h.
            priority_numbers = {'Animation': 0, 'High': 1, 'Low': 2}
            priority = priority_numbers[property['priority']]
            name_without_leading_dash = property['name']
            if property['name'].startswith('-'):
                name_without_leading_dash = property['name'][1:]
            property['sorting_key'] = (priority, name_without_leading_dash)

        # Assert there are no key collisions.
        sorting_keys = [p['sorting_key'] for p in properties]
        assert len(sorting_keys) == len(set(sorting_keys)), \
            ('Collision detected - two properties have the same name and priority, '
             'a potentially non-deterministic ordering can occur.')
        properties.sort(key=lambda p: p['sorting_key'])

        self._aliases = [
            property for property in properties if property['alias_for']
        ]
        properties = [
            property for property in properties if not property['alias_for']
        ]

        # 0: CSSPropertyInvalid
        # 1: CSSPropertyApplyAtRule
        # 2: CSSPropertyVariable
        self._first_enum_value = 3

        # StylePropertyMetadata additionally assumes there are under 1024 properties.
        assert self._first_enum_value + len(
            properties
        ) < 512, 'Property aliasing expects there are under 512 properties.'

        for offset, property in enumerate(properties):
            property['property_id'] = name_utilities.enum_for_css_property(
                property['name'])
            property['upper_camel_name'] = name_utilities.camel_case(
                property['name'])
            property['lower_camel_name'] = name_utilities.lower_first(
                property['upper_camel_name'])
            property['enum_value'] = self._first_enum_value + offset
            property['is_internal'] = property['name'].startswith('-internal-')

        self._properties_including_aliases = properties
        self._properties = {
            property['property_id']: property
            for property in properties
        }

        # The generated code will only work with at most one alias per property
        assert len({property['alias_for']
                    for property in self._aliases}) == len(self._aliases)

        for property in self._aliases:
            property[
                'property_id'] = name_utilities.enum_for_css_property_alias(
                    property['name'])
            aliased_property = self._properties[
                name_utilities.enum_for_css_property(property['alias_for'])]
            property['enum_value'] = aliased_property['enum_value'] + 512
        self._properties_including_aliases += self._aliases
Esempio n. 10
0
    def __init__(self, in_file_path):
        super(ComputedStyleBaseWriter, self).__init__(in_file_path)
        self._outputs = {
            'ComputedStyleBase.h': self.generate_base_computed_style_h,
            'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp,
            'ComputedStyleBaseConstants.h': self.generate_base_computed_style_constants,
        }

        # A map of enum name -> list of enum values
        self._computed_enums = {}
        for property in self._properties.values():
            if property['keyword_only']:
                enum_name = property['type_name']
                # From the Blink style guide: Enum members should use InterCaps with an initial capital letter. [names-enum-members]
                enum_values = [camel_case(k) for k in property['keywords']]
                self._computed_enums[enum_name] = enum_values

        # A list of all the fields to be generated.
        self._fields = []
        for property in self._properties.values():
            if property['keyword_only']:
                property_name = property['upper_camel_name']
                if property['name_for_methods']:
                    property_name = property['name_for_methods']
                property_name_lower = property_name[0].lower() + property_name[1:]

                # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members]
                field_name = 'm_' + property_name_lower
                bits_needed = math.log(len(property['keywords']), 2)
                type_name = property['type_name']

                assert property['initial_keyword'] is not None, \
                    ('MakeComputedStyleBase requires an initial keyword for keyword_only values, none specified '
                     'for property ' + property['name'])
                default_value = type_name + '::' + camel_case(property['initial_keyword'])

                # If the property is independent, add the single-bit sized isInherited flag
                # to the list of Fields as well.
                if property['independent']:
                    field_name_suffix_upper = property['upper_camel_name'] + 'IsInherited'
                    field_name_suffix_lower = property_name_lower + 'IsInherited'
                    self._fields.append(Field(
                        'inherited_flag',
                        name='m_' + field_name_suffix_lower,
                        property_name=property['name'],
                        type='bool',
                        size=1,
                        default_value='true',
                        getter_method_name=field_name_suffix_lower,
                        setter_method_name='set' + field_name_suffix_upper,
                        initial_method_name='initial' + field_name_suffix_upper,
                        resetter_method_name='reset' + field_name_suffix_upper,
                    ))

                # Add the property itself as a member variable.
                self._fields.append(Field(
                    'enum',
                    name=field_name,
                    property_name=property['name'],
                    inherited=property['inherited'],
                    independent=property['independent'],
                    type=type_name,
                    size=int(math.ceil(bits_needed)),
                    default_value=default_value,
                    getter_method_name=property_name_lower,
                    setter_method_name='set' + property_name,
                    initial_method_name='initial' + property_name,
                    resetter_method_name='reset' + property_name,
                    is_inherited_method_name=property_name_lower + 'IsInherited',
                ))

        # Small optimization: order fields by size, from largest to smallest,
        # to reduce wasted space from alignment.
        self._fields.sort(key=lambda f: f.size, reverse=True)