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 |