1# Copyright 2017 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from itertools import chain 6 7from blinkbuild.name_style_converter import NameStyleConverter 8 9 10def _flatten_list(x): 11 """Flattens a list of lists into a single list.""" 12 return list(chain.from_iterable(x)) 13 14 15def _num_32_bit_words_for_bit_fields(bit_fields): 16 """ 17 Gets the number of 32 bit unsigned ints needed store a list of bit fields. 18 """ 19 num_buckets, cur_bucket = 0, 0 20 for field in bit_fields: 21 if field.size + cur_bucket > 32: 22 num_buckets += 1 23 cur_bucket = 0 24 cur_bucket += field.size 25 return num_buckets + (cur_bucket > 0) 26 27 28class Group(object): 29 """Represents a group of fields stored together in a class. 30 31 Attributes: 32 name: The name of the group as a string, or None. 33 subgroups: List of Group instances that are stored as subgroups under 34 this group. 35 fields: List of Field instances stored directly under this group. 36 parent: The parent group, or None if this is the root group. 37 """ 38 39 def __init__(self, name, subgroups, fields): 40 self.name = name 41 self.subgroups = subgroups 42 self.fields = fields 43 self.parent = None 44 45 converter = NameStyleConverter(name or '') 46 self.type_name = converter.to_class_name(prefix='style', suffix='data') 47 self.member_name = converter.to_class_data_member(suffix='data') 48 self.num_32_bit_words_for_bit_fields = _num_32_bit_words_for_bit_fields( 49 field for field in fields if field.is_bit_field) 50 51 # Recursively get all the fields in the subgroups as well 52 self.all_fields = _flatten_list(subgroup.all_fields 53 for subgroup in subgroups) + fields 54 55 # Ensure that all fields/subgroups on this group link to it 56 for field in fields: 57 field.group = self 58 59 for subgroup in subgroups: 60 subgroup.parent = self 61 62 def path_without_root(self): 63 """Return list of ancestor groups, excluding the root group. 64 65 The first item is the current group, second item is the parent, third 66 is the grandparent and so on. 67 """ 68 group_path = [] 69 current_group = self 70 while current_group.name: 71 group_path.insert(0, current_group) 72 current_group = current_group.parent 73 return group_path 74 75 76class Enum(object): 77 """Represents a generated enum in ComputedStyleBaseConstants.""" 78 79 def __init__(self, type_name, keywords, is_set): 80 self.type_name = type_name 81 self.values = [ 82 NameStyleConverter(keyword).to_enum_value() for keyword in keywords 83 ] 84 self.is_set = is_set 85 86 87class DiffGroup(object): 88 """Represents a group of expressions and subgroups that need to be diffed 89 for a function in ComputedStyle. 90 91 Attributes: 92 subgroups: List of DiffGroup instances that are stored as subgroups 93 under this group. 94 expressions: List of expression that are on this group that need to 95 be diffed. 96 """ 97 98 def __init__(self, group): 99 self.group = group 100 self.subgroups = [] 101 self.fields = [] 102 self.expressions = [] 103 self.predicates = [] 104 105 106class Field(object): 107 """ 108 The generated ComputedStyle object is made up of a series of Fields. 109 Each Field has a name, size, type, etc, and a bunch of attributes to 110 determine which methods it will be used in. 111 112 A Field also has enough information to use any storage type in C++, such as 113 regular member variables, or more complex storage like vectors or hashmaps. 114 Almost all properties will have at least one Field, often more than one. 115 116 Most attributes in this class correspond to parameters in 117 css_properties.json5. See that file for a more detailed explanation of 118 each attribute. 119 120 Attributes: 121 field_role: The semantic role of the field. Can be: 122 - 'property': for fields that store CSS properties 123 - 'inherited_flag': for single-bit flags that store whether a 124 property is inherited by this style or 125 set explicitly 126 name_for_methods: String used to form the names of getters and setters. 127 Should be in upper camel case. 128 property_name: Name of the property that the field is part of. 129 type_name: Name of the C++ type exposed by the generated interface 130 (e.g. EClear, int). 131 wrapper_pointer_name: Name of the pointer type that wraps this field 132 (e.g. RefPtr). 133 field_template: Determines the interface generated for the field. Can 134 be one of: keyword, flag, or monotonic_flag. 135 size: Number of bits needed for storage. 136 default_value: Default value for this field when it is first initialized 137 """ 138 139 def __init__(self, field_role, name_for_methods, property_name, type_name, 140 wrapper_pointer_name, field_template, size, default_value, 141 custom_copy, custom_compare, mutable, getter_method_name, 142 setter_method_name, initial_method_name, 143 computed_style_custom_functions, **kwargs): 144 name_source = NameStyleConverter(name_for_methods) 145 self.name = name_source.to_class_data_member() 146 self.property_name = property_name 147 self.type_name = type_name 148 self.wrapper_pointer_name = wrapper_pointer_name 149 self.alignment_type = self.wrapper_pointer_name or self.type_name 150 self.field_template = field_template 151 self.size = size 152 self.default_value = default_value 153 self.custom_copy = custom_copy 154 self.custom_compare = custom_compare 155 self.mutable = mutable 156 self.group = None 157 158 # Method names 159 self.getter_method_name = getter_method_name 160 self.setter_method_name = setter_method_name 161 self.internal_getter_method_name = name_source.to_function_name( 162 suffix='internal') 163 self.internal_mutable_method_name = name_source.to_function_name( 164 prefix='mutable', suffix='internal') 165 self.internal_setter_method_name = NameStyleConverter( 166 setter_method_name).to_function_name(suffix='internal') 167 self.initial_method_name = initial_method_name 168 self.resetter_method_name = name_source.to_function_name( 169 prefix='reset') 170 self.computed_style_custom_functions = computed_style_custom_functions 171 # Only bitfields have sizes. 172 self.is_bit_field = self.size is not None 173 174 # Field role: one of these must be true 175 self.is_property = field_role == 'property' 176 self.is_inherited_flag = field_role == 'inherited_flag' 177 assert (self.is_property, self.is_inherited_flag).count(True) == 1, \ 178 'Field role has to be exactly one of: property, inherited_flag' 179 180 if not self.is_inherited_flag: 181 self.is_inherited = kwargs.pop('inherited') 182 self.is_independent = kwargs.pop('independent') 183 assert self.is_inherited or not self.is_independent, \ 184 'Only inherited fields can be independent' 185 186 self.is_inherited_method_name = name_source.to_function_name( 187 suffix=['is', 'inherited']) 188 assert len(kwargs) == 0, \ 189 'Unexpected arguments provided to Field: ' + str(kwargs) 190