OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
3 # for details. All rights reserved. Use of this source code is governed by a | |
4 # BSD-style license that can be found in the LICENSE file. | |
5 | |
6 """This module provides shared functionality for the systems to generate | |
7 native binding from the IDL database.""" | |
8 | |
9 import emitter | |
10 import os | |
11 import systemwrapping | |
12 from generator import * | |
13 from systembase import * | |
14 | |
15 class NativeImplementationSystem(System): | |
16 | |
17 def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): | |
18 super(NativeImplementationSystem, self).__init__( | |
19 templates, database, emitters, output_dir) | |
20 | |
21 self._auxiliary_dir = auxiliary_dir | |
22 self._dom_public_files = [] | |
23 self._dom_impl_files = [] | |
24 self._cpp_header_files = [] | |
25 self._cpp_impl_files = [] | |
26 | |
27 def InterfaceGenerator(self, | |
28 interface, | |
29 common_prefix, | |
30 super_interface_name, | |
31 source_filter): | |
32 interface_name = interface.id | |
33 | |
34 dart_interface_path = self._FilePathForDartInterface(interface_name) | |
35 self._dom_public_files.append(dart_interface_path) | |
36 | |
37 pure_interfaces = set([ | |
sra1
2012/02/21 19:22:13
This could be moved to generator.py
| |
38 'ElementTimeControl', | |
39 'ElementTraversal', | |
40 'MediaQueryListListener', | |
41 'NodeSelector', | |
42 'SVGExternalResourcesRequired', | |
43 'SVGFilterPrimitiveStandardAttributes', | |
44 'SVGFitToViewBox', | |
45 'SVGLangSpace', | |
46 'SVGLocatable', | |
47 'SVGStylable', | |
48 'SVGTests', | |
49 'SVGTransformable', | |
50 'SVGURIReference', | |
51 'SVGViewSpec', | |
52 'SVGZoomAndPan']) | |
53 if interface_name in pure_interfaces: | |
54 return None | |
55 | |
56 dart_impl_path = self._FilePathForDartImplementation(interface_name) | |
57 self._dom_impl_files.append(dart_impl_path) | |
58 | |
59 cpp_header_path = self._FilePathForCppHeader(interface_name) | |
60 self._cpp_header_files.append(cpp_header_path) | |
61 | |
62 cpp_impl_path = self._FilePathForCppImplementation(interface_name) | |
63 self._cpp_impl_files.append(cpp_impl_path) | |
64 | |
65 return NativeImplementationGenerator(interface, super_interface_name, | |
66 self._emitters.FileEmitter(dart_impl_path), | |
67 self._emitters.FileEmitter(cpp_header_path), | |
68 self._emitters.FileEmitter(cpp_impl_path), | |
69 self._BaseDefines(interface), | |
70 self._templates) | |
71 | |
72 def ProcessCallback(self, interface, info): | |
73 self._interface = interface | |
74 | |
75 dart_interface_path = self._FilePathForDartInterface(self._interface.id) | |
76 self._dom_public_files.append(dart_interface_path) | |
77 | |
78 cpp_header_handlers_emitter = emitter.Emitter() | |
79 cpp_impl_handlers_emitter = emitter.Emitter() | |
80 class_name = 'Dart%s' % self._interface.id | |
81 for operation in interface.operations: | |
82 if operation.type.id == 'void': | |
83 return_type = 'void' | |
84 return_prefix = '' | |
85 else: | |
86 return_type = 'bool' | |
87 return_prefix = 'return ' | |
88 | |
89 parameters = [] | |
90 arguments = [] | |
91 for argument in operation.arguments: | |
92 argument_type_info = GetIDLTypeInfo(argument.type) | |
93 parameters.append('%s %s' % (argument_type_info.parameter_type(), | |
94 argument.id)) | |
95 arguments.append(argument.id) | |
96 | |
97 cpp_header_handlers_emitter.Emit( | |
98 '\n' | |
99 ' virtual $TYPE handleEvent($PARAMETERS);\n', | |
100 TYPE=return_type, PARAMETERS=', '.join(parameters)) | |
101 | |
102 cpp_impl_handlers_emitter.Emit( | |
103 '\n' | |
104 '$TYPE $CLASS_NAME::handleEvent($PARAMETERS)\n' | |
105 '{\n' | |
106 ' $(RETURN_PREFIX)m_callback.handleEvent($ARGUMENTS);\n' | |
107 '}\n', | |
108 TYPE=return_type, | |
109 CLASS_NAME=class_name, | |
110 PARAMETERS=', '.join(parameters), | |
111 RETURN_PREFIX=return_prefix, | |
112 ARGUMENTS=', '.join(arguments)) | |
113 | |
114 cpp_header_path = self._FilePathForCppHeader(self._interface.id) | |
115 cpp_header_emitter = self._emitters.FileEmitter(cpp_header_path) | |
116 cpp_header_emitter.Emit( | |
117 self._templates.Load('cpp_callback_header.template'), | |
118 INTERFACE=self._interface.id, | |
119 HANDLERS=cpp_header_handlers_emitter.Fragments()) | |
120 | |
121 cpp_impl_path = self._FilePathForCppImplementation(self._interface.id) | |
122 self._cpp_impl_files.append(cpp_impl_path) | |
123 cpp_impl_emitter = self._emitters.FileEmitter(cpp_impl_path) | |
124 cpp_impl_emitter.Emit( | |
125 self._templates.Load('cpp_callback_implementation.template'), | |
126 INTERFACE=self._interface.id, | |
127 HANDLERS=cpp_impl_handlers_emitter.Fragments()) | |
128 | |
129 def GenerateLibraries(self, lib_dir): | |
130 auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) | |
131 | |
132 # Generate dom_public.dart. | |
133 self._GenerateLibFile( | |
134 'dom_public.darttemplate', | |
135 os.path.join(self._output_dir, 'dom_public.dart'), | |
136 self._dom_public_files, | |
137 AUXILIARY_DIR=auxiliary_dir); | |
138 | |
139 # Generate dom_impl.dart. | |
140 self._GenerateLibFile( | |
141 'dom_impl.darttemplate', | |
142 os.path.join(self._output_dir, 'dom_impl.dart'), | |
143 self._dom_impl_files, | |
144 AUXILIARY_DIR=auxiliary_dir); | |
145 | |
146 # Generate DartDerivedSourcesAll.cpp. | |
147 cpp_all_in_one_path = os.path.join(self._output_dir, | |
148 'DartDerivedSourcesAll.cpp') | |
149 | |
150 includes_emitter = emitter.Emitter() | |
151 for f in self._cpp_impl_files: | |
152 path = os.path.relpath(f, os.path.dirname(cpp_all_in_one_path)) | |
153 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
154 | |
155 cpp_all_in_one_emitter = self._emitters.FileEmitter(cpp_all_in_one_path) | |
156 cpp_all_in_one_emitter.Emit( | |
157 self._templates.Load('cpp_all_in_one.template'), | |
158 INCLUDES=includes_emitter.Fragments()) | |
159 | |
160 # Generate DartResolver.cpp. | |
161 cpp_resolver_path = os.path.join(self._output_dir, 'DartResolver.cpp') | |
162 | |
163 includes_emitter = emitter.Emitter() | |
164 resolver_body_emitter = emitter.Emitter() | |
165 for f in self._cpp_header_files: | |
166 path = os.path.relpath(f, os.path.dirname(cpp_resolver_path)) | |
167 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
168 resolver_body_emitter.Emit( | |
169 ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argume ntCount))\n' | |
170 ' return func;\n', | |
171 CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | |
172 | |
173 cpp_resolver_emitter = self._emitters.FileEmitter(cpp_resolver_path) | |
174 cpp_resolver_emitter.Emit( | |
175 self._templates.Load('cpp_resolver.template'), | |
176 INCLUDES=includes_emitter.Fragments(), | |
177 RESOLVER_BODY=resolver_body_emitter.Fragments()) | |
178 | |
179 # Generate DartDerivedSourcesAll.cpp | |
180 cpp_all_in_one_path = os.path.join(self._output_dir, | |
181 'DartDerivedSourcesAll.cpp') | |
182 | |
183 includes_emitter = emitter.Emitter() | |
184 for file in self._cpp_impl_files: | |
185 path = os.path.relpath(file, os.path.dirname(cpp_all_in_one_path)) | |
186 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
187 | |
188 cpp_all_in_one_emitter = self._emitters.FileEmitter(cpp_all_in_one_path) | |
189 cpp_all_in_one_emitter.Emit( | |
190 self._templates.Load('cpp_all_in_one.template'), | |
191 INCLUDES=includes_emitter.Fragments()) | |
192 | |
193 # Generate DartResolver.cpp | |
194 cpp_resolver_path = os.path.join(self._output_dir, 'DartResolver.cpp') | |
195 | |
196 includes_emitter = emitter.Emitter() | |
197 resolver_body_emitter = emitter.Emitter() | |
198 for file in self._cpp_header_files: | |
199 path = os.path.relpath(file, os.path.dirname(cpp_resolver_path)) | |
200 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
201 resolver_body_emitter.Emit( | |
202 ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argu mentCount))\n' | |
203 ' return func;\n', | |
204 CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | |
205 | |
206 cpp_resolver_emitter = self._emitters.FileEmitter(cpp_resolver_path) | |
207 cpp_resolver_emitter.Emit( | |
208 self._templates.Load('cpp_resolver.template'), | |
209 INCLUDES=includes_emitter.Fragments(), | |
210 RESOLVER_BODY=resolver_body_emitter.Fragments()) | |
211 | |
212 def Finish(self): | |
213 pass | |
214 | |
215 def _FilePathForDartInterface(self, interface_name): | |
216 return os.path.join(self._output_dir, 'src', 'interface', | |
217 '%s.dart' % interface_name) | |
218 | |
219 def _FilePathForDartImplementation(self, interface_name): | |
220 return os.path.join(self._output_dir, 'dart', | |
221 '%sImplementation.dart' % interface_name) | |
222 | |
223 def _FilePathForCppHeader(self, interface_name): | |
224 return os.path.join(self._output_dir, 'cpp', 'Dart%s.h' % interface_name) | |
225 | |
226 def _FilePathForCppImplementation(self, interface_name): | |
227 return os.path.join(self._output_dir, 'cpp', 'Dart%s.cpp' % interface_name) | |
228 | |
229 | |
230 class NativeImplementationGenerator(systemwrapping.WrappingInterfaceGenerator): | |
231 """Generates Dart implementation for one DOM IDL interface.""" | |
232 | |
233 def __init__(self, interface, super_interface, | |
234 dart_impl_emitter, cpp_header_emitter, cpp_impl_emitter, | |
235 base_members, templates): | |
236 """Generates Dart and C++ code for the given interface. | |
237 | |
238 Args: | |
239 | |
240 interface: an IDLInterface instance. It is assumed that all types have | |
241 been converted to Dart types (e.g. int, String), unless they are in | |
242 the same package as the interface. | |
243 super_interface: A string or None, the name of the common interface that | |
244 this interface implements, if any. | |
245 dart_impl_emitter: an Emitter for the file containing the Dart | |
246 implementation class. | |
247 cpp_header_emitter: an Emitter for the file containing the C++ header. | |
248 cpp_impl_emitter: an Emitter for the file containing the C++ | |
249 implementation. | |
250 base_members: a set of names of members defined in a base class. This is | |
251 used to avoid static member 'overriding' in the generated Dart code. | |
252 """ | |
253 self._interface = interface | |
254 self._super_interface = super_interface | |
255 self._dart_impl_emitter = dart_impl_emitter | |
256 self._cpp_header_emitter = cpp_header_emitter | |
257 self._cpp_impl_emitter = cpp_impl_emitter | |
258 self._base_members = base_members | |
259 self._templates = templates | |
260 self._current_secondary_parent = None | |
261 | |
262 def StartInterface(self): | |
263 self._class_name = self._ImplClassName(self._interface.id) | |
264 self._interface_type_info = GetIDLTypeInfoByName(self._interface.id) | |
265 self._members_emitter = emitter.Emitter() | |
266 self._cpp_declarations_emitter = emitter.Emitter() | |
267 self._cpp_impl_includes = {} | |
268 self._cpp_definitions_emitter = emitter.Emitter() | |
269 self._cpp_resolver_emitter = emitter.Emitter() | |
270 | |
271 # Generate constructor. | |
272 # FIXME: add proper support for non-custom constructors. | |
273 if ('CustomConstructor' in self._interface.ext_attrs or | |
274 'V8CustomConstructor' in self._interface.ext_attrs or | |
275 self._interface.id in ['FileReader', 'WebKitCSSMatrix', 'XSLTProcessor'] ): | |
276 self._cpp_resolver_emitter.Emit( | |
277 ' if (name == "$(INTERFACE_NAME)_constructor_Callback")\n' | |
278 ' return Dart$(INTERFACE_NAME)Internal::constructorCallback;\n' , | |
279 INTERFACE_NAME=self._interface.id) | |
280 self._cpp_declarations_emitter.Emit( | |
281 '\n' | |
282 'void constructorCallback(Dart_NativeArguments);\n') | |
283 | |
284 def _ImplClassName(self, interface_name): | |
285 return interface_name + 'Implementation' | |
286 | |
287 def FinishInterface(self): | |
288 base = self._BaseClassName(self._interface) | |
289 self._dart_impl_emitter.Emit( | |
290 self._templates.Load('dart_implementation.darttemplate'), | |
291 CLASS=self._class_name, BASE=base, INTERFACE=self._interface.id, | |
292 MEMBERS=self._members_emitter.Fragments()) | |
293 | |
294 self._GenerateCppHeader() | |
295 | |
296 self._cpp_impl_emitter.Emit( | |
297 self._templates.Load('cpp_implementation.template'), | |
298 INTERFACE=self._interface.id, | |
299 INCLUDES=''.join(['#include "%s.h"\n' % | |
300 k for k in self._cpp_impl_includes.keys()]), | |
301 CALLBACKS=self._cpp_definitions_emitter.Fragments(), | |
302 RESOLVER=self._cpp_resolver_emitter.Fragments()) | |
303 | |
304 def _GenerateCppHeader(self): | |
305 webcore_include = self._interface_type_info.webcore_include() | |
306 if webcore_include: | |
307 webcore_include = '#include "%s.h"\n' % webcore_include | |
308 else: | |
309 webcore_include = '' | |
310 | |
311 if ('CustomToJS' in self._interface.ext_attrs or | |
312 'CustomToJSObject' in self._interface.ext_attrs or | |
313 'PureInterface' in self._interface.ext_attrs or | |
314 'CPPPureInterface' in self._interface.ext_attrs or | |
315 self._interface_type_info.custom_to_dart()): | |
316 to_dart_value_template = ( | |
317 'Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value);\n') | |
318 else: | |
319 to_dart_value_template = ( | |
320 'inline Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value)\n' | |
321 '{\n' | |
322 ' return DartDOMWrapper::toDart<Dart$(INTERFACE)>(value);\n' | |
323 '}\n') | |
324 to_dart_value_emitter = emitter.Emitter() | |
325 to_dart_value_emitter.Emit( | |
326 to_dart_value_template, | |
327 INTERFACE=self._interface.id, | |
328 WEBCORE_CLASS_NAME=self._interface_type_info.native_type()) | |
329 | |
330 self._cpp_header_emitter.Emit( | |
331 self._templates.Load('cpp_header.template'), | |
332 INTERFACE=self._interface.id, | |
333 WEBCORE_INCLUDE=webcore_include, | |
334 ADDITIONAL_INCLUDES='', | |
335 WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | |
336 TO_DART_VALUE=to_dart_value_emitter.Fragments(), | |
337 DECLARATIONS=self._cpp_declarations_emitter.Fragments()) | |
338 | |
339 def AddAttribute(self, getter, setter): | |
340 # FIXME: Dartium does not support attribute event listeners. However, JS | |
341 # implementation falls back to them when addEventListener is not available. | |
342 # Make sure addEventListener is available in all EventTargets and remove | |
343 # this check. | |
344 if (getter or setter).type.id == 'EventListener': | |
345 return | |
346 | |
347 # FIXME: support 'ImplementedBy'. | |
348 if 'ImplementedBy' in (getter or setter).ext_attrs: | |
349 return | |
350 | |
351 # FIXME: these should go away. | |
352 classes_with_unsupported_custom_getters = [ | |
353 'Clipboard', 'Console', 'Coordinates', 'DeviceMotionEvent', | |
354 'DeviceOrientationEvent', 'FileReader', 'JavaScriptCallFrame', | |
355 'HTMLInputElement', 'HTMLOptionsCollection', 'HTMLOutputElement', | |
356 'ScriptProfileNode', 'WebKitAnimation'] | |
357 if (self._interface.id in classes_with_unsupported_custom_getters and | |
358 getter and set(['Custom', 'CustomGetter']) & set(getter.ext_attrs)): | |
359 return | |
360 | |
361 if getter: | |
362 self._AddGetter(getter) | |
363 if setter: | |
364 self._AddSetter(setter) | |
365 | |
366 def _AddGetter(self, attr): | |
367 dart_declaration = '%s get %s()' % (attr.type.id, attr.id) | |
368 is_custom = 'Custom' in attr.ext_attrs or 'CustomGetter' in attr.ext_attrs | |
369 cpp_callback_name = self._GenerateNativeBinding(attr.id, 1, | |
370 dart_declaration, 'Getter', is_custom) | |
371 if is_custom: | |
372 return | |
373 | |
374 arguments = [] | |
375 if 'Reflect' in attr.ext_attrs: | |
376 webcore_function_name = GetIDLTypeInfo(attr.type).webcore_getter_name() | |
377 if 'URL' in attr.ext_attrs: | |
378 if 'NonEmpty' in attr.ext_attrs: | |
379 webcore_function_name = 'getNonEmptyURLAttribute' | |
380 else: | |
381 webcore_function_name = 'getURLAttribute' | |
382 arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | |
383 else: | |
384 if attr.id == 'operator': | |
385 webcore_function_name = '_operator' | |
386 elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString': | |
387 webcore_function_name = 'svgTarget' | |
388 else: | |
389 webcore_function_name = re.sub(r'^(HTML|URL|JS|XML|XSLT|\w)', | |
390 lambda s: s.group(1).lower(), | |
391 attr.id) | |
392 webcore_function_name = re.sub(r'^(create|exclusive)', | |
393 lambda s: 'is' + s.group(1).capitalize(), | |
394 webcore_function_name) | |
395 if attr.type.id.startswith('SVGAnimated'): | |
396 webcore_function_name += 'Animated' | |
397 | |
398 self._GenerateNativeCallback(cpp_callback_name, attr, '', | |
399 webcore_function_name, arguments, idl_return_type=attr.type, | |
400 raises_dart_exceptions=attr.get_raises, | |
401 raises_dom_exceptions=attr.get_raises) | |
402 | |
403 def _AddSetter(self, attr): | |
404 dart_declaration = 'void set %s(%s)' % (attr.id, attr.type.id) | |
405 is_custom = set(['Custom', 'CustomSetter', 'V8CustomSetter']) & set(attr.ext _attrs) | |
406 cpp_callback_name = self._GenerateNativeBinding(attr.id, 2, | |
407 dart_declaration, 'Setter', is_custom) | |
408 if is_custom: | |
409 return | |
410 | |
411 arguments = [] | |
412 if 'Reflect' in attr.ext_attrs: | |
413 webcore_function_name = GetIDLTypeInfo(attr.type).webcore_setter_name() | |
414 arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | |
415 else: | |
416 webcore_function_name = re.sub(r'^(xml(?=[A-Z])|\w)', | |
417 lambda s: s.group(1).upper(), | |
418 attr.id) | |
419 webcore_function_name = 'set%s' % webcore_function_name | |
420 if attr.type.id.startswith('SVGAnimated'): | |
421 webcore_function_name += 'Animated' | |
422 | |
423 arguments.append(attr.id) | |
424 parameter_definitions_emitter = emitter.Emitter() | |
425 self._GenerateParameterAdapter(parameter_definitions_emitter, attr, 0) | |
426 parameter_definitions = parameter_definitions_emitter.Fragments() | |
427 self._GenerateNativeCallback(cpp_callback_name, attr, parameter_definitions, | |
428 webcore_function_name, arguments, idl_return_type=None, | |
429 raises_dart_exceptions=True, | |
430 raises_dom_exceptions=attr.set_raises) | |
431 | |
432 def _HasNativeIndexGetter(self, interface): | |
433 return ('CustomIndexedGetter' in interface.ext_attrs or | |
434 'NumericIndexedGetter' in interface.ext_attrs) | |
435 | |
436 def _EmitNativeIndexGetter(self, interface, element_type): | |
437 dart_declaration = '%s operator[](int index)' % element_type | |
438 self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration, | |
439 'Callback', True) | |
440 | |
441 def _EmitNativeIndexSetter(self, interface, element_type): | |
442 dart_declaration = 'void operator[]=(int index, %s value)' % element_type | |
443 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, | |
444 'Callback', True) | |
445 | |
446 def AddOperation(self, info): | |
447 """ | |
448 Arguments: | |
449 info: An OperationInfo object. | |
450 """ | |
451 | |
452 if 'Custom' in info.overloads[0].ext_attrs: | |
453 parameters = info.ParametersImplementationDeclaration() | |
454 dart_declaration = '%s %s(%s)' % (info.type_name, info.name, parameters) | |
455 argument_count = 1 + len(info.arg_infos) | |
456 self._GenerateNativeBinding(info.name, argument_count, dart_declaration, | |
457 'Callback', True) | |
458 return | |
459 | |
460 body = self._members_emitter.Emit( | |
461 '\n' | |
462 ' $TYPE $NAME($PARAMETERS) {\n' | |
463 '$!BODY' | |
464 ' }\n', | |
465 TYPE=info.type_name, | |
466 NAME=info.name, | |
467 PARAMETERS=info.ParametersImplementationDeclaration()) | |
468 | |
469 # Process in order of ascending number of arguments to ensure missing | |
470 # optional arguments are processed early. | |
471 overloads = sorted(info.overloads, | |
472 key=lambda overload: len(overload.arguments)) | |
473 self._native_version = 0 | |
474 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
475 if fallthrough: | |
476 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
477 | |
478 def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): | |
479 """Generates a call to a single operation. | |
480 | |
481 Arguments: | |
482 dispatch_emitter: an dispatch_emitter for the body of a block of code. | |
483 info: the compound information about the operation and its overloads. | |
484 indent: an indentation string for generated code. | |
485 operation: the IDLOperation to call. | |
486 """ | |
487 | |
488 # FIXME: support ImplementedBy callbacks. | |
489 if 'ImplementedBy' in operation.ext_attrs: | |
490 return | |
491 | |
492 for op in self._interface.operations: | |
493 if op.id != operation.id or len(op.arguments) <= len(operation.arguments): | |
494 continue | |
495 next_argument = op.arguments[len(operation.arguments)] | |
496 if next_argument.is_optional and 'Callback' in next_argument.ext_attrs: | |
497 # FIXME: '[Optional, Callback]' arguments could be non-optional in | |
498 # webcore. We need to fix overloads handling to generate native | |
499 # callbacks properly. | |
500 return | |
501 | |
502 self._native_version += 1 | |
503 native_name = info.name | |
504 if self._native_version > 1: | |
505 native_name = '%s_%s' % (native_name, self._native_version) | |
506 argument_list = ', '.join([info.arg_infos[i][0] | |
507 for (i, arg) in enumerate(operation.arguments)]) | |
508 | |
509 # Generate dispatcher. | |
510 if info.type_name != 'void': | |
511 dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n', | |
512 INDENT=indent, | |
513 NATIVENAME=native_name, | |
514 ARGS=argument_list) | |
515 else: | |
516 dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n' | |
517 '$(INDENT)return;\n', | |
518 INDENT=indent, | |
519 NATIVENAME=native_name, | |
520 ARGS=argument_list) | |
521 # Generate binding. | |
522 dart_declaration = '%s _%s(%s)' % (info.type_name, native_name, | |
523 argument_list) | |
524 is_custom = 'Custom' in operation.ext_attrs | |
525 cpp_callback_name = self._GenerateNativeBinding( | |
526 native_name, 1 + len(operation.arguments), dart_declaration, 'Callback', | |
527 is_custom) | |
528 if is_custom: | |
529 return | |
530 | |
531 # Generate callback. | |
532 webcore_function_name = operation.id | |
533 if 'ImplementedAs' in operation.ext_attrs: | |
534 webcore_function_name = operation.ext_attrs['ImplementedAs'] | |
535 | |
536 parameter_definitions_emitter = emitter.Emitter() | |
537 raises_dart_exceptions = len(operation.arguments) > 0 or operation.raises | |
538 arguments = [] | |
539 | |
540 # Process 'CallWith' argument. | |
541 if 'CallWith' in operation.ext_attrs: | |
542 call_with = operation.ext_attrs['CallWith'] | |
543 if call_with == 'ScriptExecutionContext': | |
544 parameter_definitions_emitter.Emit( | |
545 ' ScriptExecutionContext* context = DartUtilities::scriptExec utionContext();\n' | |
546 ' if (!context)\n' | |
547 ' return;\n') | |
548 arguments.append('context') | |
549 elif call_with == 'ScriptArguments|CallStack': | |
550 raises_dart_exceptions = True | |
551 self._cpp_impl_includes['ScriptArguments'] = 1 | |
552 self._cpp_impl_includes['ScriptCallStack'] = 1 | |
553 self._cpp_impl_includes['V8Proxy'] = 1 | |
554 self._cpp_impl_includes['v8'] = 1 | |
555 parameter_definitions_emitter.Emit( | |
556 ' v8::HandleScope handleScope;\n' | |
557 ' v8::Context::Scope scope(V8Proxy::mainWorldContext(DartUtil ities::domWindowForCurrentIsolate()->frame()));\n' | |
558 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $ INDEX);\n' | |
559 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::crea teScriptArguments(customArgument, exception));\n' | |
560 ' if (!scriptArguments)\n' | |
561 ' goto fail;\n' | |
562 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::crea teScriptCallStack());\n' | |
563 ' if (!scriptCallStack->size())\n' | |
564 ' return;\n', | |
565 INDEX=len(operation.arguments)) | |
566 arguments.extend(['scriptArguments', 'scriptCallStack']) | |
567 | |
568 # Process Dart arguments. | |
569 for (i, argument) in enumerate(operation.arguments): | |
570 if i == len(operation.arguments) - 1 and self._interface.id == 'Console' a nd argument.id == 'arg': | |
571 # FIXME: we are skipping last argument here because it was added in | |
572 # supplemental dart.idl. Cleanup dart.idl and remove this check. | |
573 break | |
574 self._GenerateParameterAdapter(parameter_definitions_emitter, argument, i) | |
575 arguments.append(argument.id) | |
576 | |
577 if operation.id in ['addEventListener', 'removeEventListener']: | |
578 # addEventListener's and removeEventListener's last argument is marked | |
579 # as optional in idl, but is not optional in webcore implementation. | |
580 if len(operation.arguments) == 2: | |
581 arguments.append('false') | |
582 | |
583 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope rty': | |
584 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart | |
585 # idl, but is not optional in webcore implementation. | |
586 if len(operation.arguments) == 2: | |
587 arguments.append('String()') | |
588 | |
589 if 'NeedsUserGestureCheck' in operation.ext_attrs: | |
590 arguments.extend('DartUtilities::processingUserGesture') | |
591 | |
592 parameter_definitions = parameter_definitions_emitter.Fragments() | |
593 self._GenerateNativeCallback(cpp_callback_name, operation, | |
594 parameter_definitions, webcore_function_name, arguments, | |
595 idl_return_type=operation.type, | |
596 raises_dart_exceptions=raises_dart_exceptions, | |
597 raises_dom_exceptions=operation.raises) | |
598 | |
599 def _GenerateNativeCallback(self, callback_name, idl_node, | |
600 parameter_definitions, function_name, arguments, idl_return_type, | |
601 raises_dart_exceptions, raises_dom_exceptions): | |
602 receiver = self._interface_type_info.receiver() | |
603 if raises_dom_exceptions: | |
604 arguments.append('ec') | |
605 callback = '%s%s(%s)' % (receiver, function_name, ', '.join(arguments)) | |
606 | |
607 nested_templates = [] | |
608 if idl_return_type and idl_return_type.id != 'void': | |
609 return_type_info = GetIDLTypeInfo(idl_return_type) | |
610 conversion_cast = return_type_info.conversion_cast('$BODY') | |
611 if isinstance(return_type_info, SVGTearOffIDLTypeInfo): | |
612 svg_primitive_types = ['SVGAngle', 'SVGLength', 'SVGMatrix', | |
613 'SVGNumber', 'SVGPoint', 'SVGRect', 'SVGTransform'] | |
614 conversion_cast = '%s::create($BODY)' | |
615 if self._interface.id.startswith('SVGAnimated'): | |
616 conversion_cast = 'static_cast<%s*>($BODY)' | |
617 elif return_type_info.idl_type() == 'SVGStringList': | |
618 conversion_cast = '%s::create(receiver, $BODY)' | |
619 elif self._interface.id.endswith('List'): | |
620 conversion_cast = 'static_cast<%s*>($BODY.get())' | |
621 elif return_type_info.idl_type() in svg_primitive_types: | |
622 conversion_cast = '%s::create($BODY)' | |
623 else: | |
624 conversion_cast = 'static_cast<%s*>($BODY)' | |
625 conversion_cast = conversion_cast % return_type_info.native_type() | |
626 nested_templates.append(conversion_cast) | |
627 | |
628 if return_type_info.conversion_include(): | |
629 self._cpp_impl_includes[return_type_info.conversion_include()] = 1 | |
630 if (return_type_info.idl_type() in ['DOMString', 'AtomicString'] and | |
631 'TreatReturnedNullStringAs' in idl_node.ext_attrs): | |
632 nested_templates.append('$BODY, ConvertDefaultToNull') | |
633 nested_templates.append( | |
634 ' Dart_Handle returnValue = toDartValue($BODY);\n' | |
635 ' if (returnValue)\n' | |
636 ' Dart_SetReturnValue(args, returnValue);\n') | |
637 else: | |
638 nested_templates.append(' $BODY;\n') | |
639 | |
640 if raises_dom_exceptions: | |
641 nested_templates.append( | |
642 ' ExceptionCode ec = 0;\n' | |
643 '$BODY' | |
644 ' if (UNLIKELY(ec)) {\n' | |
645 ' exception = DartDOMWrapper::exceptionCodeToDartException( ec);\n' | |
646 ' goto fail;\n' | |
647 ' }\n') | |
648 | |
649 nested_templates.append( | |
650 ' {\n' | |
651 ' $WEBCORE_CLASS_NAME* receiver = DartDOMWrapper::receiver< $WEBC ORE_CLASS_NAME >(args);\n' | |
652 '$PARAMETER_DEFINITIONS' | |
653 '\n' | |
654 '$BODY' | |
655 ' return;\n' | |
656 ' }\n') | |
657 | |
658 if raises_dart_exceptions: | |
659 nested_templates.append( | |
660 ' Dart_Handle exception;\n' | |
661 '$BODY' | |
662 '\n' | |
663 'fail:\n' | |
664 ' Dart_ThrowException(exception);\n' | |
665 ' ASSERT_NOT_REACHED();\n') | |
666 | |
667 nested_templates.append( | |
668 '\n' | |
669 'static void $CALLBACK_NAME(Dart_NativeArguments args)\n' | |
670 '{\n' | |
671 ' DartApiScope dartApiScope;\n' | |
672 '$BODY' | |
673 '}\n') | |
674 | |
675 template_parameters = { | |
676 'CALLBACK_NAME': callback_name, | |
677 'WEBCORE_CLASS_NAME': self._interface_type_info.native_type(), | |
678 'PARAMETER_DEFINITIONS': parameter_definitions, | |
679 } | |
680 for template in nested_templates: | |
681 template_parameters['BODY'] = callback | |
682 callback_emitter = emitter.Emitter() | |
683 callback_emitter.Emit(template, **template_parameters) | |
684 callback = ''.join(callback_emitter.Fragments()) | |
685 | |
686 self._cpp_definitions_emitter.Emit(callback) | |
687 | |
688 def _GenerateParameterAdapter(self, emitter, idl_argument, index): | |
689 type_info = GetIDLTypeInfo(idl_argument.type) | |
690 (adapter_type, include_name) = type_info.parameter_adapter_info() | |
691 if include_name: | |
692 self._cpp_impl_includes[include_name] = 1 | |
693 emitter.Emit( | |
694 '\n' | |
695 ' const $ADAPTER_TYPE $NAME(Dart_GetNativeArgument(args, $INDEX)) ;\n' | |
696 ' if (!$NAME.conversionSuccessful()) {\n' | |
697 ' exception = $NAME.exception();\n' | |
698 ' goto fail;\n' | |
699 ' }\n', | |
700 ADAPTER_TYPE=adapter_type, | |
701 NAME=idl_argument.id, | |
702 INDEX=index + 1) | |
703 | |
704 def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration, | |
705 native_suffix, is_custom): | |
706 native_binding = '%s_%s_%s' % (self._interface.id, idl_name, native_suffix) | |
707 self._members_emitter.Emit( | |
708 '\n' | |
709 ' $DART_DECLARATION native "$NATIVE_BINDING";\n', | |
710 DART_DECLARATION=dart_declaration, NATIVE_BINDING=native_binding) | |
711 | |
712 cpp_callback_name = '%s%s' % (idl_name, native_suffix) | |
713 self._cpp_resolver_emitter.Emit( | |
714 ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n' | |
715 ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n', | |
716 ARGC=argument_count, | |
717 NATIVE_BINDING=native_binding, | |
718 INTERFACE_NAME=self._interface.id, | |
719 CPP_CALLBACK_NAME=cpp_callback_name) | |
720 | |
721 if is_custom: | |
722 self._cpp_declarations_emitter.Emit( | |
723 '\n' | |
724 'void $CPP_CALLBACK_NAME(Dart_NativeArguments);\n', | |
725 CPP_CALLBACK_NAME=cpp_callback_name) | |
726 | |
727 return cpp_callback_name | |
728 | |
729 def _GenerateWebCoreReflectionAttributeName(self, attr): | |
730 namespace = 'HTMLNames' | |
731 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | |
732 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | |
733 'onmouseup', 'onresize', 'onscroll', 'onunload'] | |
734 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | |
735 namespace = 'SVGNames' | |
736 self._cpp_impl_includes[namespace] = 1 | |
737 | |
738 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | |
739 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | |
740 | |
OLD | NEW |