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 if IsPureInterface(interface_name): | |
38 return None | |
39 | |
40 dart_impl_path = self._FilePathForDartImplementation(interface_name) | |
41 self._dom_impl_files.append(dart_impl_path) | |
42 | |
43 cpp_header_path = self._FilePathForCppHeader(interface_name) | |
44 self._cpp_header_files.append(cpp_header_path) | |
45 | |
46 cpp_impl_path = self._FilePathForCppImplementation(interface_name) | |
47 self._cpp_impl_files.append(cpp_impl_path) | |
48 | |
49 return NativeImplementationGenerator(self, interface, super_interface_name, | |
50 self._emitters.FileEmitter(dart_impl_path), | |
51 self._emitters.FileEmitter(cpp_header_path), | |
52 self._emitters.FileEmitter(cpp_impl_path), | |
53 self._BaseDefines(interface), | |
54 self._templates) | |
55 | |
56 def ProcessCallback(self, interface, info): | |
57 self._interface = interface | |
58 | |
59 dart_interface_path = self._FilePathForDartInterface(self._interface.id) | |
60 self._dom_public_files.append(dart_interface_path) | |
61 | |
62 cpp_impl_includes = set() | |
63 cpp_header_handlers_emitter = emitter.Emitter() | |
64 cpp_impl_handlers_emitter = emitter.Emitter() | |
65 class_name = 'Dart%s' % self._interface.id | |
66 for operation in interface.operations: | |
67 if operation.type.id == 'void': | |
68 return_type = 'void' | |
69 return_prefix = '' | |
70 else: | |
71 return_type = 'bool' | |
72 return_prefix = 'return ' | |
73 | |
74 parameters = [] | |
75 arguments = [] | |
76 for argument in operation.arguments: | |
77 argument_type_info = GetIDLTypeInfo(argument.type.id) | |
78 parameters.append('%s %s' % (argument_type_info.parameter_type(), | |
79 argument.id)) | |
80 arguments.append(argument.id) | |
81 cpp_impl_includes |= set(argument_type_info.conversion_includes()) | |
82 | |
83 cpp_header_handlers_emitter.Emit( | |
84 '\n' | |
85 ' virtual $TYPE handleEvent($PARAMETERS);\n', | |
86 TYPE=return_type, PARAMETERS=', '.join(parameters)) | |
87 | |
88 cpp_impl_handlers_emitter.Emit( | |
89 '\n' | |
90 '$TYPE $CLASS_NAME::handleEvent($PARAMETERS)\n' | |
91 '{\n' | |
92 ' $(RETURN_PREFIX)m_callback.handleEvent($ARGUMENTS);\n' | |
93 '}\n', | |
94 TYPE=return_type, | |
95 CLASS_NAME=class_name, | |
96 PARAMETERS=', '.join(parameters), | |
97 RETURN_PREFIX=return_prefix, | |
98 ARGUMENTS=', '.join(arguments)) | |
99 | |
100 cpp_header_path = self._FilePathForCppHeader(self._interface.id) | |
101 cpp_header_emitter = self._emitters.FileEmitter(cpp_header_path) | |
102 cpp_header_emitter.Emit( | |
103 self._templates.Load('cpp_callback_header.template'), | |
104 INTERFACE=self._interface.id, | |
105 HANDLERS=cpp_header_handlers_emitter.Fragments()) | |
106 | |
107 cpp_impl_path = self._FilePathForCppImplementation(self._interface.id) | |
108 self._cpp_impl_files.append(cpp_impl_path) | |
109 cpp_impl_emitter = self._emitters.FileEmitter(cpp_impl_path) | |
110 cpp_impl_emitter.Emit( | |
111 self._templates.Load('cpp_callback_implementation.template'), | |
112 INCLUDES=_GenerateCPPIncludes(cpp_impl_includes), | |
113 INTERFACE=self._interface.id, | |
114 HANDLERS=cpp_impl_handlers_emitter.Fragments()) | |
115 | |
116 def GenerateLibraries(self, lib_dir): | |
117 auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) | |
118 | |
119 # Generate dom_public.dart. | |
120 self._GenerateLibFile( | |
121 'dom_public.darttemplate', | |
122 os.path.join(self._output_dir, 'dom_public.dart'), | |
123 self._dom_public_files, | |
124 AUXILIARY_DIR=MassagePath(auxiliary_dir)); | |
125 | |
126 # Generate dom_impl.dart. | |
127 self._GenerateLibFile( | |
128 'dom_impl.darttemplate', | |
129 os.path.join(self._output_dir, 'dom_impl.dart'), | |
130 self._dom_impl_files, | |
131 AUXILIARY_DIR=MassagePath(auxiliary_dir)); | |
132 | |
133 # Generate DartDerivedSourcesXX.cpp. | |
134 partitions = 20 # FIXME: this should be configurable. | |
135 sources_count = len(self._cpp_impl_files) | |
136 for i in range(0, partitions): | |
137 derived_sources_path = os.path.join(self._output_dir, | |
138 'DartDerivedSources%02i.cpp' % (i + 1)) | |
139 | |
140 includes_emitter = emitter.Emitter() | |
141 for impl_file in self._cpp_impl_files[i::partitions]: | |
142 path = os.path.relpath(impl_file, os.path.dirname(derived_sources_path
)) | |
143 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
144 | |
145 derived_sources_emitter = self._emitters.FileEmitter(derived_sources_path) | |
146 derived_sources_emitter.Emit( | |
147 self._templates.Load('cpp_derived_sources.template'), | |
148 INCLUDES=includes_emitter.Fragments()) | |
149 | |
150 # Generate DartResolver.cpp. | |
151 cpp_resolver_path = os.path.join(self._output_dir, 'DartResolver.cpp') | |
152 | |
153 includes_emitter = emitter.Emitter() | |
154 resolver_body_emitter = emitter.Emitter() | |
155 for file in self._cpp_header_files: | |
156 path = os.path.relpath(file, os.path.dirname(cpp_resolver_path)) | |
157 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
158 resolver_body_emitter.Emit( | |
159 ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argu
mentCount))\n' | |
160 ' return func;\n', | |
161 CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | |
162 | |
163 cpp_resolver_emitter = self._emitters.FileEmitter(cpp_resolver_path) | |
164 cpp_resolver_emitter.Emit( | |
165 self._templates.Load('cpp_resolver.template'), | |
166 INCLUDES=includes_emitter.Fragments(), | |
167 RESOLVER_BODY=resolver_body_emitter.Fragments()) | |
168 | |
169 def Finish(self): | |
170 pass | |
171 | |
172 def _FilePathForDartInterface(self, interface_name): | |
173 return os.path.join(self._output_dir, 'src', 'interface', | |
174 '%s.dart' % interface_name) | |
175 | |
176 def _FilePathForDartImplementation(self, interface_name): | |
177 return os.path.join(self._output_dir, 'dart', | |
178 '%sImplementation.dart' % interface_name) | |
179 | |
180 def _FilePathForDartFactoryProvider(self, interface_name): | |
181 return os.path.join(self._output_dir, 'dart', | |
182 '_%sFactoryProvider.dart' % interface_name) | |
183 | |
184 def _FilePathForDartFactoryProviderImplementation(self, interface_name): | |
185 return os.path.join(self._output_dir, 'dart', | |
186 '%sFactoryProviderImplementation.dart' % interface_name) | |
187 | |
188 def _FilePathForCppHeader(self, interface_name): | |
189 return os.path.join(self._output_dir, 'cpp', 'Dart%s.h' % interface_name) | |
190 | |
191 def _FilePathForCppImplementation(self, interface_name): | |
192 return os.path.join(self._output_dir, 'cpp', 'Dart%s.cpp' % interface_name) | |
193 | |
194 | |
195 class NativeImplementationGenerator(systemwrapping.WrappingInterfaceGenerator): | |
196 """Generates Dart implementation for one DOM IDL interface.""" | |
197 | |
198 def __init__(self, system, interface, super_interface, | |
199 dart_impl_emitter, cpp_header_emitter, cpp_impl_emitter, | |
200 base_members, templates): | |
201 """Generates Dart and C++ code for the given interface. | |
202 | |
203 Args: | |
204 system: The NativeImplementationSystem. | |
205 interface: an IDLInterface instance. It is assumed that all types have | |
206 been converted to Dart types (e.g. int, String), unless they are in | |
207 the same package as the interface. | |
208 super_interface: A string or None, the name of the common interface that | |
209 this interface implements, if any. | |
210 dart_impl_emitter: an Emitter for the file containing the Dart | |
211 implementation class. | |
212 cpp_header_emitter: an Emitter for the file containing the C++ header. | |
213 cpp_impl_emitter: an Emitter for the file containing the C++ | |
214 implementation. | |
215 base_members: a set of names of members defined in a base class. This is | |
216 used to avoid static member 'overriding' in the generated Dart code. | |
217 """ | |
218 self._system = system | |
219 self._interface = interface | |
220 self._super_interface = super_interface | |
221 self._dart_impl_emitter = dart_impl_emitter | |
222 self._cpp_header_emitter = cpp_header_emitter | |
223 self._cpp_impl_emitter = cpp_impl_emitter | |
224 self._base_members = base_members | |
225 self._templates = templates | |
226 self._current_secondary_parent = None | |
227 | |
228 def StartInterface(self): | |
229 self._class_name = self._ImplClassName(self._interface.id) | |
230 self._interface_type_info = GetIDLTypeInfo(self._interface.id) | |
231 self._members_emitter = emitter.Emitter() | |
232 self._cpp_declarations_emitter = emitter.Emitter() | |
233 self._cpp_impl_includes = set() | |
234 self._cpp_definitions_emitter = emitter.Emitter() | |
235 self._cpp_resolver_emitter = emitter.Emitter() | |
236 | |
237 self._GenerateConstructors() | |
238 | |
239 def _GenerateConstructors(self): | |
240 if not self._IsConstructable(): | |
241 return | |
242 | |
243 # TODO(antonm): currently we don't have information about number of argument
s expected by | |
244 # the constructor, so name only dispatch. | |
245 self._cpp_resolver_emitter.Emit( | |
246 ' if (name == "$(INTERFACE_NAME)_constructor_Callback")\n' | |
247 ' return Dart$(INTERFACE_NAME)Internal::constructorCallback;\n', | |
248 INTERFACE_NAME=self._interface.id) | |
249 | |
250 | |
251 constructor_info = AnalyzeConstructor(self._interface) | |
252 if constructor_info: | |
253 self._EmitFactoryProvider(self._interface.id, constructor_info) | |
254 | |
255 if constructor_info is None: | |
256 # We have a custom implementation for it. | |
257 self._cpp_declarations_emitter.Emit( | |
258 '\n' | |
259 'void constructorCallback(Dart_NativeArguments);\n') | |
260 return | |
261 | |
262 raises_dom_exceptions = 'ConstructorRaisesException' in self._interface.ext_
attrs | |
263 raises_exceptions = raises_dom_exceptions or len(constructor_info.idl_args)
> 0 | |
264 arguments = [] | |
265 parameter_definitions_emitter = emitter.Emitter() | |
266 create_function = 'create' | |
267 if 'NamedConstructor' in self._interface.ext_attrs: | |
268 raises_exceptions = True | |
269 parameter_definitions_emitter.Emit( | |
270 ' DOMWindow* domWindow = DartUtilities::domWindowForCurrentIs
olate();\n' | |
271 ' if (!domWindow) {\n' | |
272 ' exception = Dart_NewString("Failed to fetch domWindow")
;\n' | |
273 ' goto fail;\n' | |
274 ' }\n' | |
275 ' Document* document = domWindow->document();\n') | |
276 self._cpp_impl_includes.add('"DOMWindow.h"') | |
277 arguments.append('document') | |
278 create_function = 'createForJSConstructor' | |
279 if 'CallWith' in self._interface.ext_attrs: | |
280 call_with = self._interface.ext_attrs['CallWith'] | |
281 if call_with == 'ScriptExecutionContext': | |
282 raises_exceptions = True | |
283 parameter_definitions_emitter.Emit( | |
284 ' ScriptExecutionContext* context = DartUtilities::scriptExec
utionContext();\n' | |
285 ' if (!context) {\n' | |
286 ' exception = Dart_NewString("Failed to create an object"
);\n' | |
287 ' goto fail;\n' | |
288 ' }\n') | |
289 arguments.append('context') | |
290 else: | |
291 raise Exception('Unsupported CallWith=%s attribute' % call_with) | |
292 | |
293 # Process constructor arguments. | |
294 for (i, arg) in enumerate(constructor_info.idl_args): | |
295 self._GenerateParameterAdapter(parameter_definitions_emitter, arg, i - 1) | |
296 arguments.append(arg.id) | |
297 | |
298 function_expression = '%s::%s' % (self._interface_type_info.native_type(), c
reate_function) | |
299 invocation = self._GenerateWebCoreInvocation(function_expression, arguments, | |
300 self._interface.id, self._interface.ext_attrs, raises_dom_exceptions) | |
301 self._GenerateNativeCallback(callback_name='constructorCallback', | |
302 parameter_definitions=parameter_definitions_emitter.Fragments(), | |
303 needs_receiver=False, invocation=invocation, | |
304 raises_exceptions=raises_exceptions) | |
305 | |
306 def _ImplClassName(self, interface_name): | |
307 return interface_name + 'Implementation' | |
308 | |
309 def _IsConstructable(self): | |
310 # FIXME: support ConstructorTemplate. | |
311 return set(['CustomConstructor', 'V8CustomConstructor', 'Constructor', 'Name
dConstructor']) & set(self._interface.ext_attrs) | |
312 | |
313 def _EmitFactoryProvider(self, interface_name, constructor_info): | |
314 factory_provider = '_' + interface_name + 'FactoryProvider' | |
315 implementation_class = interface_name + 'FactoryProviderImplementation' | |
316 implementation_function = 'create' + interface_name | |
317 native_implementation_function = '%s_constructor_Callback' % interface_name | |
318 | |
319 # Emit private factory provider in public library. | |
320 template_file = 'factoryprovider_%s.darttemplate' % interface_name | |
321 template = self._system._templates.TryLoad(template_file) | |
322 if not template: | |
323 template = self._system._templates.Load('factoryprovider.darttemplate') | |
324 | |
325 dart_impl_path = self._system._FilePathForDartFactoryProvider( | |
326 interface_name) | |
327 self._system._dom_public_files.append(dart_impl_path) | |
328 | |
329 emitter = self._system._emitters.FileEmitter(dart_impl_path) | |
330 emitter.Emit( | |
331 template, | |
332 FACTORY_PROVIDER=factory_provider, | |
333 CONSTRUCTOR=interface_name, | |
334 PARAMETERS=constructor_info.ParametersImplementationDeclaration(), | |
335 IMPL_CLASS=implementation_class, | |
336 IMPL_FUNCTION=implementation_function, | |
337 ARGUMENTS=constructor_info.ParametersAsArgumentList()) | |
338 | |
339 # Emit public implementation in implementation libary. | |
340 dart_impl_path = self._system._FilePathForDartFactoryProviderImplementation( | |
341 interface_name) | |
342 self._system._dom_impl_files.append(dart_impl_path) | |
343 emitter = self._system._emitters.FileEmitter(dart_impl_path) | |
344 emitter.Emit( | |
345 'class $IMPL_CLASS {\n' | |
346 ' static $INTERFACE_NAME $IMPL_FUNCTION($PARAMETERS)\n' | |
347 ' native "$NATIVE_NAME";\n' | |
348 '}', | |
349 INTERFACE_NAME=interface_name, | |
350 PARAMETERS=constructor_info.ParametersImplementationDeclaration(), | |
351 IMPL_CLASS=implementation_class, | |
352 IMPL_FUNCTION=implementation_function, | |
353 NATIVE_NAME=native_implementation_function) | |
354 | |
355 def FinishInterface(self): | |
356 base = self._BaseClassName(self._interface) | |
357 self._dart_impl_emitter.Emit( | |
358 self._templates.Load('dart_implementation.darttemplate'), | |
359 CLASS=self._class_name, BASE=base, INTERFACE=self._interface.id, | |
360 MEMBERS=self._members_emitter.Fragments()) | |
361 | |
362 self._GenerateCppHeader() | |
363 | |
364 self._cpp_impl_emitter.Emit( | |
365 self._templates.Load('cpp_implementation.template'), | |
366 INTERFACE=self._interface.id, | |
367 INCLUDES=_GenerateCPPIncludes(self._cpp_impl_includes), | |
368 CALLBACKS=self._cpp_definitions_emitter.Fragments(), | |
369 RESOLVER=self._cpp_resolver_emitter.Fragments()) | |
370 | |
371 def _GenerateCppHeader(self): | |
372 webcore_includes = _GenerateCPPIncludes(self._interface_type_info.webcore_in
cludes()) | |
373 | |
374 if ('CustomToJS' in self._interface.ext_attrs or | |
375 'CustomToJSObject' in self._interface.ext_attrs or | |
376 'PureInterface' in self._interface.ext_attrs or | |
377 'CPPPureInterface' in self._interface.ext_attrs or | |
378 self._interface_type_info.custom_to_dart()): | |
379 to_dart_value_template = ( | |
380 'Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value);\n') | |
381 else: | |
382 to_dart_value_template = ( | |
383 'inline Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value)\n' | |
384 '{\n' | |
385 ' return DartDOMWrapper::toDart<Dart$(INTERFACE)>(value);\n' | |
386 '}\n') | |
387 to_dart_value_emitter = emitter.Emitter() | |
388 to_dart_value_emitter.Emit( | |
389 to_dart_value_template, | |
390 INTERFACE=self._interface.id, | |
391 WEBCORE_CLASS_NAME=self._interface_type_info.native_type()) | |
392 | |
393 self._cpp_header_emitter.Emit( | |
394 self._templates.Load('cpp_header.template'), | |
395 INTERFACE=self._interface.id, | |
396 WEBCORE_INCLUDES=webcore_includes, | |
397 WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | |
398 TO_DART_VALUE=to_dart_value_emitter.Fragments(), | |
399 DECLARATIONS=self._cpp_declarations_emitter.Fragments()) | |
400 | |
401 def _GenerateCallWithHandling(self, node, parameter_definitions_emitter, argum
ents): | |
402 if 'CallWith' not in node.ext_attrs: | |
403 return False | |
404 | |
405 call_with = node.ext_attrs['CallWith'] | |
406 if call_with == 'ScriptExecutionContext': | |
407 parameter_definitions_emitter.Emit( | |
408 '\n' | |
409 ' ScriptExecutionContext* context = DartUtilities::scriptExecut
ionContext();\n' | |
410 ' if (!context)\n' | |
411 ' return;\n') | |
412 arguments.append('context') | |
413 return False | |
414 | |
415 if call_with == 'ScriptArguments|CallStack': | |
416 self._cpp_impl_includes.add('"DOMWindow.h"') | |
417 self._cpp_impl_includes.add('"ScriptArguments.h"') | |
418 self._cpp_impl_includes.add('"ScriptCallStack.h"') | |
419 self._cpp_impl_includes.add('"V8Proxy.h"') | |
420 self._cpp_impl_includes.add('"v8.h"') | |
421 parameter_definitions_emitter.Emit( | |
422 '\n' | |
423 ' v8::HandleScope handleScope;\n' | |
424 ' v8::Context::Scope scope(V8Proxy::mainWorldContext(DartUtilit
ies::domWindowForCurrentIsolate()->frame()));\n' | |
425 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $IN
DEX);\n' | |
426 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::create
ScriptArguments(customArgument, exception));\n' | |
427 ' if (!scriptArguments)\n' | |
428 ' goto fail;\n' | |
429 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::create
ScriptCallStack());\n' | |
430 ' if (!scriptCallStack->size())\n' | |
431 ' return;\n', | |
432 INDEX=len(node.arguments)) | |
433 arguments.extend(['scriptArguments', 'scriptCallStack']) | |
434 return True | |
435 | |
436 return False | |
437 | |
438 def AddAttribute(self, getter, setter): | |
439 # FIXME: Dartium does not support attribute event listeners. However, JS | |
440 # implementation falls back to them when addEventListener is not available. | |
441 # Make sure addEventListener is available in all EventTargets and remove | |
442 # this check. | |
443 if (getter or setter).type.id == 'EventListener': | |
444 return | |
445 | |
446 if 'CheckSecurityForNode' in (getter or setter).ext_attrs: | |
447 # FIXME: exclude from interface as well. | |
448 return | |
449 | |
450 # FIXME: these should go away. | |
451 classes_with_unsupported_custom_getters = [ | |
452 'Clipboard', 'Console', 'Coordinates', 'DeviceMotionEvent', | |
453 'DeviceOrientationEvent', 'FileReader', 'JavaScriptCallFrame', | |
454 'HTMLInputElement', 'HTMLOptionsCollection', 'HTMLOutputElement', | |
455 'ScriptProfileNode', 'WebKitAnimation'] | |
456 if (self._interface.id in classes_with_unsupported_custom_getters and | |
457 getter and set(['Custom', 'CustomGetter']) & set(getter.ext_attrs)): | |
458 return | |
459 | |
460 if getter: | |
461 self._AddGetter(getter) | |
462 if setter: | |
463 self._AddSetter(setter) | |
464 | |
465 def _AddGetter(self, attr): | |
466 type_info = GetIDLTypeInfo(attr.type.id) | |
467 dart_declaration = '%s get %s()' % ( | |
468 type_info.dart_type(), DartDomNameOfAttribute(attr)) | |
469 is_custom = 'Custom' in attr.ext_attrs or 'CustomGetter' in attr.ext_attrs | |
470 cpp_callback_name = self._GenerateNativeBinding(attr.id, 1, | |
471 dart_declaration, 'Getter', is_custom) | |
472 if is_custom: | |
473 return | |
474 | |
475 arguments = [] | |
476 parameter_definitions_emitter = emitter.Emitter() | |
477 raises_exceptions = self._GenerateCallWithHandling(attr, parameter_definitio
ns_emitter, arguments) | |
478 raises_exceptions = raises_exceptions or attr.get_raises | |
479 | |
480 if 'Reflect' in attr.ext_attrs: | |
481 webcore_function_name = GetIDLTypeInfo(attr.type.id).webcore_getter_name() | |
482 if 'URL' in attr.ext_attrs: | |
483 if 'NonEmpty' in attr.ext_attrs: | |
484 webcore_function_name = 'getNonEmptyURLAttribute' | |
485 else: | |
486 webcore_function_name = 'getURLAttribute' | |
487 arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | |
488 else: | |
489 if attr.id == 'operator': | |
490 webcore_function_name = '_operator' | |
491 elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString': | |
492 webcore_function_name = 'svgTarget' | |
493 else: | |
494 webcore_function_name = re.sub(r'^(HTML|URL|JS|XML|XSLT|\w)', | |
495 lambda s: s.group(1).lower(), | |
496 attr.id) | |
497 webcore_function_name = re.sub(r'^(create|exclusive)', | |
498 lambda s: 'is' + s.group(1).capitalize(), | |
499 webcore_function_name) | |
500 if attr.type.id.startswith('SVGAnimated'): | |
501 webcore_function_name += 'Animated' | |
502 | |
503 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
504 invocation = self._GenerateWebCoreInvocation(function_expression, | |
505 arguments, attr.type.id, attr.ext_attrs, attr.get_raises) | |
506 self._GenerateNativeCallback(cpp_callback_name, parameter_definitions_emitte
r.Fragments(), | |
507 True, invocation, raises_exceptions=raises_exceptions) | |
508 | |
509 def _AddSetter(self, attr): | |
510 type_info = GetIDLTypeInfo(attr.type.id) | |
511 dart_declaration = 'void set %s(%s)' % ( | |
512 DartDomNameOfAttribute(attr), type_info.dart_type()) | |
513 is_custom = set(['Custom', 'CustomSetter', 'V8CustomSetter']) & set(attr.ext
_attrs) | |
514 cpp_callback_name = self._GenerateNativeBinding(attr.id, 2, | |
515 dart_declaration, 'Setter', is_custom) | |
516 if is_custom: | |
517 return | |
518 | |
519 arguments = [] | |
520 parameter_definitions_emitter = emitter.Emitter() | |
521 self._GenerateCallWithHandling(attr, parameter_definitions_emitter, argument
s) | |
522 | |
523 if 'Reflect' in attr.ext_attrs: | |
524 webcore_function_name = GetIDLTypeInfo(attr.type.id).webcore_setter_name() | |
525 arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | |
526 else: | |
527 webcore_function_name = re.sub(r'^(xml(?=[A-Z])|\w)', | |
528 lambda s: s.group(1).upper(), | |
529 attr.id) | |
530 webcore_function_name = 'set%s' % webcore_function_name | |
531 if attr.type.id.startswith('SVGAnimated'): | |
532 webcore_function_name += 'Animated' | |
533 | |
534 arguments.append('value') | |
535 | |
536 self._GenerateParameterAdapter( | |
537 parameter_definitions_emitter, attr, 0, adapter_name='value') | |
538 parameter_definitions = parameter_definitions_emitter.Fragments() | |
539 | |
540 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
541 invocation = self._GenerateWebCoreInvocation(function_expression, | |
542 arguments, 'void', attr.ext_attrs, attr.set_raises) | |
543 | |
544 self._GenerateNativeCallback(cpp_callback_name, parameter_definitions_emitte
r.Fragments(), | |
545 True, invocation, raises_exceptions=True) | |
546 | |
547 def _HasNativeIndexGetter(self, interface): | |
548 return ('CustomIndexedGetter' in interface.ext_attrs or | |
549 'NumericIndexedGetter' in interface.ext_attrs) | |
550 | |
551 def _EmitNativeIndexGetter(self, interface, element_type): | |
552 dart_declaration = '%s operator[](int index)' % element_type | |
553 self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration, | |
554 'Callback', True) | |
555 | |
556 def _EmitNativeIndexSetter(self, interface, element_type): | |
557 dart_declaration = 'void operator[]=(int index, %s value)' % element_type | |
558 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, | |
559 'Callback', True) | |
560 | |
561 def AddOperation(self, info): | |
562 """ | |
563 Arguments: | |
564 info: An OperationInfo object. | |
565 """ | |
566 | |
567 if 'CheckSecurityForNode' in info.overloads[0].ext_attrs: | |
568 # FIXME: exclude from interface as well. | |
569 return | |
570 | |
571 if 'Custom' in info.overloads[0].ext_attrs: | |
572 parameters = info.ParametersImplementationDeclaration() | |
573 dart_declaration = '%s %s(%s)' % (info.type_name, info.name, parameters) | |
574 argument_count = 1 + len(info.arg_infos) | |
575 self._GenerateNativeBinding(info.name, argument_count, dart_declaration, | |
576 'Callback', True) | |
577 return | |
578 | |
579 body = self._members_emitter.Emit( | |
580 '\n' | |
581 ' $TYPE $NAME($PARAMETERS) {\n' | |
582 '$!BODY' | |
583 ' }\n', | |
584 TYPE=info.type_name, | |
585 NAME=info.name, | |
586 PARAMETERS=info.ParametersImplementationDeclaration()) | |
587 | |
588 # Process in order of ascending number of arguments to ensure missing | |
589 # optional arguments are processed early. | |
590 overloads = sorted(info.overloads, | |
591 key=lambda overload: len(overload.arguments)) | |
592 self._native_version = 0 | |
593 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
594 if fallthrough: | |
595 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
596 | |
597 def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): | |
598 """Generates a call to a single operation. | |
599 | |
600 Arguments: | |
601 dispatch_emitter: an dispatch_emitter for the body of a block of code. | |
602 info: the compound information about the operation and its overloads. | |
603 indent: an indentation string for generated code. | |
604 operation: the IDLOperation to call. | |
605 """ | |
606 | |
607 self._native_version += 1 | |
608 native_name = info.name | |
609 if self._native_version > 1: | |
610 native_name = '%s_%s' % (native_name, self._native_version) | |
611 argument_list = ', '.join([info.arg_infos[i][0] | |
612 for (i, arg) in enumerate(operation.arguments)]) | |
613 | |
614 # Generate dispatcher. | |
615 if info.type_name != 'void': | |
616 dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n', | |
617 INDENT=indent, | |
618 NATIVENAME=native_name, | |
619 ARGS=argument_list) | |
620 else: | |
621 dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n' | |
622 '$(INDENT)return;\n', | |
623 INDENT=indent, | |
624 NATIVENAME=native_name, | |
625 ARGS=argument_list) | |
626 # Generate binding. | |
627 dart_declaration = '%s _%s(%s)' % (info.type_name, native_name, | |
628 argument_list) | |
629 is_custom = 'Custom' in operation.ext_attrs | |
630 cpp_callback_name = self._GenerateNativeBinding( | |
631 native_name, 1 + len(operation.arguments), dart_declaration, 'Callback', | |
632 is_custom) | |
633 if is_custom: | |
634 return | |
635 | |
636 # Generate callback. | |
637 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i
d) | |
638 | |
639 parameter_definitions_emitter = emitter.Emitter() | |
640 arguments = [] | |
641 raises_exceptions = self._GenerateCallWithHandling( | |
642 operation, parameter_definitions_emitter, arguments) | |
643 raises_exceptions = raises_exceptions or len(operation.arguments) > 0 or ope
ration.raises | |
644 | |
645 # Process Dart arguments. | |
646 for (i, argument) in enumerate(operation.arguments): | |
647 if (i == len(operation.arguments) - 1 and | |
648 self._interface.id == 'Console' and | |
649 argument.id == 'arg'): | |
650 # FIXME: we are skipping last argument here because it was added in | |
651 # supplemental dart.idl. Cleanup dart.idl and remove this check. | |
652 break | |
653 self._GenerateParameterAdapter(parameter_definitions_emitter, argument, i) | |
654 arguments.append(argument.id) | |
655 | |
656 if operation.id in ['addEventListener', 'removeEventListener']: | |
657 # addEventListener's and removeEventListener's last argument is marked | |
658 # as optional in idl, but is not optional in webcore implementation. | |
659 if len(operation.arguments) == 2: | |
660 arguments.append('false') | |
661 | |
662 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope
rty': | |
663 # CSSStyleDeclaration.setProperty priority parameter is optional in Dart | |
664 # idl, but is not optional in webcore implementation. | |
665 if len(operation.arguments) == 2: | |
666 arguments.append('String()') | |
667 | |
668 if 'NeedsUserGestureCheck' in operation.ext_attrs: | |
669 arguments.append('DartUtilities::processingUserGesture') | |
670 | |
671 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, operation) | |
672 invocation = self._GenerateWebCoreInvocation(function_expression, arguments, | |
673 operation.type.id, operation.ext_attrs, operation.raises) | |
674 self._GenerateNativeCallback(cpp_callback_name, | |
675 parameter_definitions=parameter_definitions_emitter.Fragments(), | |
676 needs_receiver=True, invocation=invocation, | |
677 raises_exceptions=raises_exceptions) | |
678 | |
679 def _GenerateNativeCallback(self, callback_name, parameter_definitions, | |
680 needs_receiver, invocation, raises_exceptions): | |
681 | |
682 if needs_receiver: | |
683 parameter_definitions = emitter.Format( | |
684 ' $WEBCORE_CLASS_NAME* receiver = DartDOMWrapper::receiver< $WE
BCORE_CLASS_NAME >(args);\n' | |
685 ' $PARAMETER_DEFINITIONS\n', | |
686 WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | |
687 PARAMETER_DEFINITIONS=parameter_definitions) | |
688 | |
689 body = emitter.Format( | |
690 ' {\n' | |
691 '$PARAMETER_DEFINITIONS' | |
692 '$INVOCATION' | |
693 ' return;\n' | |
694 ' }\n', | |
695 PARAMETER_DEFINITIONS=parameter_definitions, | |
696 INVOCATION=invocation) | |
697 | |
698 if raises_exceptions: | |
699 body = emitter.Format( | |
700 ' Dart_Handle exception;\n' | |
701 '$BODY' | |
702 '\n' | |
703 'fail:\n' | |
704 ' Dart_ThrowException(exception);\n' | |
705 ' ASSERT_NOT_REACHED();\n', | |
706 BODY=body) | |
707 | |
708 self._cpp_definitions_emitter.Emit( | |
709 '\n' | |
710 'static void $CALLBACK_NAME(Dart_NativeArguments args)\n' | |
711 '{\n' | |
712 ' DartApiScope dartApiScope;\n' | |
713 '$BODY' | |
714 '}\n', | |
715 CALLBACK_NAME=callback_name, | |
716 BODY=body) | |
717 | |
718 def _GenerateParameterAdapter(self, emitter, idl_node, index, | |
719 adapter_name=None): | |
720 """idl_node is IDLArgument or IDLAttribute.""" | |
721 type_info = GetIDLTypeInfo(idl_node.type.id) | |
722 (adapter_type, include_name) = type_info.parameter_adapter_info() | |
723 if include_name: | |
724 self._cpp_impl_includes.add(include_name) | |
725 flags = '' | |
726 if (idl_node.ext_attrs.get('Optional') == 'DefaultIsNullString' or | |
727 'RequiredCppParameter' in idl_node.ext_attrs): | |
728 flags = ', DartUtilities::ConvertNullToDefaultValue' | |
729 emitter.Emit( | |
730 '\n' | |
731 ' const $ADAPTER_TYPE $NAME(Dart_GetNativeArgument(args, $INDEX)$
FLAGS);\n' | |
732 ' if (!$NAME.conversionSuccessful()) {\n' | |
733 ' exception = $NAME.exception();\n' | |
734 ' goto fail;\n' | |
735 ' }\n', | |
736 ADAPTER_TYPE=adapter_type, | |
737 NAME=adapter_name or idl_node.id, | |
738 INDEX=index + 1, | |
739 FLAGS=flags) | |
740 | |
741 def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration, | |
742 native_suffix, is_custom): | |
743 native_binding = '%s_%s_%s' % (self._interface.id, idl_name, native_suffix) | |
744 self._members_emitter.Emit( | |
745 '\n' | |
746 ' $DART_DECLARATION native "$NATIVE_BINDING";\n', | |
747 DART_DECLARATION=dart_declaration, NATIVE_BINDING=native_binding) | |
748 | |
749 cpp_callback_name = '%s%s' % (idl_name, native_suffix) | |
750 self._cpp_resolver_emitter.Emit( | |
751 ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n' | |
752 ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n', | |
753 ARGC=argument_count, | |
754 NATIVE_BINDING=native_binding, | |
755 INTERFACE_NAME=self._interface.id, | |
756 CPP_CALLBACK_NAME=cpp_callback_name) | |
757 | |
758 if is_custom: | |
759 self._cpp_declarations_emitter.Emit( | |
760 '\n' | |
761 'void $CPP_CALLBACK_NAME(Dart_NativeArguments);\n', | |
762 CPP_CALLBACK_NAME=cpp_callback_name) | |
763 | |
764 return cpp_callback_name | |
765 | |
766 def _GenerateWebCoreReflectionAttributeName(self, attr): | |
767 namespace = 'HTMLNames' | |
768 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | |
769 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | |
770 'onmouseup', 'onresize', 'onscroll', 'onunload'] | |
771 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | |
772 namespace = 'SVGNames' | |
773 self._cpp_impl_includes.add('"%s.h"' % namespace) | |
774 | |
775 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | |
776 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | |
777 | |
778 def _GenerateWebCoreFunctionExpression(self, function_name, idl_node): | |
779 if 'ImplementedBy' in idl_node.ext_attrs: | |
780 return '%s::%s' % (idl_node.ext_attrs['ImplementedBy'], function_name) | |
781 return '%s%s' % (self._interface_type_info.receiver(), function_name) | |
782 | |
783 def _GenerateWebCoreInvocation(self, function_expression, arguments, | |
784 idl_return_type, attributes, raises_dom_exceptions): | |
785 invocation_template = ' $FUNCTION_CALL;\n' | |
786 if idl_return_type != 'void': | |
787 return_type_info = GetIDLTypeInfo(idl_return_type) | |
788 self._cpp_impl_includes |= set(return_type_info.conversion_includes()) | |
789 | |
790 # Generate C++ cast based on idl return type. | |
791 conversion_cast = return_type_info.conversion_cast('$FUNCTION_CALL') | |
792 if isinstance(return_type_info, SVGTearOffIDLTypeInfo): | |
793 svg_primitive_types = ['SVGAngle', 'SVGLength', 'SVGMatrix', | |
794 'SVGNumber', 'SVGPoint', 'SVGRect', 'SVGTransform'] | |
795 conversion_cast = '%s::create($FUNCTION_CALL)' | |
796 if self._interface.id.startswith('SVGAnimated'): | |
797 conversion_cast = 'static_cast<%s*>($FUNCTION_CALL)' | |
798 elif return_type_info.idl_type() == 'SVGStringList': | |
799 conversion_cast = '%s::create(receiver, $FUNCTION_CALL)' | |
800 elif self._interface.id.endswith('List'): | |
801 conversion_cast = 'static_cast<%s*>($FUNCTION_CALL.get())' | |
802 elif return_type_info.idl_type() in svg_primitive_types: | |
803 conversion_cast = '%s::create($FUNCTION_CALL)' | |
804 else: | |
805 conversion_cast = 'static_cast<%s*>($FUNCTION_CALL)' | |
806 conversion_cast = conversion_cast % return_type_info.native_type() | |
807 | |
808 # Generate to Dart conversion of C++ value. | |
809 conversion_arguments = [conversion_cast] | |
810 if (return_type_info.idl_type() in ['DOMString', 'AtomicString'] and | |
811 'TreatReturnedNullStringAs' in attributes): | |
812 conversion_arguments.append('ConvertDefaultToNull') | |
813 | |
814 invocation_template = emitter.Format( | |
815 ' Dart_Handle returnValue = toDartValue($ARGUMENTS);\n' | |
816 ' if (returnValue)\n' | |
817 ' Dart_SetReturnValue(args, returnValue);\n', | |
818 ARGUMENTS=', '.join(conversion_arguments)) | |
819 | |
820 if raises_dom_exceptions: | |
821 # Add 'ec' argument to WebCore invocation and convert DOM exception to Dar
t exception. | |
822 arguments.append('ec') | |
823 invocation_template = emitter.Format( | |
824 ' ExceptionCode ec = 0;\n' | |
825 '$INVOCATION' | |
826 ' if (UNLIKELY(ec)) {\n' | |
827 ' exception = DartDOMWrapper::exceptionCodeToDartException(
ec);\n' | |
828 ' goto fail;\n' | |
829 ' }\n', | |
830 INVOCATION=invocation_template) | |
831 | |
832 if 'ImplementedBy' in attributes: | |
833 arguments.insert(0, 'receiver') | |
834 self._cpp_impl_includes.add('"%s.h"' % attributes['ImplementedBy']) | |
835 | |
836 return emitter.Format(invocation_template, | |
837 FUNCTION_CALL='%s(%s)' % (function_expression, ', '.join(arguments))) | |
838 | |
839 def _GenerateCPPIncludes(includes): | |
840 return ''.join(['#include %s\n' % include for include in includes]) | |
OLD | NEW |