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 |