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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 self.fields = fields | 66 self.fields = fields |
67 self.type_name = class_name(join_name('style', name, 'data')) | 67 self.type_name = class_name(join_name('style', name, 'data')) |
68 self.member_name = class_member_name(join_name(name, 'data')) | 68 self.member_name = class_member_name(join_name(name, 'data')) |
69 self.num_32_bit_words_for_bit_fields = _num_32_bit_words_for_bit_fields( | 69 self.num_32_bit_words_for_bit_fields = _num_32_bit_words_for_bit_fields( |
70 field for field in fields if field.is_bit_field | 70 field for field in fields if field.is_bit_field |
71 ) | 71 ) |
72 | 72 |
73 # Recursively get all the fields in the subgroups as well | 73 # Recursively get all the fields in the subgroups as well |
74 self.all_fields = _flatten_list(subgroup.all_fields for subgroup in subg
roups) + fields | 74 self.all_fields = _flatten_list(subgroup.all_fields for subgroup in subg
roups) + fields |
75 | 75 |
| 76 # Link group |
| 77 for field in fields: |
| 78 field.group = self |
| 79 |
76 | 80 |
77 class DiffGroup(object): | 81 class DiffGroup(object): |
78 """Represents a group of expressions and subgroups that need to be diffed | 82 """Represents a group of expressions and subgroups that need to be diffed |
79 for a function in ComputedStyle. | 83 for a function in ComputedStyle. |
80 | 84 |
81 Attributes: | 85 Attributes: |
82 subgroups: List of DiffGroup instances that are stored as subgroups unde
r this group. | 86 subgroups: List of DiffGroup instances that are stored as subgroups unde
r this group. |
83 expressions: List of expression that are on this group that need to be d
iffed. | 87 expressions: List of expression that are on this group that need to be d
iffed. |
84 """ | 88 """ |
85 def __init__(self, group_name): | 89 def __init__(self, group_name): |
86 self.group_name = group_name | 90 self.group_name = group_name |
87 self.subgroups = [] | 91 self.subgroups = [] |
| 92 self.fields = [] |
88 self.expressions = [] | 93 self.expressions = [] |
89 self.predicates = [] | 94 self.predicates = [] |
90 | 95 |
91 | 96 |
92 class Field(object): | 97 class Field(object): |
93 """ | 98 """ |
94 The generated ComputedStyle object is made up of a series of Fields. | 99 The generated ComputedStyle object is made up of a series of Fields. |
95 Each Field has a name, size, type, etc, and a bunch of attributes to | 100 Each Field has a name, size, type, etc, and a bunch of attributes to |
96 determine which methods it will be used in. | 101 determine which methods it will be used in. |
97 | 102 |
98 A Field also has enough information to use any storage type in C++, such as | 103 A Field also has enough information to use any storage type in C++, such as |
99 regular member variables, or more complex storage like vectors or hashmaps. | 104 regular member variables, or more complex storage like vectors or hashmaps. |
100 Almost all properties will have at least one Field, often more than one. | 105 Almost all properties will have at least one Field, often more than one. |
101 | 106 |
102 Most attributes in this class correspond to parameters in CSSProperties.json
5. | 107 Most attributes in this class correspond to parameters in CSSProperties.json
5. |
103 See that file for a more detailed explanation of each attribute. | 108 See that file for a more detailed explanation of each attribute. |
104 | 109 |
105 Attributes: | 110 Attributes: |
106 field_role: The semantic role of the field. Can be: | 111 field_role: The semantic role of the field. Can be: |
107 - 'property': for fields that store CSS properties | 112 - 'property': for fields that store CSS properties |
108 - 'inherited_flag': for single-bit flags that store whether a proper
ty is | 113 - 'inherited_flag': for single-bit flags that store whether a proper
ty is |
109 inherited by this style or set explicitly | 114 inherited by this style or set explicitly |
110 name_for_methods: String used to form the names of getters and setters. | 115 name_for_methods: String used to form the names of getters and setters. |
111 Should be in upper camel case. | 116 Should be in upper camel case. |
112 property_name: Name of the property that the field is part of. | 117 property_name: Name of the property that the field is part of. |
113 type_name: Name of the C++ type exposed by the generated interface (e.g.
EClear, int). | 118 type_name: Name of the C++ type exposed by the generated interface (e.g.
EClear, int). |
114 wrapper_pointer_name: Name of the pointer type that wraps this field (e.
g. RefPtr). | 119 wrapper_pointer_name: Name of the pointer type that wraps this field (e.
g. RefPtr). |
115 field_template: Determines the interface generated for the field. Can be
one of: | 120 field_template: Determines the interface generated for the field. Can be
one of: |
116 keyword, flag, or monotonic_flag. | 121 keyword, flag, or monotonic_flag. |
117 field_group: The name of the group that this field is inside. | |
118 size: Number of bits needed for storage. | 122 size: Number of bits needed for storage. |
119 default_value: Default value for this field when it is first initialized
. | 123 default_value: Default value for this field when it is first initialized
. |
120 """ | 124 """ |
121 | 125 |
122 def __init__(self, field_role, name_for_methods, property_name, type_name, w
rapper_pointer_name, | 126 def __init__(self, field_role, name_for_methods, property_name, type_name, w
rapper_pointer_name, |
123 field_template, field_group, size, default_value, custom_copy,
custom_compare, | 127 field_template, size, default_value, custom_copy, custom_compar
e, |
124 getter_method_name, setter_method_name, initial_method_name, **
kwargs): | 128 getter_method_name, setter_method_name, initial_method_name, **
kwargs): |
125 """Creates a new field.""" | 129 """Creates a new field.""" |
126 self.name = class_member_name(name_for_methods) | 130 self.name = class_member_name(name_for_methods) |
127 self.property_name = property_name | 131 self.property_name = property_name |
128 self.type_name = type_name | 132 self.type_name = type_name |
129 self.wrapper_pointer_name = wrapper_pointer_name | 133 self.wrapper_pointer_name = wrapper_pointer_name |
130 self.alignment_type = self.wrapper_pointer_name or self.type_name | 134 self.alignment_type = self.wrapper_pointer_name or self.type_name |
131 self.field_template = field_template | 135 self.field_template = field_template |
132 self.group_name = field_group | |
133 self.group_member_name = class_member_name(join_name(field_group, 'data'
)) if field_group else None | |
134 self.size = size | 136 self.size = size |
135 self.default_value = default_value | 137 self.default_value = default_value |
136 self.custom_copy = custom_copy | 138 self.custom_copy = custom_copy |
137 self.custom_compare = custom_compare | 139 self.custom_compare = custom_compare |
| 140 self.group = None |
138 | 141 |
139 # Field role: one of these must be true | 142 # Field role: one of these must be true |
140 self.is_property = field_role == 'property' | 143 self.is_property = field_role == 'property' |
141 self.is_inherited_flag = field_role == 'inherited_flag' | 144 self.is_inherited_flag = field_role == 'inherited_flag' |
142 assert (self.is_property, self.is_inherited_flag).count(True) == 1, \ | 145 assert (self.is_property, self.is_inherited_flag).count(True) == 1, \ |
143 'Field role has to be exactly one of: property, inherited_flag' | 146 'Field role has to be exactly one of: property, inherited_flag' |
144 | 147 |
145 if not self.is_inherited_flag: | 148 if not self.is_inherited_flag: |
146 self.is_inherited = kwargs.pop('inherited') | 149 self.is_inherited = kwargs.pop('inherited') |
147 self.is_independent = kwargs.pop('independent') | 150 self.is_independent = kwargs.pop('independent') |
148 assert self.is_inherited or not self.is_independent, 'Only inherited
fields can be independent' | 151 assert self.is_inherited or not self.is_independent, 'Only inherited
fields can be independent' |
149 | 152 |
150 self.is_inherited_method_name = method_name(join_name(name_for_metho
ds, 'is inherited')) | 153 self.is_inherited_method_name = method_name(join_name(name_for_metho
ds, 'is inherited')) |
151 | 154 |
152 # Method names | 155 # Method names |
153 # TODO(nainar): Method name generation is inconsistent. Fix. | 156 # TODO(nainar): Method name generation is inconsistent. Fix. |
154 self.getter_method_name = getter_method_name | 157 self.getter_method_name = getter_method_name |
155 self.setter_method_name = setter_method_name | 158 self.setter_method_name = setter_method_name |
156 self.internal_getter_method_name = method_name(join_name(self.name, 'Int
ernal')) | 159 self.internal_getter_method_name = method_name(join_name(self.name, 'Int
ernal')) |
157 self.internal_mutable_method_name = method_name(join_name('Mutable', nam
e_for_methods, 'Internal')) | 160 self.internal_mutable_method_name = method_name(join_name('Mutable', nam
e_for_methods, 'Internal')) |
158 self.internal_setter_method_name = method_name(join_name(setter_method_n
ame, 'Internal')) | 161 self.internal_setter_method_name = method_name(join_name(setter_method_n
ame, 'Internal')) |
159 self.initial_method_name = initial_method_name | 162 self.initial_method_name = initial_method_name |
160 self.resetter_method_name = method_name(join_name('Reset', name_for_meth
ods)) | 163 self.resetter_method_name = method_name(join_name('Reset', name_for_meth
ods)) |
161 if self.group_name: | |
162 self.getter_expression = self.group_member_name + '->' + class_membe
r_name(self.name) | |
163 else: | |
164 self.getter_expression = class_member_name(self.name) | |
165 | 164 |
166 # If the size of the field is not None, it means it is a bit field | 165 # If the size of the field is not None, it means it is a bit field |
167 self.is_bit_field = self.size is not None | 166 self.is_bit_field = self.size is not None |
168 | 167 |
169 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st
r(kwargs) | 168 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st
r(kwargs) |
170 | 169 |
171 | 170 |
172 def _get_include_paths(properties): | 171 def _get_include_paths(properties): |
173 """ | 172 """ |
174 Get a list of paths that need to be included for ComputedStyleBase. | 173 Get a list of paths that need to be included for ComputedStyleBase. |
175 """ | 174 """ |
176 include_paths = set() | 175 include_paths = set() |
177 for property_ in properties: | 176 for property_ in properties: |
178 include_paths.update(property_['include_paths']) | 177 include_paths.update(property_['include_paths']) |
179 return list(sorted(include_paths)) | 178 return list(sorted(include_paths)) |
180 | 179 |
181 | 180 |
182 def _group_fields(fields): | 181 def _create_groups(properties): |
183 """Groups a list of fields by their group_name and returns the root group.""
" | 182 """Groups a list of fields by their group_name and returns the root group.""
" |
184 groups = defaultdict(list) | 183 groups = defaultdict(list) |
185 for field in fields: | 184 for property_ in properties: |
186 groups[field.group_name].append(field) | 185 groups[property_['field_group']].extend(_create_fields(property_)) |
187 | 186 |
188 no_group = groups.pop(None) | 187 no_group = groups.pop(None) |
189 subgroups = [Group(group_name, [], _reorder_fields(fields)) for group_name,
fields in groups.items()] | 188 subgroups = [Group(group_name, [], _reorder_fields(fields)) for group_name,
fields in groups.items()] |
190 return Group('', subgroups=subgroups, fields=_reorder_fields(no_group)) | 189 return Group('', subgroups=subgroups, fields=_reorder_fields(no_group)) |
191 | 190 |
192 | 191 |
193 def _create_diff_groups_map(diff_function_inputs, root_group): | 192 def _create_diff_groups_map(diff_function_inputs, root_group): |
194 diff_functions_map = {} | 193 diff_functions_map = {} |
195 for entry in diff_function_inputs: | 194 for entry in diff_function_inputs: |
196 diff_functions_map[entry['name']] = _create_diff_groups(entry['fields_to
_diff'], | 195 diff_functions_map[entry['name']] = _create_diff_groups(entry['fields_to
_diff'], |
(...skipping 10 matching lines...) Expand all Loading... |
207 | 206 |
208 def _create_diff_groups(fields_to_diff, methods_to_diff, predicates_to_test, roo
t_group): | 207 def _create_diff_groups(fields_to_diff, methods_to_diff, predicates_to_test, roo
t_group): |
209 diff_group = DiffGroup(root_group.member_name) | 208 diff_group = DiffGroup(root_group.member_name) |
210 field_dependencies = _list_field_dependencies(methods_to_diff + predicates_t
o_test) | 209 field_dependencies = _list_field_dependencies(methods_to_diff + predicates_t
o_test) |
211 for subgroup in root_group.subgroups: | 210 for subgroup in root_group.subgroups: |
212 if any(field.property_name in (fields_to_diff + field_dependencies) for
field in subgroup.all_fields): | 211 if any(field.property_name in (fields_to_diff + field_dependencies) for
field in subgroup.all_fields): |
213 diff_group.subgroups.append(_create_diff_groups(fields_to_diff, meth
ods_to_diff, predicates_to_test, subgroup)) | 212 diff_group.subgroups.append(_create_diff_groups(fields_to_diff, meth
ods_to_diff, predicates_to_test, subgroup)) |
214 for entry in fields_to_diff: | 213 for entry in fields_to_diff: |
215 for field in root_group.fields: | 214 for field in root_group.fields: |
216 if not field.is_inherited_flag and entry == field.property_name: | 215 if not field.is_inherited_flag and entry == field.property_name: |
217 diff_group.expressions.append(field.getter_expression) | 216 diff_group.fields.append(field) |
218 for entry in methods_to_diff: | 217 for entry in methods_to_diff: |
219 for field in root_group.fields: | 218 for field in root_group.fields: |
220 if not field.is_inherited_flag and field.property_name in entry['fie
ld_dependencies']: | 219 if not field.is_inherited_flag and field.property_name in entry['fie
ld_dependencies']: |
221 diff_group.expressions.append(entry['method']) | 220 diff_group.expressions.append(entry['method']) |
222 for entry in predicates_to_test: | 221 for entry in predicates_to_test: |
223 for field in root_group.fields: | 222 for field in root_group.fields: |
224 if not field.is_inherited_flag and field.property_name in entry['fie
ld_dependencies']: | 223 if not field.is_inherited_flag and field.property_name in entry['fie
ld_dependencies']: |
225 diff_group.predicates.append(entry['predicate']) | 224 diff_group.predicates.append(entry['predicate']) |
226 return diff_group | 225 return diff_group |
227 | 226 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 | 288 |
290 return Field( | 289 return Field( |
291 'property', | 290 'property', |
292 name_for_methods, | 291 name_for_methods, |
293 property_name=property_['name'], | 292 property_name=property_['name'], |
294 inherited=property_['inherited'], | 293 inherited=property_['inherited'], |
295 independent=property_['independent'], | 294 independent=property_['independent'], |
296 type_name=type_name, | 295 type_name=type_name, |
297 wrapper_pointer_name=property_['wrapper_pointer_name'], | 296 wrapper_pointer_name=property_['wrapper_pointer_name'], |
298 field_template=property_['field_template'], | 297 field_template=property_['field_template'], |
299 field_group=property_['field_group'], | |
300 size=size, | 298 size=size, |
301 default_value=default_value, | 299 default_value=default_value, |
302 custom_copy=property_['custom_copy'], | 300 custom_copy=property_['custom_copy'], |
303 custom_compare=property_['custom_compare'], | 301 custom_compare=property_['custom_compare'], |
304 getter_method_name=property_['getter'], | 302 getter_method_name=property_['getter'], |
305 setter_method_name=property_['setter'], | 303 setter_method_name=property_['setter'], |
306 initial_method_name=property_['initial'], | 304 initial_method_name=property_['initial'], |
307 ) | 305 ) |
308 | 306 |
309 | 307 |
310 def _create_inherited_flag_field(property_): | 308 def _create_inherited_flag_field(property_): |
311 """ | 309 """ |
312 Create the field used for an inheritance fast path from an independent CSS p
roperty, | 310 Create the field used for an inheritance fast path from an independent CSS p
roperty, |
313 and return the Field object. | 311 and return the Field object. |
314 """ | 312 """ |
315 name_for_methods = join_name(property_['name_for_methods'], 'is inherited') | 313 name_for_methods = join_name(property_['name_for_methods'], 'is inherited') |
316 return Field( | 314 return Field( |
317 'inherited_flag', | 315 'inherited_flag', |
318 name_for_methods, | 316 name_for_methods, |
319 property_name=property_['name'], | 317 property_name=property_['name'], |
320 type_name='bool', | 318 type_name='bool', |
321 wrapper_pointer_name=None, | 319 wrapper_pointer_name=None, |
322 field_template='primitive', | 320 field_template='primitive', |
323 field_group=property_['field_group'], | |
324 size=1, | 321 size=1, |
325 default_value='true', | 322 default_value='true', |
326 custom_copy=False, | 323 custom_copy=False, |
327 custom_compare=False, | 324 custom_compare=False, |
328 getter_method_name=method_name(name_for_methods), | 325 getter_method_name=method_name(name_for_methods), |
329 setter_method_name=method_name(join_name('set', name_for_methods)), | 326 setter_method_name=method_name(join_name('set', name_for_methods)), |
330 initial_method_name=method_name(join_name('initial', name_for_methods)), | 327 initial_method_name=method_name(join_name('initial', name_for_methods)), |
331 ) | 328 ) |
332 | 329 |
333 | 330 |
334 def _create_fields(properties): | 331 def _create_fields(property_): |
335 """ | 332 """ |
336 Create ComputedStyle fields from properties and return a list of Field objec
ts. | 333 Create ComputedStyle fields from a property and return a list of Field objec
ts. |
337 """ | 334 """ |
338 fields = [] | 335 fields = [] |
339 for property_ in properties: | 336 # Only generate properties that have a field template |
340 # Only generate properties that have a field template | 337 if property_['field_template'] is not None: |
341 if property_['field_template'] is not None: | 338 # If the property is independent, add the single-bit sized isInherited f
lag |
342 # If the property is independent, add the single-bit sized isInherit
ed flag | 339 # to the list of Fields as well. |
343 # to the list of Fields as well. | 340 if property_['independent']: |
344 if property_['independent']: | 341 fields.append(_create_inherited_flag_field(property_)) |
345 fields.append(_create_inherited_flag_field(property_)) | |
346 | 342 |
347 fields.append(_create_property_field(property_)) | 343 fields.append(_create_property_field(property_)) |
348 | 344 |
349 return fields | 345 return fields |
350 | 346 |
351 | 347 |
352 def _reorder_bit_fields(bit_fields): | 348 def _reorder_bit_fields(bit_fields): |
353 # Since fields cannot cross word boundaries, in order to minimize | 349 # Since fields cannot cross word boundaries, in order to minimize |
354 # padding, group fields into buckets so that as many buckets as possible | 350 # padding, group fields into buckets so that as many buckets as possible |
355 # are exactly 32 bits. Although this greedy approach may not always | 351 # are exactly 32 bits. Although this greedy approach may not always |
356 # produce the optimal solution, we add a static_assert to the code to | 352 # produce the optimal solution, we add a static_assert to the code to |
357 # ensure ComputedStyleBase results in the expected size. If that | 353 # ensure ComputedStyleBase results in the expected size. If that |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 default_parameters=self.json5_file.parameters | 419 default_parameters=self.json5_file.parameters |
424 ).name_dictionaries | 420 ).name_dictionaries |
425 | 421 |
426 for property_ in extra_fields: | 422 for property_ in extra_fields: |
427 make_style_builder.apply_property_naming_defaults(property_) | 423 make_style_builder.apply_property_naming_defaults(property_) |
428 | 424 |
429 all_properties = css_properties + extra_fields | 425 all_properties = css_properties + extra_fields |
430 | 426 |
431 self._generated_enums = _create_enums(all_properties) | 427 self._generated_enums = _create_enums(all_properties) |
432 | 428 |
433 all_fields = _create_fields(all_properties) | |
434 | |
435 # Organise fields into a tree structure where the root group | 429 # Organise fields into a tree structure where the root group |
436 # is ComputedStyleBase. | 430 # is ComputedStyleBase. |
437 self._root_group = _group_fields(all_fields) | 431 self._root_group = _create_groups(all_properties) |
438 self._diff_functions_map = _create_diff_groups_map(json5_generator.Json5
File.load_from_files( | 432 self._diff_functions_map = _create_diff_groups_map(json5_generator.Json5
File.load_from_files( |
439 [json5_file_paths[2]] | 433 [json5_file_paths[2]] |
440 ).name_dictionaries, self._root_group) | 434 ).name_dictionaries, self._root_group) |
441 | 435 |
442 self._include_paths = _get_include_paths(all_properties) | 436 self._include_paths = _get_include_paths(all_properties) |
443 self._outputs = { | 437 self._outputs = { |
444 'ComputedStyleBase.h': self.generate_base_computed_style_h, | 438 'ComputedStyleBase.h': self.generate_base_computed_style_h, |
445 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, | 439 'ComputedStyleBase.cpp': self.generate_base_computed_style_cpp, |
446 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_co
nstants, | 440 'ComputedStyleBaseConstants.h': self.generate_base_computed_style_co
nstants, |
447 } | 441 } |
(...skipping 20 matching lines...) Expand all Loading... |
468 | 462 |
469 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') | 463 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') |
470 def generate_base_computed_style_constants(self): | 464 def generate_base_computed_style_constants(self): |
471 return { | 465 return { |
472 'properties': self._properties, | 466 'properties': self._properties, |
473 'enums': self._generated_enums, | 467 'enums': self._generated_enums, |
474 } | 468 } |
475 | 469 |
476 if __name__ == '__main__': | 470 if __name__ == '__main__': |
477 json5_generator.Maker(ComputedStyleBaseWriter).main() | 471 json5_generator.Maker(ComputedStyleBaseWriter).main() |
OLD | NEW |