Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: third_party/WebKit/Source/build/scripts/make_computed_style_base.py

Issue 2697953004: Add support for generating external types in ComputedStyleBase. (Closed)
Patch Set: remove unused macro Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 import make_style_builder 11 import make_style_builder
12 12
13 from name_utilities import ( 13 from name_utilities import (
14 enum_for_css_keyword, enum_type_name, enum_value_name, class_member_name, me thod_name 14 enum_for_css_keyword, enum_type_name, enum_value_name, class_member_name, me thod_name
15 ) 15 )
16 16
17 17
18 # Temporary hard-coded list of fields that are not CSS properties. 18 # Temporary hard-coded list of fields that are not CSS properties.
19 # TODO(shend): Put this into its own JSON5 file. 19 # TODO(shend): Put this into its own JSON5 file.
20 NONPROPERTIES = [ 20 NONPROPERTIES = [
21 {'name': 'IsLink', 'field_template': 'monotonic_flag', 21 {'name': 'IsLink', 'field_template': 'monotonic_flag',
22 'inherited': False, 'independent': False}, 22 'inherited': False, 'independent': False, 'default_value': False},
23 {'name': 'OriginalDisplay', 'field_template': 'keyword', 'initial_keyword': 'inline', 23 {'name': 'OriginalDisplay', 'field_template': 'keyword', 'default_value': 'i nline',
24 'type_name': 'EDisplay', 'inherited': False, 'independent': False, 24 'type_name': 'EDisplay', 'inherited': False, 'independent': False,
25 'keywords': [ 25 'keywords': [
26 "inline", "block", "list-item", "inline-block", "table", "inline-table" , "table-row-group", "table-header-group", 26 "inline", "block", "list-item", "inline-block", "table", "inline-table" , "table-row-group", "table-header-group",
27 "table-footer-group", "table-row", "table-column-group", "table-column" , "table-cell", "table-caption", "-webkit-box", 27 "table-footer-group", "table-row", "table-column-group", "table-column" , "table-cell", "table-caption", "-webkit-box",
28 "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "co ntents", "flow-root", "none" 28 "-webkit-inline-box", "flex", "inline-flex", "grid", "inline-grid", "co ntents", "flow-root", "none"
29 ]}, 29 ]},
30 {'name': 'InsideLink', 'field_template': 'keyword', 'initial_keyword': 'not- inside-link', 30 {'name': 'InsideLink', 'field_template': 'keyword', 'default_value': 'not-in side-link',
31 'keywords': ['not-inside-link', 'inside-unvisited-link', 'inside-visited-li nk'], 31 'keywords': ['not-inside-link', 'inside-unvisited-link', 'inside-visited-li nk'],
32 'inherited': True, 'independent': False}, 32 'inherited': True, 'independent': False},
33 # Style can not be shared. 33 # Style can not be shared.
34 {'name': 'Unique', 'field_template': 'monotonic_flag', 34 {'name': 'Unique', 'field_template': 'monotonic_flag',
35 'inherited': False, 'independent': False}, 35 'inherited': False, 'independent': False, 'default_value': False},
36 # Whether this style is affected by these pseudo-classes. 36 # Whether this style is affected by these pseudo-classes.
37 {'name': 'AffectedByFocus', 'field_template': 'monotonic_flag', 37 {'name': 'AffectedByFocus', 'field_template': 'monotonic_flag',
38 'inherited': False, 'independent': False}, 38 'inherited': False, 'independent': False, 'default_value': False},
39 {'name': 'AffectedByHover', 'field_template': 'monotonic_flag', 39 {'name': 'AffectedByHover', 'field_template': 'monotonic_flag',
40 'inherited': False, 'independent': False}, 40 'inherited': False, 'independent': False, 'default_value': False},
41 {'name': 'AffectedByActive', 'field_template': 'monotonic_flag', 41 {'name': 'AffectedByActive', 'field_template': 'monotonic_flag',
42 'inherited': False, 'independent': False}, 42 'inherited': False, 'independent': False, 'default_value': False},
43 {'name': 'AffectedByDrag', 'field_template': 'monotonic_flag', 43 {'name': 'AffectedByDrag', 'field_template': 'monotonic_flag',
44 'inherited': False, 'independent': False}, 44 'inherited': False, 'independent': False, 'default_value': False},
45 # A non-inherited property references a variable or @apply is used 45 # A non-inherited property references a variable or @apply is used
46 {'name': 'HasVariableReferenceFromNonInheritedProperty', 'field_template': ' monotonic_flag', 46 {'name': 'HasVariableReferenceFromNonInheritedProperty', 'field_template': ' monotonic_flag',
47 'inherited': False, 'independent': False}, 47 'inherited': False, 'independent': False, 'default_value': False},
48 # Explicitly inherits a non-inherited property 48 # Explicitly inherits a non-inherited property
49 {'name': 'HasExplicitlyInheritedProperties', 'field_template': 'monotonic_fl ag', 49 {'name': 'HasExplicitlyInheritedProperties', 'field_template': 'monotonic_fl ag',
50 'inherited': False, 'independent': False}, 50 'inherited': False, 'independent': False, 'default_value': False},
51 # These properties only have generated storage, and their methods are handwr itten in ComputedStyle. 51 # These properties only have generated storage, and their methods are handwr itten in ComputedStyle.
52 # TODO(shend): Remove these fields and delete the 'storage_only' template. 52 # TODO(shend): Remove these fields and delete the 'storage_only' template.
53 {'name': 'EmptyState', 'field_template': 'storage_only', 'size': 1, 'default _value': 'false', 53 {'name': 'EmptyState', 'field_template': 'storage_only', 'size': 1, 'default _value': 'false',
54 'type_name': 'bool', 'inherited': False, 'independent': False}, 54 'type_name': 'bool', 'inherited': False, 'independent': False},
55 {'name': 'StyleType', 'field_template': 'storage_only', 'size': 6, 'default_ value': '0', 55 {'name': 'StyleType', 'field_template': 'storage_only', 'size': 6, 'default_ value': '0',
56 'type_name': 'PseudoId', 'inherited': False, 'independent': False}, 56 'type_name': 'PseudoId', 'inherited': False, 'independent': False},
57 {'name': 'PseudoBits', 'field_template': 'storage_only', 'size': 8, 'default _value': 'PseudoIdNone', 57 {'name': 'PseudoBits', 'field_template': 'storage_only', 'size': 8, 'default _value': 'PseudoIdNone',
58 'type_name': 'PseudoId', 'inherited': False, 'independent': False}, 58 'type_name': 'PseudoId', 'inherited': False, 'independent': False},
59 # True if 'underline solid' is the only text decoration on this element. 59 # True if 'underline solid' is the only text decoration on this element.
60 {'name': 'HasSimpleUnderline', 'field_template': 'storage_only', 'size': 1, 'default_value': 'false', 60 {'name': 'HasSimpleUnderline', 'field_template': 'storage_only', 'size': 1, 'default_value': 'false',
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 115
116 self.is_inherited_method_name = method_name(name_for_methods + 'IsIn herited') 116 self.is_inherited_method_name = method_name(name_for_methods + 'IsIn herited')
117 117
118 # Method names 118 # Method names
119 getter_prefix = 'Get' if name_for_methods == self.type_name else '' 119 getter_prefix = 'Get' if name_for_methods == self.type_name else ''
120 self.getter_method_name = method_name(getter_prefix + name_for_methods) 120 self.getter_method_name = method_name(getter_prefix + name_for_methods)
121 self.setter_method_name = method_name('Set' + name_for_methods) 121 self.setter_method_name = method_name('Set' + name_for_methods)
122 self.initial_method_name = method_name('Initial' + name_for_methods) 122 self.initial_method_name = method_name('Initial' + name_for_methods)
123 self.resetter_method_name = method_name('Reset' + name_for_methods) 123 self.resetter_method_name = method_name('Reset' + name_for_methods)
124 124
125 # If the size of the field is not None, it means it is a bit field
126 self.is_bit_field = self.size is not None
127
125 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs) 128 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st r(kwargs)
126 129
127 130
128 def _get_include_paths(properties): 131 def _get_include_paths(properties):
129 """ 132 """
130 Get a list of paths that need to be included for ComputedStyleBase. 133 Get a list of paths that need to be included for ComputedStyleBase.
131 """ 134 """
132 include_paths = set() 135 include_paths = set()
133 for property_ in properties: 136 for property_ in properties:
134 if property_['field_type_path'] is not None: 137 if property_['field_type_path'] is not None:
(...skipping 25 matching lines...) Expand all
160 163
161 164
162 def _create_field(field_role, property_): 165 def _create_field(field_role, property_):
163 """ 166 """
164 Create a property or nonproperty field. 167 Create a property or nonproperty field.
165 """ 168 """
166 assert field_role in ('property', 'nonproperty') 169 assert field_role in ('property', 'nonproperty')
167 170
168 name_for_methods = property_['name_for_methods'] 171 name_for_methods = property_['name_for_methods']
169 172
173 assert property_['default_value'] is not None, \
174 ('MakeComputedStyleBase requires an default value for all fields, none s pecified '
175 'for property ' + property_['name'])
176
170 if property_['field_template'] == 'keyword': 177 if property_['field_template'] == 'keyword':
171 assert property_['initial_keyword'] is not None, \
172 ('MakeComputedStyleBase requires an initial keyword for keyword fiel ds, none specified '
173 'for property ' + property_['name'])
174 type_name = property_['type_name'] 178 type_name = property_['type_name']
175 default_value = type_name + '::' + enum_value_name(property_['initial_ke yword']) 179 default_value = type_name + '::' + enum_value_name(property_['default_va lue'])
176 size = int(math.ceil(math.log(len(property_['keywords']), 2))) 180 size = int(math.ceil(math.log(len(property_['keywords']), 2)))
177 elif property_['field_template'] == 'storage_only': 181 elif property_['field_template'] == 'storage_only':
178 # 'storage_only' fields need to specify a size, type_name and default_va lue 182 # 'storage_only' fields need to specify a size, type_name and default_va lue
179 type_name = property_['type_name'] 183 type_name = property_['type_name']
180 default_value = property_['default_value'] 184 default_value = property_['default_value']
181 size = property_['size'] 185 size = property_['size']
186 elif property_['field_template'] == 'external':
187 type_name = property_['type_name']
188 default_value = property_['default_value']
189 size = None
182 else: 190 else:
183 assert property_['field_template'] in ('flag', 'monotonic_flag') 191 assert property_['field_template'] in ('flag', 'monotonic_flag')
184 type_name = 'bool' 192 type_name = 'bool'
185 default_value = 'false' 193 default_value = 'false'
186 size = 1 194 size = 1
187 195
188 return Field( 196 return Field(
189 field_role, 197 field_role,
190 name_for_methods, 198 name_for_methods,
191 property_name=property_['name'], 199 property_name=property_['name'],
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 Group a list of fields into buckets to minimise padding. 245 Group a list of fields into buckets to minimise padding.
238 Returns a list of buckets, where each bucket is a list of Field objects. 246 Returns a list of buckets, where each bucket is a list of Field objects.
239 """ 247 """
240 # Since fields cannot cross word boundaries, in order to minimize 248 # Since fields cannot cross word boundaries, in order to minimize
241 # padding, group fields into buckets so that as many buckets as possible 249 # padding, group fields into buckets so that as many buckets as possible
242 # are exactly 32 bits. Although this greedy approach may not always 250 # are exactly 32 bits. Although this greedy approach may not always
243 # produce the optimal solution, we add a static_assert to the code to 251 # produce the optimal solution, we add a static_assert to the code to
244 # ensure ComputedStyleBase results in the expected size. If that 252 # ensure ComputedStyleBase results in the expected size. If that
245 # static_assert fails, this code is falling into the small number of 253 # static_assert fails, this code is falling into the small number of
246 # cases that are suboptimal, and may need to be rethought. 254 # cases that are suboptimal, and may need to be rethought.
247 # For more details on packing bitfields to reduce padding, see: 255 # For more details on packing bit fields to reduce padding, see:
248 # http://www.catb.org/esr/structure-packing/#_bitfields 256 # http://www.catb.org/esr/structure-packing/#_bitfields
249 field_buckets = [] 257 field_buckets = []
250 # Consider fields in descending order of size to reduce fragmentation 258 # Consider fields in descending order of size to reduce fragmentation
251 # when they are selected. 259 # when they are selected.
252 for field in sorted(fields, key=lambda f: f.size, reverse=True): 260 for field in sorted(fields, key=lambda f: f.size, reverse=True):
253 added_to_bucket = False 261 added_to_bucket = False
254 # Go through each bucket and add this field if it will not increase 262 # Go through each bucket and add this field if it will not increase
255 # the bucket's size to larger than 32 bits. Otherwise, make a new 263 # the bucket's size to larger than 32 bits. Otherwise, make a new
256 # bucket containing only this field. 264 # bucket containing only this field.
257 for bucket in field_buckets: 265 for bucket in field_buckets:
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 # Override the type name when field_type_path is specified 297 # Override the type name when field_type_path is specified
290 for property_ in property_values: 298 for property_ in property_values:
291 if property_['field_type_path']: 299 if property_['field_type_path']:
292 property_['type_name'] = property_['field_type_path'].split('/') [-1] 300 property_['type_name'] = property_['field_type_path'].split('/') [-1]
293 301
294 self._generated_enums = _create_enums(property_values + NONPROPERTIES) 302 self._generated_enums = _create_enums(property_values + NONPROPERTIES)
295 303
296 all_fields = (_create_fields('property', property_values) + 304 all_fields = (_create_fields('property', property_values) +
297 _create_fields('nonproperty', NONPROPERTIES)) 305 _create_fields('nonproperty', NONPROPERTIES))
298 306
299 # Group fields into buckets 307 # Separate the normal fields from the bit fields
300 field_buckets = _pack_fields(all_fields) 308 bit_fields = [field for field in all_fields if field.is_bit_field]
309 normal_fields = [field for field in all_fields if not field.is_bit_field ]
310
311 # Pack bit fields into buckets
312 field_buckets = _pack_fields(bit_fields)
301 313
302 # The expected size of ComputedStyleBase is equivalent to as many words 314 # The expected size of ComputedStyleBase is equivalent to as many words
303 # as the total number of buckets. 315 # as the total number of buckets.
304 self._expected_total_field_bytes = len(field_buckets) 316 self._expected_bit_field_bytes = len(field_buckets)
305 317
306 # The most optimal size of ComputedStyleBase is the total sum of all the 318 # The most optimal size of ComputedStyleBase is the total sum of all the
307 # field sizes, rounded up to the nearest word. If this produces the 319 # field sizes, rounded up to the nearest word. If this produces the
308 # incorrect value, either the packing algorithm is not optimal or there 320 # incorrect value, either the packing algorithm is not optimal or there
309 # is no way to pack the fields such that excess padding space is not 321 # is no way to pack the fields such that excess padding space is not
310 # added. 322 # added.
311 # If this fails, increase padding_bytes by 1, but be aware that 323 # If this fails, increase extra_padding_bytes by 1, but be aware that
312 # this also increases ComputedStyleBase by 1 word. 324 # this also increases ComputedStyleBase by 1 word.
313 # We should be able to bring padding_bytes back to 0 from time to 325 # We should be able to bring extra_padding_bytes back to 0 from time to
314 # time. 326 # time.
315 padding_bytes = 0 327 extra_padding_bytes = 0
316 optimal_total_field_bytes = int(math.ceil(sum(f.size for f in all_fields ) / 32.0)) 328 optimal_bit_field_bytes = int(math.ceil(sum(f.size for f in bit_fields) / 32.0))
317 real_total_field_bytes = optimal_total_field_bytes + padding_bytes 329 real_bit_field_bytes = optimal_bit_field_bytes + extra_padding_bytes
318 assert self._expected_total_field_bytes == real_total_field_bytes, \ 330 assert self._expected_bit_field_bytes == real_bit_field_bytes, \
319 ('The field packing algorithm produced %s bytes, optimal is %s bytes ' % 331 ('The field packing algorithm produced %s bytes, optimal is %s bytes ' %
320 (self._expected_total_field_bytes, real_total_field_bytes)) 332 (self._expected_bit_field_bytes, real_bit_field_bytes))
333
334 # Normal fields go first, then the bit fields.
335 self._fields = list(normal_fields)
321 336
322 # Order the fields so fields in each bucket are adjacent. 337 # Order the fields so fields in each bucket are adjacent.
323 self._fields = []
324 for bucket in field_buckets: 338 for bucket in field_buckets:
325 for field in bucket: 339 for field in bucket:
326 self._fields.append(field) 340 self._fields.append(field)
327 341
328 self._include_paths = _get_include_paths(property_values + NONPROPERTIES ) 342 self._include_paths = _get_include_paths(property_values + NONPROPERTIES )
329 343
330 344
331 @template_expander.use_jinja('ComputedStyleBase.h.tmpl') 345 @template_expander.use_jinja('ComputedStyleBase.h.tmpl')
332 def generate_base_computed_style_h(self): 346 def generate_base_computed_style_h(self):
333 return { 347 return {
334 'properties': self._properties, 348 'properties': self._properties,
335 'enums': self._generated_enums, 349 'enums': self._generated_enums,
336 'include_paths': self._include_paths, 350 'include_paths': self._include_paths,
337 'fields': self._fields, 351 'fields': self._fields,
338 'expected_total_field_bytes': self._expected_total_field_bytes,
339 } 352 }
340 353
341 @template_expander.use_jinja('ComputedStyleBase.cpp.tmpl') 354 @template_expander.use_jinja('ComputedStyleBase.cpp.tmpl')
342 def generate_base_computed_style_cpp(self): 355 def generate_base_computed_style_cpp(self):
343 return { 356 return {
344 'properties': self._properties, 357 'properties': self._properties,
345 'enums': self._generated_enums, 358 'enums': self._generated_enums,
346 'fields': self._fields, 359 'fields': self._fields,
347 'expected_total_field_bytes': self._expected_total_field_bytes, 360 'expected_bit_field_bytes': self._expected_bit_field_bytes,
348 } 361 }
349 362
350 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') 363 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl')
351 def generate_base_computed_style_constants(self): 364 def generate_base_computed_style_constants(self):
352 return { 365 return {
353 'properties': self._properties, 366 'properties': self._properties,
354 'enums': self._generated_enums, 367 'enums': self._generated_enums,
355 'fields': self._fields, 368 'fields': self._fields,
356 'expected_total_field_bytes': self._expected_total_field_bytes,
357 } 369 }
358 370
359 @template_expander.use_jinja('CSSValueIDMappingsGenerated.h.tmpl') 371 @template_expander.use_jinja('CSSValueIDMappingsGenerated.h.tmpl')
360 def generate_css_value_mappings(self): 372 def generate_css_value_mappings(self):
361 mappings = {} 373 mappings = {}
362 374
363 for property_ in self._properties.values(): 375 for property_ in self._properties.values():
364 if property_['field_template'] == 'keyword': 376 if property_['field_template'] == 'keyword':
365 mappings[property_['type_name']] = { 377 mappings[property_['type_name']] = {
366 'default_value': enum_value_name(property_['initial_keyword' ]), 378 'default_value': enum_value_name(property_['default_value']) ,
367 'mapping': [(enum_value_name(k), enum_for_css_keyword(k)) fo r k in property_['keywords']], 379 'mapping': [(enum_value_name(k), enum_for_css_keyword(k)) fo r k in property_['keywords']],
368 } 380 }
369 381
370 return { 382 return {
371 'include_paths': self._include_paths, 383 'include_paths': self._include_paths,
372 'mappings': mappings, 384 'mappings': mappings,
373 } 385 }
374 386
375 if __name__ == '__main__': 387 if __name__ == '__main__':
376 json5_generator.Maker(ComputedStyleBaseWriter).main() 388 json5_generator.Maker(ComputedStyleBaseWriter).main()
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.cpp.tmpl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698