| 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 28 matching lines...) Expand all Loading... |
| 39 class Field(object): | 39 class Field(object): |
| 40 """ | 40 """ |
| 41 The generated ComputedStyle object is made up of a series of Fields. | 41 The generated ComputedStyle object is made up of a series of Fields. |
| 42 Each Field has a name, size, type, etc, and a bunch of attributes to | 42 Each Field has a name, size, type, etc, and a bunch of attributes to |
| 43 determine which methods it will be used in. | 43 determine which methods it will be used in. |
| 44 | 44 |
| 45 A Field also has enough information to use any storage type in C++, such as | 45 A Field also has enough information to use any storage type in C++, such as |
| 46 regular member variables, or more complex storage like vectors or hashmaps. | 46 regular member variables, or more complex storage like vectors or hashmaps. |
| 47 Almost all properties will have at least one Field, often more than one. | 47 Almost all properties will have at least one Field, often more than one. |
| 48 | 48 |
| 49 Fields also fall into various roles, which determine the logic that is | 49 Most attributes in this class correspond to parameters in CSSProperties.json
5. |
| 50 used to generate them. The available field roles are: | 50 See that file for a more detailed explanation of each attribute. |
| 51 - 'property', for fields that store CSS properties | 51 |
| 52 - 'inherited_flag', for single-bit flags that store whether a property is | 52 Attributes: |
| 53 inherited by this style or set explicitly | 53 field_role: The semantic role of the field. Can be: |
| 54 - 'nonproperty', for fields that are not CSS properties | 54 - 'property': for fields that store CSS properties |
| 55 - 'inherited_flag': for single-bit flags that store whether a proper
ty is |
| 56 inherited by this style or set explicitly |
| 57 - 'nonproperty': for fields that are not CSS properties |
| 58 name_for_methods: String used to form the names of getters and setters. |
| 59 Should be in upper camel case. |
| 60 property_name: Name of the property that the field is part of. |
| 61 type_name: Name of the C++ type exposed by the generated interface (e.g.
EClear, int). |
| 62 field_template: Determines the interface generated for the field. Can be
one of: |
| 63 keyword, flag, or monotonic_flag. |
| 64 size: Number of bits needed for storage. |
| 65 default_value: Default value for this field when it is first initialized
. |
| 55 """ | 66 """ |
| 56 | 67 |
| 57 # List of required attributes for a field which need to be passed in by | 68 def __init__(self, field_role, name_for_methods, property_name, type_name, |
| 58 # keyword arguments. See CSSProperties.json5 for an explanation of each | 69 field_template, size, default_value, **kwargs): |
| 59 # attribute. | 70 """Creates a new field.""" |
| 60 REQUIRED_ATTRIBUTES = set([ | 71 self.name = class_member_name(name_for_methods) |
| 61 # Name of field | 72 self.property_name = property_name |
| 62 'name', | 73 self.type_name = type_name |
| 63 # Name of property field is for | 74 self.field_template = field_template |
| 64 'property_name', | 75 self.size = size |
| 65 # Name of the type (e.g. EClear, int) | 76 self.default_value = default_value |
| 66 'type_name', | |
| 67 # Affects how the field is generated (keyword, flag, monotonic_flag) | |
| 68 'field_template', | |
| 69 # Bits needed for storage | |
| 70 'size', | |
| 71 # Default value for field | |
| 72 'default_value', | |
| 73 # Method names | |
| 74 'getter_method_name', | |
| 75 'setter_method_name', | |
| 76 'initial_method_name', | |
| 77 'resetter_method_name', | |
| 78 ]) | |
| 79 | |
| 80 def __init__(self, field_role, **kwargs): | |
| 81 # Values common to all fields | |
| 82 # Set attributes from the keyword arguments | |
| 83 for attrib in Field.REQUIRED_ATTRIBUTES: | |
| 84 setattr(self, attrib, kwargs.pop(attrib)) | |
| 85 | 77 |
| 86 # Field role: one of these must be true | 78 # Field role: one of these must be true |
| 87 self.is_property = field_role == 'property' | 79 self.is_property = field_role == 'property' |
| 88 self.is_inherited_flag = field_role == 'inherited_flag' | 80 self.is_inherited_flag = field_role == 'inherited_flag' |
| 89 self.is_nonproperty = field_role == 'nonproperty' | 81 self.is_nonproperty = field_role == 'nonproperty' |
| 90 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c
ount(True) == 1, \ | 82 assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).c
ount(True) == 1, \ |
| 91 'Field role has to be exactly one of: property, inherited_flag, nonp
roperty' | 83 'Field role has to be exactly one of: property, inherited_flag, nonp
roperty' |
| 92 | 84 |
| 93 if self.is_property: | 85 if self.is_property: |
| 94 self.is_inherited = kwargs.pop('inherited') | 86 self.is_inherited = kwargs.pop('inherited') |
| 95 self.is_independent = kwargs.pop('independent') | 87 self.is_independent = kwargs.pop('independent') |
| 96 assert self.is_inherited or not self.is_independent, 'Only inherited
fields can be independent' | 88 assert self.is_inherited or not self.is_independent, 'Only inherited
fields can be independent' |
| 97 | 89 |
| 98 self.is_inherited_method_name = kwargs.pop('is_inherited_method_name
') | 90 self.is_inherited_method_name = method_name(name_for_methods + 'IsIn
herited') |
| 99 elif self.is_inherited_flag: | 91 |
| 100 # Inherited flag-only fields | 92 # Method names |
| 101 pass | 93 getter_prefix = 'Get' if name_for_methods == self.type_name else '' |
| 94 self.getter_method_name = method_name(getter_prefix + name_for_methods) |
| 95 self.setter_method_name = method_name('Set' + name_for_methods) |
| 96 self.initial_method_name = method_name('Initial' + name_for_methods) |
| 97 self.resetter_method_name = method_name('Reset' + name_for_methods) |
| 102 | 98 |
| 103 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st
r(kwargs) | 99 assert len(kwargs) == 0, 'Unexpected arguments provided to Field: ' + st
r(kwargs) |
| 104 | 100 |
| 105 | 101 |
| 106 def _get_include_paths(properties): | 102 def _get_include_paths(properties): |
| 107 """ | 103 """ |
| 108 Get a list of paths that need to be included for ComputedStyleBase. | 104 Get a list of paths that need to be included for ComputedStyleBase. |
| 109 """ | 105 """ |
| 110 include_paths = set() | 106 include_paths = set() |
| 111 for property_ in properties: | 107 for property_ in properties: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 134 | 130 |
| 135 enums[enum_name] = enum_values | 131 enums[enum_name] = enum_values |
| 136 | 132 |
| 137 return enums | 133 return enums |
| 138 | 134 |
| 139 | 135 |
| 140 def _create_property_field(property_): | 136 def _create_property_field(property_): |
| 141 """ | 137 """ |
| 142 Create a property field from a CSS property and return the Field object. | 138 Create a property field from a CSS property and return the Field object. |
| 143 """ | 139 """ |
| 144 name_for_methods = property_['name_for_methods'] | |
| 145 | |
| 146 bits_needed = math.log(len(property_['keywords']), 2) # TODO: implement for
non-enums | 140 bits_needed = math.log(len(property_['keywords']), 2) # TODO: implement for
non-enums |
| 147 type_name = property_['type_name'] | 141 type_name = property_['type_name'] |
| 148 | 142 |
| 149 # For now, the getter name should match the field name. Later, getter names | |
| 150 # will start with an uppercase letter, so if they conflict with the type nam
e, | |
| 151 # add 'get' to the front. | |
| 152 if type_name != name_for_methods: | |
| 153 getter_method_name = method_name(name_for_methods) | |
| 154 else: | |
| 155 getter_method_name = method_name('get-' + name_for_methods) | |
| 156 | |
| 157 assert property_['initial_keyword'] is not None, \ | 143 assert property_['initial_keyword'] is not None, \ |
| 158 ('MakeComputedStyleBase requires an initial keyword for keyword fields,
none specified ' | 144 ('MakeComputedStyleBase requires an initial keyword for keyword fields,
none specified ' |
| 159 'for property ' + property_['name']) | 145 'for property ' + property_['name']) |
| 160 default_value = type_name + '::' + enum_value_name(property_['initial_keywor
d']) | 146 default_value = type_name + '::' + enum_value_name(property_['initial_keywor
d']) |
| 161 | 147 |
| 162 return Field( | 148 return Field( |
| 163 'property', | 149 'property', |
| 164 name=class_member_name(name_for_methods), | 150 property_['name_for_methods'], |
| 165 property_name=property_['name'], | 151 property_name=property_['name'], |
| 166 inherited=property_['inherited'], | 152 inherited=property_['inherited'], |
| 167 independent=property_['independent'], | 153 independent=property_['independent'], |
| 168 type_name=type_name, | 154 type_name=type_name, |
| 169 field_template=property_['field_template'], | 155 field_template=property_['field_template'], |
| 170 size=int(math.ceil(bits_needed)), | 156 size=int(math.ceil(bits_needed)), |
| 171 default_value=default_value, | 157 default_value=default_value, |
| 172 getter_method_name=getter_method_name, | |
| 173 setter_method_name=method_name('set-' + name_for_methods), | |
| 174 initial_method_name=method_name('initial-' + name_for_methods), | |
| 175 resetter_method_name=method_name('reset-' + name_for_methods), | |
| 176 is_inherited_method_name=method_name(name_for_methods + '-IsInherited'), | |
| 177 ) | 158 ) |
| 178 | 159 |
| 179 | 160 |
| 180 def _create_inherited_flag_field(property_): | 161 def _create_inherited_flag_field(property_): |
| 181 """ | 162 """ |
| 182 Create the field used for an inheritance fast path from an independent CSS p
roperty, | 163 Create the field used for an inheritance fast path from an independent CSS p
roperty, |
| 183 and return the Field object. | 164 and return the Field object. |
| 184 """ | 165 """ |
| 185 name_for_methods = property_['name_for_methods'] | |
| 186 name_for_methods_suffixed = name_for_methods + 'IsInherited' | |
| 187 | |
| 188 return Field( | 166 return Field( |
| 189 'inherited_flag', | 167 'inherited_flag', |
| 190 name=class_member_name(name_for_methods_suffixed), | 168 property_['name_for_methods'] + 'IsInherited', |
| 191 property_name=property_['name'], | 169 property_name=property_['name'], |
| 192 type_name='bool', | 170 type_name='bool', |
| 193 field_template='flag', | 171 field_template='flag', |
| 194 size=1, | 172 size=1, |
| 195 default_value='true', | 173 default_value='true', |
| 196 getter_method_name=method_name(name_for_methods_suffixed), | |
| 197 setter_method_name=method_name('set-' + name_for_methods_suffixed), | |
| 198 initial_method_name=method_name('initial-' + name_for_methods_suffixed), | |
| 199 resetter_method_name=method_name('reset-' + name_for_methods_suffixed), | |
| 200 ) | 174 ) |
| 201 | 175 |
| 202 | 176 |
| 203 def _create_nonproperty_field(property_): | 177 def _create_nonproperty_field(property_): |
| 204 """ | 178 """ |
| 205 Create a nonproperty field from an entry in NONPROPERTY_FIELDS and return th
e Field object. | 179 Create a nonproperty field from an entry in NONPROPERTY_FIELDS and return th
e Field object. |
| 206 """ | 180 """ |
| 207 # TODO(shend): Make this work for nonflags | 181 # TODO(shend): Make this work for nonflags |
| 208 assert property_['field_template'] in ('flag', 'monotonic_flag', 'storage_on
ly'), \ | 182 assert property_['field_template'] in ('flag', 'monotonic_flag', 'storage_on
ly'), \ |
| 209 "Nonproperties with arbitrary templates are not yet supported" | 183 "Nonproperties with arbitrary templates are not yet supported" |
| 210 name_for_methods = property_['name_for_methods'] | |
| 211 | 184 |
| 212 if property_['field_template'] == 'storage_only': | 185 if property_['field_template'] == 'storage_only': |
| 213 assert 'size' in property_, 'storage_only fields need to specify a size' | 186 assert 'size' in property_, 'storage_only fields need to specify a size' |
| 214 size = property_['size'] | 187 size = property_['size'] |
| 215 else: | 188 else: |
| 216 # Otherwise the field must be some type of flag. | 189 # Otherwise the field must be some type of flag. |
| 217 size = 1 | 190 size = 1 |
| 218 | 191 |
| 219 return Field( | 192 return Field( |
| 220 'nonproperty', | 193 'nonproperty', |
| 221 name=class_member_name(name_for_methods), | 194 property_['name_for_methods'], |
| 222 property_name=name_for_methods, | 195 property_name=property_['name'], |
| 223 type_name='bool', | 196 type_name='bool', |
| 224 field_template=property_['field_template'], | 197 field_template=property_['field_template'], |
| 225 size=size, | 198 size=size, |
| 226 default_value='false', | 199 default_value='false', |
| 227 getter_method_name=method_name(name_for_methods), | |
| 228 setter_method_name=method_name('set-' + name_for_methods), | |
| 229 initial_method_name=method_name('initial-' + name_for_methods), | |
| 230 resetter_method_name=method_name('reset-' + name_for_methods), | |
| 231 ) | 200 ) |
| 232 | 201 |
| 233 | 202 |
| 234 def _create_fields(properties): | 203 def _create_fields(properties): |
| 235 """ | 204 """ |
| 236 Create ComputedStyle fields from CSS properties and return a list of Field o
bjects. | 205 Create ComputedStyle fields from CSS properties and return a list of Field o
bjects. |
| 237 """ | 206 """ |
| 238 fields = [] | 207 fields = [] |
| 239 for property_ in properties: | 208 for property_ in properties: |
| 240 # Only generate properties that have a field template | 209 # Only generate properties that have a field template |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 'mapping': [(enum_value_name(k), enum_for_css_keyword(k)) fo
r k in property_['keywords']], | 351 'mapping': [(enum_value_name(k), enum_for_css_keyword(k)) fo
r k in property_['keywords']], |
| 383 } | 352 } |
| 384 | 353 |
| 385 return { | 354 return { |
| 386 'include_paths': self._include_paths, | 355 'include_paths': self._include_paths, |
| 387 'mappings': mappings, | 356 'mappings': mappings, |
| 388 } | 357 } |
| 389 | 358 |
| 390 if __name__ == '__main__': | 359 if __name__ == '__main__': |
| 391 json5_generator.Maker(ComputedStyleBaseWriter).main() | 360 json5_generator.Maker(ComputedStyleBaseWriter).main() |
| OLD | NEW |