| 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 |