Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: third_party/WebKit/Source/bindings/scripts/generate_conditional_features.py

Issue 2970003002: Add code generation for ConditionalFeatures bindings code (Closed)
Patch Set: Readability fixes Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright 2017 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 # This script reads the global interface data collected by
8 # compute_interfaces_info_overall.py, and writes out the code which adds
9 # bindings for origin-trial-enabled features at runtime.
10
11 # pylint: disable=W0403
12
13 import optparse
14 import os
15 import posixpath
16 import sys
17 from collections import defaultdict, namedtuple
18
19 from code_generator import (initialize_jinja_env, normalize_and_sort_includes,
20 render_template)
21 from idl_reader import IdlReader
22 from utilities import (create_component_info_provider, write_file,
23 idl_filename_to_component)
24 from v8_utilities import v8_class_name, v8_class_name_or_partial, uncapitalize
25
26 # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching
27 MODULE_PYNAME = os.path.splitext(os.path.basename(__file__))[0] + '.py'
28
29
30 ConditionalInterfaceInfo = namedtuple('ConditionalInterfaceInfo', [
31 'name', 'v8_class', 'v8_class_or_partial', 'is_global'])
32
33
34 def get_install_functions(interfaces, feature_names):
35 """Construct a list of V8 bindings installation functions for each feature
36 on each interface.
37
38 interfaces is a list of ConditionalInterfaceInfo tuples
39 feature_names is a list of strings, containing names of features which can
40 be installed on those interfaces.
41 """
42 return [
43 {"condition": 'OriginTrials::%sEnabled' % uncapitalize(feature_name),
44 "name": feature_name,
45 "install_method": "install%s" % feature_name,
46 "v8_class": interface_info.v8_class,
47 "v8_class_or_partial": interface_info.v8_class_or_partial}
48 for feature_name in feature_names
49 for interface_info in interfaces]
50
51
52 def get_conditional_feature_names_from_interface(interface):
53 feature_names = set()
54 if ('OriginTrialEnabled' in interface.extended_attributes and
55 interface.is_partial):
56 feature_names.add(interface.extended_attributes['OriginTrialEnabled'])
57 for operation in interface.operations:
58 if 'OriginTrialEnabled' in operation.extended_attributes:
59 feature_names.add(
60 operation.extended_attributes['OriginTrialEnabled'])
61 for attribute in interface.attributes:
62 if 'OriginTrialEnabled' in attribute.extended_attributes:
63 feature_names.add(
64 attribute.extended_attributes['OriginTrialEnabled'])
65 return list(feature_names)
66
67
68 def read_idl_file(reader, idl_filename):
69 interfaces = reader.read_idl_file(idl_filename).interfaces
70 # There should only be a single interface defined in an IDL file. Return it.
71 assert len(interfaces) == 1
72 return interfaces.values()[0]
73
74
75 def interface_is_global(interface):
76 return ('Global' in interface.extended_attributes or
77 'PrimaryGlobal' in interface.extended_attributes)
78
79
80 def conditional_features_info(info_provider, reader, idl_filenames, target_compo nent):
81 """Read a set of IDL files and compile the mapping between interfaces and
82 the conditional features defined on them.
83
84 Returns a tuple (features_for_type, types_for_feature, includes):
85 - features_for_type is a mapping of interface->feature
86 - types_for_feature is the reverse mapping: feature->interface
87 - includes is a set of header files which need to be included in the
88 generated implementation code.
89 """
90 features_for_type = defaultdict(set)
91 types_for_feature = defaultdict(set)
92 includes = set()
93
94 for idl_filename in idl_filenames:
95 interface = read_idl_file(reader, idl_filename)
96 feature_names = get_conditional_feature_names_from_interface(interface)
97 if feature_names:
98 is_global = interface_is_global(interface)
99 if interface.is_partial:
100 # For partial interfaces, we need to generate different
101 # includes if the parent interface is in a different
102 # component.
103 parent_interface_info = info_provider.interfaces_info[interface. name]
104 parent_interface = read_idl_file(
105 reader, parent_interface_info.get('full_path'))
106 is_global = is_global or interface_is_global(parent_interface)
107 parent_component = idl_filename_to_component(
108 parent_interface_info.get('full_path'))
109 if interface.is_partial and target_component != parent_component:
110 includes.add('bindings/%s/v8/V8%s.h' %
111 (parent_component, interface.name))
112 includes.add('bindings/%s/v8/V8%sPartial.h' %
113 (target_component, interface.name))
114 else:
115 includes.add('bindings/%s/v8/V8%s.h' %
116 (target_component, interface.name))
117 # If this is a partial interface in the same component as
118 # its parent, then treat it as a non-partial interface.
119 interface.is_partial = False
120 interface_info = ConditionalInterfaceInfo(interface.name,
121 v8_class_name(interface),
122 v8_class_name_or_partial(
123 interface),
124 is_global)
125 for feature_name in feature_names:
126 features_for_type[interface_info].add(feature_name)
127 types_for_feature[feature_name].add(interface_info)
128
129 return features_for_type, types_for_feature, includes
130
131
132 def conditional_features_context(generator_name, feature_info):
133 context = {'code_generator': generator_name}
134
135 # Unpack the feature info tuple.
136 features_for_type, types_for_feature, includes = feature_info
137
138 # Add includes needed for cpp code and normalize.
139 includes.update([
140 "core/context_features/ContextFeatureSettings.h",
141 "core/dom/ExecutionContext.h",
142 "core/frame/Frame.h",
143 "core/origin_trials/OriginTrials.h",
144 "platform/bindings/ConditionalFeatures.h",
145 "platform/bindings/ScriptState.h",
146 # TODO(iclelland): Remove the need to explicitly include this; it is
147 # here because the ContextFeatureSettings code needs it.
148 "bindings/core/v8/V8Window.h",
149 ])
150 context['includes'] = normalize_and_sort_includes(includes)
151
152 # For each interface, collect a list of bindings installation functions to
153 # call, organized by conditional feature.
154 context['installers_by_interface'] = [
155 {"name": interface_info.name,
156 "is_global": interface_info.is_global,
157 "v8_class": interface_info.v8_class,
158 "installers": get_install_functions([interface_info], feature_names)}
159 for interface_info, feature_names in features_for_type.items()]
160 context['installers_by_interface'].sort(key=lambda x: x['name'])
161
162 # For each conditional feature, collect a list of bindings installation
163 # functions to call, organized by interface.
164 context['installers_by_feature'] = [
165 {"name": feature_name,
166 "installers": get_install_functions(interfaces, [feature_name])}
167 for feature_name, interfaces in types_for_feature.items()]
168 context['installers_by_feature'].sort(key=lambda x: x['name'])
169
170 return context
171
172
173 def parse_options():
174 parser = optparse.OptionParser()
175 parser.add_option('--cache-directory',
176 help='cache directory, defaults to output directory')
177 parser.add_option('--output-directory')
178 parser.add_option('--info-dir')
179 parser.add_option('--target-component',
180 type='choice',
181 choices=['Core', 'Modules'],
182 help='target component to generate code')
183 parser.add_option('--idl-files-list')
184
185 options, _ = parser.parse_args()
186 if options.output_directory is None:
187 parser.error('Must specify output directory using --output-directory.')
188 return options
189
190
191 def generate_conditional_features(info_provider, options, idl_filenames):
192 reader = IdlReader(info_provider.interfaces_info, options.cache_directory)
193 jinja_env = initialize_jinja_env(options.cache_directory)
194
195 # Extract the bidirectional mapping of conditional features <-> interfaces
196 # from the global info provider and the supplied list of IDL files.
197 feature_info = conditional_features_info(info_provider,
198 reader, idl_filenames,
199 options.target_component.lower())
200
201 # Convert that mapping into the context required for the Jinja2 templates.
202 template_context = conditional_features_context(
203 MODULE_PYNAME, feature_info)
204
205 # Generate and write out the header file
206 header_text = render_template(jinja_env.get_template(
207 "ConditionalFeaturesFor%s.h.tmpl" % options.target_component.title()), t emplate_context)
208 header_path = posixpath.join(options.output_directory,
209 "ConditionalFeaturesFor%s.h" % options.target_c omponent.title())
210 write_file(header_text, header_path)
211
212 # Generate and write out the implementation file
213 cpp_text = render_template(jinja_env.get_template(
214 "ConditionalFeaturesFor%s.cpp.tmpl" % options.target_component.title()), template_context)
215 cpp_path = posixpath.join(options.output_directory,
216 "ConditionalFeaturesFor%s.cpp" % options.target_co mponent.title())
217 write_file(cpp_text, cpp_path)
218
219
220 def main():
221 options = parse_options()
222
223 info_provider = create_component_info_provider(
224 os.path.normpath(options.info_dir), options.target_component.lower())
225 idl_filenames = map(str.strip, open(options.idl_files_list))
226
227 generate_conditional_features(info_provider, options, idl_filenames)
228 return 0
229
230
231 if __name__ == '__main__':
232 sys.exit(main())
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/bindings/modules/v8/v8.gni ('k') | third_party/WebKit/Source/bindings/scripts/scripts.gni » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698