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
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
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', )
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)
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
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)