Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 import math | 6 import math |
| 7 import sys | 7 import sys |
| 8 | 8 |
| 9 import json5_generator | 9 import json5_generator |
| 10 import template_expander | 10 import template_expander |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 # Default value for field | 55 # Default value for field |
| 56 'default_value', | 56 'default_value', |
| 57 # Method names | 57 # Method names |
| 58 'getter_method_name', | 58 'getter_method_name', |
| 59 'setter_method_name', | 59 'setter_method_name', |
| 60 'initial_method_name', | 60 'initial_method_name', |
| 61 'resetter_method_name', | 61 'resetter_method_name', |
| 62 ]) | 62 ]) |
| 63 | 63 |
| 64 def __init__(self, field_role, **kwargs): | 64 def __init__(self, field_role, **kwargs): |
| 65 # TODO(shend): get rid of this kwargs thing by creating separate classes | |
| 66 # for each field template and taking in normal arguments, then remove th e | |
| 67 # line below | |
| 68 # pylint: disable=no-member | |
|
meade_UTC10
2017/02/17 06:56:05
Is this a new lint that got enabled? o.O
shend
2017/02/19 23:10:17
Urgh, the comment doesn't explain anything, I upda
| |
| 69 | |
| 65 # Values common to all fields | 70 # Values common to all fields |
| 66 # Set attributes from the keyword arguments | 71 # Set attributes from the keyword arguments |
| 67 for attrib in Field.REQUIRED_ATTRIBUTES: | 72 for attrib in Field.REQUIRED_ATTRIBUTES: |
| 68 setattr(self, attrib, kwargs.pop(attrib)) | 73 setattr(self, attrib, kwargs.pop(attrib)) |
| 69 | 74 |
| 70 # Field role: one of these must be true | 75 # Field role: one of these must be true |
| 71 self.is_property = field_role == 'property' | 76 self.is_property = field_role == 'property' |
| 72 self.is_inherited_flag = field_role == 'inherited_flag' | 77 self.is_inherited_flag = field_role == 'inherited_flag' |
| 73 self.is_nonproperty = field_role == 'nonproperty' | 78 self.is_nonproperty = field_role == 'nonproperty' |
| 74 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c ount(True) == 1, \ | 79 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c ount(True) == 1, \ |
| 75 'Field role has to be exactly one of: property, inherited_flag, nonp roperty' | 80 'Field role has to be exactly one of: property, inherited_flag, nonp roperty' |
| 76 | 81 |
| 77 if self.is_property: | 82 if self.is_property: |
| 78 self.is_inherited = kwargs.pop('inherited') | 83 self.is_inherited = kwargs.pop('inherited') |
| 79 self.is_independent = kwargs.pop('independent') | 84 self.is_independent = kwargs.pop('independent') |
| 80 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' | 85 assert self.is_inherited or not self.is_independent, 'Only inherited fields can be independent' |
| 81 | 86 |
| 82 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') | 87 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name ') |
| 83 elif self.is_inherited_flag: | 88 elif self.is_inherited_flag: |
| 84 # Inherited flag-only fields | 89 # Inherited flag-only fields |
| 85 pass | 90 pass |
| 86 | 91 |
| 92 # Only pack the field if the field size is not None | |
|
meade_UTC10
2017/02/17 06:56:05
nit: Does this mean when the field is used as inpu
shend
2017/02/19 23:10:17
Yeah "packed" is ambiguous. I changed it to 'is_bi
| |
| 93 self.is_packed = self.size is not None | |
| 94 | |
| 87 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) | 95 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) |
| 88 | 96 |
| 89 | 97 |
| 90 def _get_include_paths(properties): | 98 def _get_include_paths(properties): |
| 91 """ | 99 """ |
| 92 Get a list of paths that need to be included for ComputedStyleBase. | 100 Get a list of paths that need to be included for ComputedStyleBase. |
| 93 """ | 101 """ |
| 94 include_paths = set() | 102 include_paths = set() |
| 95 for property_ in properties: | 103 for property_ in properties: |
| 96 if property_['field_type_path'] is not None: | 104 if property_['field_type_path'] is not None: |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 124 | 132 |
| 125 def _create_property_field(property_): | 133 def _create_property_field(property_): |
| 126 """ | 134 """ |
| 127 Create a property field from a CSS property and return the Field object. | 135 Create a property field from a CSS property and return the Field object. |
| 128 """ | 136 """ |
| 129 property_name = property_['name_for_methods'] | 137 property_name = property_['name_for_methods'] |
| 130 property_name_lower = lower_first(property_name) | 138 property_name_lower = lower_first(property_name) |
| 131 | 139 |
| 132 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] | 140 # From the Blink style guide: Other data members should be prefixed by "m_". [names-data-members] |
| 133 field_name = 'm_' + property_name_lower | 141 field_name = 'm_' + property_name_lower |
| 134 bits_needed = math.log(len(property_['keywords']), 2) # TODO: implement for non-enums | |
| 135 | 142 |
| 136 # Separate the type path from the type name, if specified. | 143 # Override the type_name if field_type_path is specified |
| 137 if property_['field_type_path']: | 144 if property_['field_type_path']: |
| 138 type_name = property_['field_type_path'].split('/')[-1] | 145 type_name = property_['field_type_path'].split('/')[-1] |
| 139 else: | 146 else: |
| 140 type_name = property_['type_name'] | 147 type_name = property_['type_name'] |
| 141 | 148 |
| 142 # For now, the getter name should match the field name. Later, getter names | 149 # For now, the getter name should match the field name. Later, getter names |
| 143 # will start with an uppercase letter, so if they conflict with the type nam e, | 150 # will start with an uppercase letter, so if they conflict with the type nam e, |
| 144 # add 'get' to the front. | 151 # add 'get' to the front. |
| 145 getter_method_name = property_name_lower | 152 getter_method_name = property_name_lower |
| 146 if type_name == property_name: | 153 if type_name == property_name: |
| 147 getter_method_name = 'get' + property_name | 154 getter_method_name = 'get' + property_name |
| 148 | 155 |
| 149 assert property_['initial_keyword'] is not None, \ | 156 if property_['field_template'] == 'keyword': |
| 150 ('MakeComputedStyleBase requires an initial keyword for keyword fields, none specified ' | 157 assert property_['default_value'] is not None, \ |
| 151 'for property ' + property_['name']) | 158 ('MakeComputedStyleBase requires an initial keyword for keyword fiel ds, none specified ' |
| 152 default_value = type_name + '::k' + camel_case(property_['initial_keyword']) | 159 'for property ' + property_['name']) |
| 160 bits_needed = int(math.ceil(math.log(len(property_['keywords']), 2))) | |
| 161 default_value = type_name + '::k' + camel_case(property_['default_value' ]) | |
| 162 else: | |
| 163 bits_needed = None | |
| 164 default_value = property_['default_value'] | |
| 153 | 165 |
| 154 return Field( | 166 return Field( |
| 155 'property', | 167 'property', |
| 156 name=field_name, | 168 name=field_name, |
| 157 property_name=property_['name'], | 169 property_name=property_['name'], |
| 158 inherited=property_['inherited'], | 170 inherited=property_['inherited'], |
| 159 independent=property_['independent'], | 171 independent=property_['independent'], |
| 160 type_name=type_name, | 172 type_name=type_name, |
| 161 field_template=property_['field_template'], | 173 field_template=property_['field_template'], |
| 162 size=int(math.ceil(bits_needed)), | 174 size=bits_needed, |
| 163 default_value=default_value, | 175 default_value=default_value, |
| 164 getter_method_name=getter_method_name, | 176 getter_method_name=getter_method_name, |
| 165 setter_method_name='set' + property_name, | 177 setter_method_name='set' + property_name, |
| 166 initial_method_name='initial' + property_name, | 178 initial_method_name='initial' + property_name, |
| 167 resetter_method_name='reset' + property_name, | 179 resetter_method_name='reset' + property_name, |
| 168 is_inherited_method_name=property_name_lower + 'IsInherited', | 180 is_inherited_method_name=property_name_lower + 'IsInherited', |
| 169 ) | 181 ) |
| 170 | 182 |
| 171 | 183 |
| 172 def _create_inherited_flag_field(property_): | 184 def _create_inherited_flag_field(property_): |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, | 291 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, |
| 280 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_co nstants, | 292 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_co nstants, |
| 281 } | 293 } |
| 282 | 294 |
| 283 # Create all the enums used by properties | 295 # Create all the enums used by properties |
| 284 self._generated_enums = _create_enums(self._properties.values()) | 296 self._generated_enums = _create_enums(self._properties.values()) |
| 285 | 297 |
| 286 # Create all the fields | 298 # Create all the fields |
| 287 all_fields = _create_fields(self._properties.values()) | 299 all_fields = _create_fields(self._properties.values()) |
| 288 | 300 |
| 289 # Group fields into buckets | 301 # Separate the normal data members from the bit fields |
| 290 field_buckets = _pack_fields(all_fields) | 302 packed_fields = [field for field in all_fields if field.is_packed] |
| 303 unpacked_fields = [field for field in all_fields if not field.is_packed] | |
| 304 | |
| 305 # Pack fields into buckets | |
| 306 field_buckets = _pack_fields(packed_fields) | |
| 291 | 307 |
| 292 # The expected size of ComputedStyleBase is equivalent to as many words | 308 # The expected size of ComputedStyleBase is equivalent to as many words |
| 293 # as the total number of buckets. | 309 # as the total number of buckets. |
| 294 self._expected_total_field_bytes = len(field_buckets) | 310 self._expected_bitfield_bytes = len(field_buckets) |
| 295 | 311 |
| 296 # The most optimal size of ComputedStyleBase is the total sum of all the | 312 # The most optimal size of ComputedStyleBase is the total sum of all the |
| 297 # field sizes, rounded up to the nearest word. If this produces the | 313 # field sizes, rounded up to the nearest word. If this produces the |
| 298 # incorrect value, either the packing algorithm is not optimal or there | 314 # incorrect value, either the packing algorithm is not optimal or there |
| 299 # is no way to pack the fields such that excess padding space is not | 315 # is no way to pack the fields such that excess padding space is not |
| 300 # added. | 316 # added. |
| 301 # If this fails, increase extra_padding_bytes by 1, but be aware that | 317 # If this fails, increase extra_padding_bytes by 1, but be aware that |
| 302 # this also increases ComputedStyleBase by 1 word. | 318 # this also increases ComputedStyleBase by 1 word. |
| 303 # We should be able to bring extra_padding_bytes back to 0 from time to | 319 # We should be able to bring extra_padding_bytes back to 0 from time to |
| 304 # time. | 320 # time. |
| 305 extra_padding_bytes = 0 | 321 extra_padding_bytes = 0 |
| 306 optimal_total_field_bytes = int(math.ceil(sum(f.size for f in all_fields ) / 32.0)) | 322 optimal_bitfield_bytes = int(math.ceil(sum(f.size for f in packed_fields ) / 32.0)) |
| 307 real_total_field_bytes = optimal_total_field_bytes + extra_padding_bytes | 323 real_bitfield_bytes = optimal_bitfield_bytes + extra_padding_bytes |
| 308 assert self._expected_total_field_bytes == real_total_field_bytes, \ | 324 assert self._expected_bitfield_bytes == real_bitfield_bytes, \ |
| 309 ('The field packing algorithm produced %s bytes, optimal is %s bytes ' % | 325 ('The field packing algorithm produced %s bytes, optimal is %s bytes ' % |
| 310 (self._expected_total_field_bytes, real_total_field_bytes)) | 326 (self._expected_bitfield_bytes, real_bitfield_bytes)) |
| 327 | |
| 328 # Unpacked fields go first, then the packed fields. | |
| 329 self._fields = list(unpacked_fields) | |
| 311 | 330 |
| 312 # Order the fields so fields in each bucket are adjacent. | 331 # Order the fields so fields in each bucket are adjacent. |
| 313 self._fields = [] | |
| 314 for bucket in field_buckets: | 332 for bucket in field_buckets: |
| 315 for field in bucket: | 333 for field in bucket: |
| 316 self._fields.append(field) | 334 self._fields.append(field) |
| 317 | 335 |
| 318 | 336 |
| 319 @template_expander.use_jinja('ComputedStyleBase.h.tmpl') | 337 @template_expander.use_jinja('ComputedStyleBase.h.tmpl') |
| 320 def generate_base_computed_style_h(self): | 338 def generate_base_computed_style_h(self): |
| 321 return { | 339 return { |
| 322 'properties': self._properties, | 340 'properties': self._properties, |
| 323 'enums': self._generated_enums, | 341 'enums': self._generated_enums, |
| 324 'include_paths': _get_include_paths(self._properties.values()), | 342 'include_paths': _get_include_paths(self._properties.values()), |
| 325 'fields': self._fields, | 343 'fields': self._fields, |
| 326 'expected_total_field_bytes': self._expected_total_field_bytes, | |
| 327 } | 344 } |
| 328 | 345 |
| 329 @template_expander.use_jinja('ComputedStyleBase.cpp.tmpl') | 346 @template_expander.use_jinja('ComputedStyleBase.cpp.tmpl') |
| 330 def generate_base_computed_style_cpp(self): | 347 def generate_base_computed_style_cpp(self): |
| 331 return { | 348 return { |
| 332 'properties': self._properties, | 349 'properties': self._properties, |
| 333 'enums': self._generated_enums, | 350 'enums': self._generated_enums, |
| 334 'fields': self._fields, | 351 'fields': self._fields, |
| 335 'expected_total_field_bytes': self._expected_total_field_bytes, | 352 'expected_bitfield_bytes': self._expected_bitfield_bytes, |
| 336 } | 353 } |
| 337 | 354 |
| 338 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') | 355 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') |
| 339 def generate_base_computed_style_constants(self): | 356 def generate_base_computed_style_constants(self): |
| 340 return { | 357 return { |
| 341 'properties': self._properties, | 358 'properties': self._properties, |
| 342 'enums': self._generated_enums, | 359 'enums': self._generated_enums, |
| 343 'fields': self._fields, | 360 'fields': self._fields, |
| 344 'expected_total_field_bytes': self._expected_total_field_bytes, | |
| 345 } | 361 } |
| 346 | 362 |
| 347 if __name__ == '__main__': | 363 if __name__ == '__main__': |
| 348 json5_generator.Maker(ComputedStyleBaseWriter).main() | 364 json5_generator.Maker(ComputedStyleBaseWriter).main() |
| OLD | NEW |