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 from generator import * | |
12 from htmldartgenerator import * | |
13 | |
14 class DartiumBackend(HtmlDartGenerator): | |
15 """Generates Dart implementation for one DOM IDL interface.""" | |
16 | |
17 def __init__(self, interface, cpp_library_emitter, options): | |
18 super(DartiumBackend, self).__init__(interface, options) | |
19 | |
20 self._interface = interface | |
21 self._cpp_library_emitter = cpp_library_emitter | |
22 self._database = options.database | |
23 self._template_loader = options.templates | |
24 self._type_registry = options.type_registry | |
25 self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) | |
26 | |
27 def ImplementsMergedMembers(self): | |
28 # We could not add merged functions to implementation class because | |
29 # underlying c++ object doesn't implement them. Merged functions are | |
30 # generated on merged interface implementation instead. | |
31 return False | |
32 | |
33 def CustomJSMembers(self): | |
34 return {} | |
35 | |
36 def GenerateCallback(self, info): | |
37 if IsPureInterface(self._interface.id): | |
38 return | |
39 | |
40 cpp_impl_includes = set() | |
41 cpp_header_handlers_emitter = emitter.Emitter() | |
42 cpp_impl_handlers_emitter = emitter.Emitter() | |
43 class_name = 'Dart%s' % self._interface.id | |
44 for operation in self._interface.operations: | |
45 parameters = [] | |
46 arguments = [] | |
47 conversion_includes = [] | |
48 for argument in operation.arguments: | |
49 argument_type_info = self._TypeInfo(argument.type.id) | |
50 parameters.append('%s %s' % (argument_type_info.parameter_type(), | |
51 argument.id)) | |
52 arguments.append(argument_type_info.to_dart_conversion(argument.id)) | |
53 conversion_includes.extend(argument_type_info.conversion_includes()) | |
54 | |
55 cpp_header_handlers_emitter.Emit( | |
56 '\n' | |
57 ' virtual bool handleEvent($PARAMETERS);\n', | |
58 PARAMETERS=', '.join(parameters)) | |
59 | |
60 if 'Custom' in operation.ext_attrs: | |
61 continue | |
62 | |
63 cpp_impl_includes |= set(conversion_includes) | |
64 arguments_declaration = 'Dart_Handle arguments[] = { %s }' % ', '.join(arg
uments) | |
65 if not len(arguments): | |
66 arguments_declaration = 'Dart_Handle* arguments = 0' | |
67 cpp_impl_handlers_emitter.Emit( | |
68 '\n' | |
69 'bool $CLASS_NAME::handleEvent($PARAMETERS)\n' | |
70 '{\n' | |
71 ' if (!m_callback.isIsolateAlive())\n' | |
72 ' return false;\n' | |
73 ' DartIsolateScope scope(m_callback.isolate());\n' | |
74 ' DartApiScope apiScope;\n' | |
75 ' $ARGUMENTS_DECLARATION;\n' | |
76 ' return m_callback.handleEvent($ARGUMENT_COUNT, arguments);\n' | |
77 '}\n', | |
78 CLASS_NAME=class_name, | |
79 PARAMETERS=', '.join(parameters), | |
80 ARGUMENTS_DECLARATION=arguments_declaration, | |
81 ARGUMENT_COUNT=len(arguments)) | |
82 | |
83 cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter( | |
84 self._interface.id, | |
85 self._renamer.GetLibraryName(self._interface), | |
86 True) | |
87 cpp_header_emitter.Emit( | |
88 self._template_loader.Load('cpp_callback_header.template'), | |
89 INTERFACE=self._interface.id, | |
90 HANDLERS=cpp_header_handlers_emitter.Fragments()) | |
91 | |
92 cpp_impl_emitter = self._cpp_library_emitter.CreateSourceEmitter(self._inter
face.id) | |
93 cpp_impl_emitter.Emit( | |
94 self._template_loader.Load('cpp_callback_implementation.template'), | |
95 INCLUDES=self._GenerateCPPIncludes(cpp_impl_includes), | |
96 INTERFACE=self._interface.id, | |
97 HANDLERS=cpp_impl_handlers_emitter.Fragments()) | |
98 | |
99 def ImplementationTemplate(self): | |
100 template = None | |
101 interface_name = self._interface.doc_js_name | |
102 if interface_name == self._interface.id or not self._database.HasInterface(i
nterface_name): | |
103 template_file = 'impl_%s.darttemplate' % interface_name | |
104 template = self._template_loader.TryLoad(template_file) | |
105 if not template: | |
106 template = self._template_loader.Load('dart_implementation.darttemplate') | |
107 return template | |
108 | |
109 def RootClassName(self): | |
110 return 'NativeFieldWrapperClass1' | |
111 | |
112 def NativeSpec(self): | |
113 return '' | |
114 | |
115 def StartInterface(self, memebers_emitter): | |
116 # Create emitters for c++ implementation. | |
117 if not IsPureInterface(self._interface.id): | |
118 self._cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter( | |
119 self._interface.id, | |
120 self._renamer.GetLibraryName(self._interface)) | |
121 self._cpp_impl_emitter = self._cpp_library_emitter.CreateSourceEmitter(sel
f._interface.id) | |
122 else: | |
123 self._cpp_header_emitter = emitter.Emitter() | |
124 self._cpp_impl_emitter = emitter.Emitter() | |
125 | |
126 self._interface_type_info = self._TypeInfo(self._interface.id) | |
127 self._members_emitter = memebers_emitter | |
128 self._cpp_declarations_emitter = emitter.Emitter() | |
129 self._cpp_impl_includes = set() | |
130 self._cpp_definitions_emitter = emitter.Emitter() | |
131 self._cpp_resolver_emitter = emitter.Emitter() | |
132 | |
133 # We need to revisit our treatment of typed arrays, right now | |
134 # it is full of hacks. | |
135 if self._interface.ext_attrs.get('ConstructorTemplate') == 'TypedArray': | |
136 self._cpp_resolver_emitter.Emit( | |
137 ' if (name == "$(INTERFACE_NAME)_constructor_Callback")\n' | |
138 ' return Dart$(INTERFACE_NAME)Internal::constructorCallback;\n'
, | |
139 INTERFACE_NAME=self._interface.id) | |
140 | |
141 self._cpp_impl_includes.add('"DartArrayBufferViewCustom.h"'); | |
142 self._cpp_definitions_emitter.Emit( | |
143 '\n' | |
144 'static void constructorCallback(Dart_NativeArguments args)\n' | |
145 '{\n' | |
146 ' WebCore::DartArrayBufferViewInternal::constructWebGLArray<Dart$(INT
ERFACE_NAME)>(args);\n' | |
147 '}\n', | |
148 INTERFACE_NAME=self._interface.id); | |
149 | |
150 def EmitHelpers(self, base_class): | |
151 # Emit internal constructor which is necessary for Dartium bindings | |
152 # to construct wrappers from C++. Eventually it should go away | |
153 # once it is possible to construct such an instance directly. | |
154 super_constructor = '' | |
155 if base_class and base_class != 'NativeFieldWrapperClass1': | |
156 super_constructor = ' : super.internal()' | |
157 self._members_emitter.Emit( | |
158 ' $CLASSNAME.internal()$SUPERCONSTRUCTOR;\n', | |
159 CLASSNAME=self._interface_type_info.implementation_name(), | |
160 SUPERCONSTRUCTOR=super_constructor) | |
161 | |
162 def EmitStaticFactory(self, constructor_info): | |
163 constructor_callback_id = self._interface.id + '_constructor_Callback' | |
164 | |
165 self._members_emitter.Emit( | |
166 ' static $INTERFACE_NAME _create($PARAMETERS_DECLARATION) ' | |
167 'native "$CONSTRUCTOR_CALLBACK_ID";\n', | |
168 INTERFACE_NAME=self._interface_type_info.interface_name(), | |
169 PARAMETERS_DECLARATION=constructor_info.ParametersDeclaration( | |
170 self._DartType), | |
171 CONSTRUCTOR_CALLBACK_ID=constructor_callback_id) | |
172 | |
173 # TODO(antonm): currently we don't have information about number of argument
s expected by | |
174 # the constructor, so name only dispatch. | |
175 self._cpp_resolver_emitter.Emit( | |
176 ' if (name == "$CONSTRUCTOR_CALLBACK_ID")\n' | |
177 ' return Dart$(WEBKIT_INTERFACE_NAME)Internal::constructorCallbac
k;\n', | |
178 CONSTRUCTOR_CALLBACK_ID=constructor_callback_id, | |
179 WEBKIT_INTERFACE_NAME=self._interface.id) | |
180 | |
181 ext_attrs = self._interface.ext_attrs | |
182 | |
183 if 'CustomConstructor' in ext_attrs: | |
184 # We have a custom implementation for it. | |
185 self._cpp_declarations_emitter.Emit( | |
186 '\n' | |
187 'void constructorCallback(Dart_NativeArguments);\n') | |
188 return | |
189 | |
190 create_function = 'create' | |
191 if 'NamedConstructor' in ext_attrs: | |
192 create_function = 'createForJSConstructor' | |
193 function_expression = '%s::%s' % (self._interface_type_info.native_type(), c
reate_function) | |
194 self._GenerateNativeCallback( | |
195 'constructorCallback', | |
196 False, | |
197 function_expression, | |
198 self._interface, | |
199 constructor_info.idl_args, | |
200 self._interface.id, | |
201 'ConstructorRaisesException' in ext_attrs) | |
202 | |
203 def FinishInterface(self): | |
204 self._GenerateCPPHeader() | |
205 | |
206 self._cpp_impl_emitter.Emit( | |
207 self._template_loader.Load('cpp_implementation.template'), | |
208 INTERFACE=self._interface.id, | |
209 INCLUDES=self._GenerateCPPIncludes(self._cpp_impl_includes), | |
210 CALLBACKS=self._cpp_definitions_emitter.Fragments(), | |
211 RESOLVER=self._cpp_resolver_emitter.Fragments(), | |
212 DART_IMPLEMENTATION_CLASS=self._interface_type_info.implementation_name(
), | |
213 DART_IMPLEMENTATION_LIBRARY='dart:%s' % self._renamer.GetLibraryName(sel
f._interface)) | |
214 | |
215 def _GenerateCPPHeader(self): | |
216 to_native_emitter = emitter.Emitter() | |
217 if self._interface_type_info.custom_to_native(): | |
218 to_native_emitter.Emit( | |
219 ' static PassRefPtr<NativeType> toNative(Dart_Handle handle, Dart_H
andle& exception);\n') | |
220 else: | |
221 to_native_emitter.Emit( | |
222 ' static NativeType* toNative(Dart_Handle handle, Dart_Handle& exce
ption)\n' | |
223 ' {\n' | |
224 ' return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(hand
le, exception);\n' | |
225 ' }\n', | |
226 INTERFACE=self._interface.id) | |
227 | |
228 to_dart_emitter = emitter.Emitter() | |
229 | |
230 ext_attrs = self._interface.ext_attrs | |
231 | |
232 if ('CustomToJS' in ext_attrs or | |
233 ('CustomToJSObject' in ext_attrs and 'TypedArray' not in ext_attrs) or | |
234 'PureInterface' in ext_attrs or | |
235 'CPPPureInterface' in ext_attrs or | |
236 self._interface_type_info.custom_to_dart()): | |
237 to_dart_emitter.Emit( | |
238 ' static Dart_Handle toDart(NativeType* value);\n') | |
239 else: | |
240 to_dart_emitter.Emit( | |
241 ' static Dart_Handle toDart(NativeType* value)\n' | |
242 ' {\n' | |
243 ' return DartDOMWrapper::toDart<Dart$(INTERFACE)>(value);\n' | |
244 ' }\n', | |
245 INTERFACE=self._interface.id) | |
246 | |
247 webcore_includes = self._GenerateCPPIncludes( | |
248 self._interface_type_info.webcore_includes()) | |
249 | |
250 is_node_test = lambda interface: interface.id == 'Node' | |
251 is_active_test = lambda interface: 'ActiveDOMObject' in interface.ext_attrs | |
252 is_event_target_test = lambda interface: 'EventTarget' in interface.ext_attr
s | |
253 def TypeCheckHelper(test): | |
254 return 'true' if any(map(test, self._database.Hierarchy(self._interface)))
else 'false' | |
255 | |
256 self._cpp_header_emitter.Emit( | |
257 self._template_loader.Load('cpp_header.template'), | |
258 INTERFACE=self._interface.id, | |
259 WEBCORE_INCLUDES=webcore_includes, | |
260 WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | |
261 DECLARATIONS=self._cpp_declarations_emitter.Fragments(), | |
262 IS_NODE=TypeCheckHelper(is_node_test), | |
263 IS_ACTIVE=TypeCheckHelper(is_active_test), | |
264 IS_EVENT_TARGET=TypeCheckHelper(is_event_target_test), | |
265 TO_NATIVE=to_native_emitter.Fragments(), | |
266 TO_DART=to_dart_emitter.Fragments()) | |
267 | |
268 def EmitAttribute(self, attribute, html_name, read_only): | |
269 self._AddGetter(attribute, html_name) | |
270 if not read_only: | |
271 self._AddSetter(attribute, html_name) | |
272 | |
273 def _AddGetter(self, attr, html_name): | |
274 type_info = self._TypeInfo(attr.type.id) | |
275 dart_declaration = '%s get %s' % ( | |
276 self.SecureOutputType(attr.type.id), html_name) | |
277 is_custom = 'Custom' in attr.ext_attrs or 'CustomGetter' in attr.ext_attrs | |
278 cpp_callback_name = self._GenerateNativeBinding(attr.id, 1, | |
279 dart_declaration, 'Getter', is_custom) | |
280 if is_custom: | |
281 return | |
282 | |
283 if 'Reflect' in attr.ext_attrs: | |
284 webcore_function_name = self._TypeInfo(attr.type.id).webcore_getter_name() | |
285 if 'URL' in attr.ext_attrs: | |
286 if 'NonEmpty' in attr.ext_attrs: | |
287 webcore_function_name = 'getNonEmptyURLAttribute' | |
288 else: | |
289 webcore_function_name = 'getURLAttribute' | |
290 elif 'ImplementedAs' in attr.ext_attrs: | |
291 webcore_function_name = attr.ext_attrs['ImplementedAs'] | |
292 else: | |
293 if attr.id == 'operator': | |
294 webcore_function_name = '_operator' | |
295 elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString': | |
296 webcore_function_name = 'svgTarget' | |
297 else: | |
298 webcore_function_name = self._ToWebKitName(attr.id) | |
299 if attr.type.id.startswith('SVGAnimated'): | |
300 webcore_function_name += 'Animated' | |
301 | |
302 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
303 self._GenerateNativeCallback( | |
304 cpp_callback_name, | |
305 True, | |
306 function_expression, | |
307 attr, | |
308 [], | |
309 attr.type.id, | |
310 attr.get_raises) | |
311 | |
312 def _AddSetter(self, attr, html_name): | |
313 type_info = self._TypeInfo(attr.type.id) | |
314 dart_declaration = 'void set %s(%s value)' % (html_name, self._DartType(attr
.type.id)) | |
315 is_custom = set(['Custom', 'CustomSetter', 'V8CustomSetter']) & set(attr.ext
_attrs) | |
316 cpp_callback_name = self._GenerateNativeBinding(attr.id, 2, | |
317 dart_declaration, 'Setter', is_custom) | |
318 if is_custom: | |
319 return | |
320 | |
321 if 'Reflect' in attr.ext_attrs: | |
322 webcore_function_name = self._TypeInfo(attr.type.id).webcore_setter_name() | |
323 else: | |
324 webcore_function_name = re.sub(r'^(xml(?=[A-Z])|\w)', | |
325 lambda s: s.group(1).upper(), | |
326 attr.id) | |
327 webcore_function_name = 'set%s' % webcore_function_name | |
328 if attr.type.id.startswith('SVGAnimated'): | |
329 webcore_function_name += 'Animated' | |
330 | |
331 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, attr) | |
332 self._GenerateNativeCallback( | |
333 cpp_callback_name, | |
334 True, | |
335 function_expression, | |
336 attr, | |
337 [attr], | |
338 'void', | |
339 attr.set_raises) | |
340 | |
341 def AddIndexer(self, element_type): | |
342 """Adds all the methods required to complete implementation of List.""" | |
343 # We would like to simply inherit the implementation of everything except | |
344 # length, [], and maybe []=. It is possible to extend from a base | |
345 # array implementation class only when there is no other implementation | |
346 # inheritance. There might be no implementation inheritance other than | |
347 # DOMBaseWrapper for many classes, but there might be some where the | |
348 # array-ness is introduced by a non-root interface: | |
349 # | |
350 # interface Y extends X, List<T> ... | |
351 # | |
352 # In the non-root case we have to choose between: | |
353 # | |
354 # class YImpl extends XImpl { add List<T> methods; } | |
355 # | |
356 # and | |
357 # | |
358 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
359 # | |
360 dart_element_type = self._DartType(element_type) | |
361 if self._HasNativeIndexGetter(): | |
362 self._EmitNativeIndexGetter(dart_element_type) | |
363 else: | |
364 self._members_emitter.Emit( | |
365 '\n' | |
366 ' $TYPE operator[](int index) native "$(INTERFACE)_item_Callback";\n'
, | |
367 TYPE=self.SecureOutputType(element_type), | |
368 INTERFACE=self._interface.id) | |
369 | |
370 if self._HasNativeIndexSetter(): | |
371 self._EmitNativeIndexSetter(dart_element_type) | |
372 else: | |
373 self._members_emitter.Emit( | |
374 '\n' | |
375 ' void operator[]=(int index, $TYPE value) {\n' | |
376 ' throw new UnsupportedError("Cannot assign element of immutable Li
st.");\n' | |
377 ' }\n', | |
378 TYPE=dart_element_type) | |
379 | |
380 self.EmitListMixin(dart_element_type) | |
381 | |
382 def AmendIndexer(self, element_type): | |
383 # If interface is marked as having native indexed | |
384 # getter or setter, we must emit overrides as it's not | |
385 # guaranteed that the corresponding methods in C++ would be | |
386 # virtual. For example, as of time of writing, even though | |
387 # Uint8ClampedArray inherits from Uint8Array, ::set method | |
388 # is not virtual and accessing it through Uint8Array pointer | |
389 # would lead to wrong semantics (modulo vs. clamping.) | |
390 dart_element_type = self._DartType(element_type) | |
391 | |
392 if self._HasNativeIndexGetter(): | |
393 self._EmitNativeIndexGetter(dart_element_type) | |
394 if self._HasNativeIndexSetter(): | |
395 self._EmitNativeIndexSetter(dart_element_type) | |
396 | |
397 def _HasNativeIndexGetter(self): | |
398 ext_attrs = self._interface.ext_attrs | |
399 return ('CustomIndexedGetter' in ext_attrs or | |
400 'NumericIndexedGetter' in ext_attrs) | |
401 | |
402 def _EmitNativeIndexGetter(self, element_type): | |
403 dart_declaration = '%s operator[](int index)' % \ | |
404 self.SecureOutputType(element_type, True) | |
405 self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration, | |
406 'Callback', True) | |
407 | |
408 def _HasNativeIndexSetter(self): | |
409 return 'CustomIndexedSetter' in self._interface.ext_attrs | |
410 | |
411 def _EmitNativeIndexSetter(self, element_type): | |
412 dart_declaration = 'void operator[]=(int index, %s value)' % element_type | |
413 self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, | |
414 'Callback', True) | |
415 | |
416 def EmitOperation(self, info, html_name): | |
417 """ | |
418 Arguments: | |
419 info: An OperationInfo object. | |
420 """ | |
421 | |
422 operation = info.operations[0] | |
423 | |
424 is_custom = 'Custom' in operation.ext_attrs | |
425 has_optional_arguments = any(self._IsArgumentOptionalInWebCore(operation, ar
gument) for argument in operation.arguments) | |
426 needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_option
al_arguments) | |
427 | |
428 dart_declaration = '%s%s %s(%s)' % ( | |
429 'static ' if info.IsStatic() else '', | |
430 self.SecureOutputType(info.type_name), | |
431 html_name, | |
432 info.ParametersDeclaration( | |
433 (lambda x: 'dynamic') if needs_dispatcher else self._DartType)) | |
434 | |
435 if not needs_dispatcher: | |
436 # Bind directly to native implementation | |
437 argument_count = (0 if info.IsStatic() else 1) + len(info.param_infos) | |
438 cpp_callback_name = self._GenerateNativeBinding( | |
439 info.name, argument_count, dart_declaration, 'Callback', is_custom) | |
440 if not is_custom: | |
441 self._GenerateOperationNativeCallback(operation, operation.arguments, cp
p_callback_name) | |
442 else: | |
443 self._GenerateDispatcher(info.operations, dart_declaration, [info.name for
info in info.param_infos]) | |
444 | |
445 def _GenerateDispatcher(self, operations, dart_declaration, argument_names): | |
446 | |
447 body = self._members_emitter.Emit( | |
448 '\n' | |
449 ' $DECLARATION {\n' | |
450 '$!BODY' | |
451 ' }\n', | |
452 DECLARATION=dart_declaration) | |
453 | |
454 version = [1] | |
455 def GenerateCall(operation, argument_count, checks): | |
456 if checks: | |
457 if operation.type.id != 'void': | |
458 template = ' if ($CHECKS) {\n return $CALL;\n }\n' | |
459 else: | |
460 template = ' if ($CHECKS) {\n $CALL;\n return;\n }\n' | |
461 else: | |
462 if operation.type.id != 'void': | |
463 template = ' return $CALL;\n' | |
464 else: | |
465 template = ' $CALL;\n' | |
466 | |
467 overload_name = '%s_%s' % (operation.id, version[0]) | |
468 version[0] += 1 | |
469 argument_list = ', '.join(argument_names[:argument_count]) | |
470 call = '_%s(%s)' % (overload_name, argument_list) | |
471 body.Emit(template, CHECKS=' && '.join(checks), CALL=call) | |
472 | |
473 dart_declaration = '%s%s _%s(%s)' % ( | |
474 'static ' if operation.is_static else '', | |
475 self.SecureOutputType(operation.type.id), | |
476 overload_name, argument_list) | |
477 cpp_callback_name = self._GenerateNativeBinding( | |
478 overload_name, (0 if operation.is_static else 1) + argument_count, | |
479 dart_declaration, 'Callback', False) | |
480 self._GenerateOperationNativeCallback(operation, operation.arguments[:argu
ment_count], cpp_callback_name) | |
481 | |
482 def GenerateChecksAndCall(operation, argument_count): | |
483 checks = [] | |
484 for i in range(0, argument_count): | |
485 argument = operation.arguments[i] | |
486 argument_name = argument_names[i] | |
487 type = self._DartType(argument.type.id) | |
488 if type not in ['dynamic', 'Object']: | |
489 checks.append('(%s is %s || %s == null)' % (argument_name, type, argum
ent_name)) | |
490 checks.extend(['!?%s' % name for name in argument_names[argument_count:]]) | |
491 GenerateCall(operation, argument_count, checks) | |
492 | |
493 # TODO: Optimize the dispatch to avoid repeated checks. | |
494 if len(operations) > 1: | |
495 for operation in operations: | |
496 for position, argument in enumerate(operation.arguments): | |
497 if self._IsArgumentOptionalInWebCore(operation, argument): | |
498 GenerateChecksAndCall(operation, position) | |
499 GenerateChecksAndCall(operation, len(operation.arguments)) | |
500 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
501 else: | |
502 operation = operations[0] | |
503 argument_count = len(operation.arguments) | |
504 for position, argument in list(enumerate(operation.arguments))[::-1]: | |
505 if self._IsArgumentOptionalInWebCore(operation, argument): | |
506 check = '?%s' % argument_names[position] | |
507 # argument_count instead of position + 1 is used here to cover one | |
508 # complicated case with the effectively optional argument in the middl
e. | |
509 # Consider foo(x, [Optional] y, [Optional=DefaultIsNullString] z) | |
510 # (as of now it's modelled after HTMLMediaElement.webkitAddKey). | |
511 # y is optional in WebCore, while z is not. | |
512 # In this case, if y was actually passed, we'd like to emit foo(x, y,
z) invocation, | |
513 # not foo(x, y). | |
514 GenerateCall(operation, argument_count, [check]) | |
515 argument_count = position | |
516 GenerateCall(operation, argument_count, []) | |
517 | |
518 def SecondaryContext(self, interface): | |
519 pass | |
520 | |
521 def _GenerateOperationNativeCallback(self, operation, arguments, cpp_callback_
name): | |
522 webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.i
d) | |
523 function_expression = self._GenerateWebCoreFunctionExpression(webcore_functi
on_name, operation) | |
524 self._GenerateNativeCallback( | |
525 cpp_callback_name, | |
526 not operation.is_static, | |
527 function_expression, | |
528 operation, | |
529 arguments, | |
530 operation.type.id, | |
531 operation.raises) | |
532 | |
533 def _GenerateNativeCallback(self, | |
534 callback_name, | |
535 needs_receiver, | |
536 function_expression, | |
537 node, | |
538 arguments, | |
539 return_type, | |
540 raises_dom_exception): | |
541 ext_attrs = node.ext_attrs | |
542 | |
543 cpp_arguments = [] | |
544 requires_v8_scope = \ | |
545 any((self._TypeInfo(argument.type.id).requires_v8_scope() for argument i
n arguments)) or\ | |
546 self._interface.id.startswith('IDB') | |
547 runtime_check = None | |
548 raises_exceptions = raises_dom_exception or arguments | |
549 | |
550 # TODO(antonm): unify with ScriptState below. | |
551 requires_stack_info = ext_attrs.get('CallWith') == 'ScriptArguments|ScriptSt
ate' | |
552 if requires_stack_info: | |
553 raises_exceptions = True | |
554 requires_v8_scope = True | |
555 cpp_arguments = ['&state', 'scriptArguments.release()'] | |
556 # WebKit uses scriptArguments to reconstruct last argument, so | |
557 # it's not needed and should be just removed. | |
558 arguments = arguments[:-1] | |
559 | |
560 # TODO(antonm): unify with ScriptState below. | |
561 requires_script_arguments = ext_attrs.get('CallWith') == 'ScriptArguments' | |
562 if requires_script_arguments: | |
563 raises_exceptions = True | |
564 requires_v8_scope = True | |
565 cpp_arguments = ['scriptArguments.release()'] | |
566 # WebKit uses scriptArguments to reconstruct last argument, so | |
567 # it's not needed and should be just removed. | |
568 arguments = arguments[:-1] | |
569 | |
570 requires_script_execution_context = ext_attrs.get('CallWith') == 'ScriptExec
utionContext' | |
571 if requires_script_execution_context: | |
572 raises_exceptions = True | |
573 cpp_arguments = ['context'] | |
574 | |
575 requires_script_state = ext_attrs.get('CallWith') == 'ScriptState' | |
576 if requires_script_state: | |
577 raises_exceptions = True | |
578 cpp_arguments = ['&state'] | |
579 | |
580 requires_dom_window = 'NamedConstructor' in ext_attrs | |
581 if requires_dom_window: | |
582 raises_exceptions = True | |
583 cpp_arguments = ['document'] | |
584 | |
585 if 'ImplementedBy' in ext_attrs: | |
586 assert needs_receiver | |
587 self._cpp_impl_includes.add('"%s.h"' % ext_attrs['ImplementedBy']) | |
588 cpp_arguments.append('receiver') | |
589 | |
590 if 'Reflect' in ext_attrs: | |
591 cpp_arguments = [self._GenerateWebCoreReflectionAttributeName(node)] | |
592 | |
593 v8EnabledPerContext = ext_attrs.get('synthesizedV8EnabledPerContext', ext_at
trs.get('V8EnabledPerContext')) | |
594 v8EnabledAtRuntime = ext_attrs.get('synthesizedV8EnabledAtRuntime', ext_attr
s.get('V8EnabledAtRuntime')) | |
595 assert(not (v8EnabledPerContext and v8EnabledAtRuntime)) | |
596 | |
597 if v8EnabledPerContext: | |
598 raises_exceptions = True | |
599 self._cpp_impl_includes.add('"ContextFeatures.h"') | |
600 self._cpp_impl_includes.add('"DOMWindow.h"') | |
601 runtime_check = emitter.Format( | |
602 ' if (!ContextFeatures::$(FEATURE)Enabled(DartUtilities::domWin
dowForCurrentIsolate()->document())) {\n' | |
603 ' exception = Dart_NewStringFromCString("Feature $FEATURE i
s not enabled");\n' | |
604 ' goto fail;\n' | |
605 ' }', | |
606 FEATURE=v8EnabledPerContext) | |
607 | |
608 if v8EnabledAtRuntime: | |
609 raises_exceptions = True | |
610 self._cpp_impl_includes.add('"RuntimeEnabledFeatures.h"') | |
611 runtime_check = emitter.Format( | |
612 ' if (!RuntimeEnabledFeatures::$(FEATURE)Enabled()) {\n' | |
613 ' exception = Dart_NewStringFromCString("Feature $FEATURE i
s not enabled");\n' | |
614 ' goto fail;\n' | |
615 ' }', | |
616 FEATURE=self._ToWebKitName(v8EnabledAtRuntime)) | |
617 | |
618 body_emitter = self._cpp_definitions_emitter.Emit( | |
619 '\n' | |
620 'static void $CALLBACK_NAME(Dart_NativeArguments args)\n' | |
621 '{\n' | |
622 ' DartApiScope dartApiScope;\n' | |
623 '$!BODY' | |
624 '}\n', | |
625 CALLBACK_NAME=callback_name) | |
626 | |
627 if raises_exceptions: | |
628 body_emitter = body_emitter.Emit( | |
629 ' Dart_Handle exception = 0;\n' | |
630 '$!BODY' | |
631 '\n' | |
632 'fail:\n' | |
633 ' Dart_ThrowException(exception);\n' | |
634 ' ASSERT_NOT_REACHED();\n') | |
635 | |
636 body_emitter = body_emitter.Emit( | |
637 ' {\n' | |
638 '$!BODY' | |
639 ' return;\n' | |
640 ' }\n') | |
641 | |
642 if requires_v8_scope: | |
643 body_emitter.Emit( | |
644 ' V8Scope v8scope;\n\n') | |
645 | |
646 if runtime_check: | |
647 body_emitter.Emit( | |
648 '$RUNTIME_CHECK\n', | |
649 RUNTIME_CHECK=runtime_check) | |
650 | |
651 if requires_script_execution_context: | |
652 body_emitter.Emit( | |
653 ' ScriptExecutionContext* context = DartUtilities::scriptExecut
ionContext();\n' | |
654 ' if (!context) {\n' | |
655 ' exception = Dart_NewStringFromCString("Failed to retrieve
a context");\n' | |
656 ' goto fail;\n' | |
657 ' }\n\n') | |
658 | |
659 if requires_script_state: | |
660 body_emitter.Emit( | |
661 ' ScriptState* currentState = ScriptState::current();\n' | |
662 ' if (!currentState) {\n' | |
663 ' exception = Dart_NewStringFromCString("Failed to retrieve
a script state");\n' | |
664 ' goto fail;\n' | |
665 ' }\n' | |
666 ' ScriptState& state = *currentState;\n\n') | |
667 | |
668 if requires_dom_window: | |
669 self._cpp_impl_includes.add('"DOMWindow.h"') | |
670 body_emitter.Emit( | |
671 ' DOMWindow* domWindow = DartUtilities::domWindowForCurrentIsol
ate();\n' | |
672 ' if (!domWindow) {\n' | |
673 ' exception = Dart_NewStringFromCString("Failed to fetch do
mWindow");\n' | |
674 ' goto fail;\n' | |
675 ' }\n' | |
676 ' Document* document = domWindow->document();\n') | |
677 | |
678 if needs_receiver: | |
679 body_emitter.Emit( | |
680 ' $WEBCORE_CLASS_NAME* receiver = DartDOMWrapper::receiver< $WE
BCORE_CLASS_NAME >(args);\n', | |
681 WEBCORE_CLASS_NAME=self._interface_type_info.native_type()) | |
682 | |
683 if requires_stack_info: | |
684 self._cpp_impl_includes.add('"ScriptArguments.h"') | |
685 body_emitter.Emit( | |
686 '\n' | |
687 ' ScriptState* currentState = ScriptState::current();\n' | |
688 ' if (!currentState) {\n' | |
689 ' exception = Dart_NewStringFromCString("Failed to retrieve
a script state");\n' | |
690 ' goto fail;\n' | |
691 ' }\n' | |
692 ' ScriptState& state = *currentState;\n' | |
693 '\n' | |
694 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $IN
DEX);\n' | |
695 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::create
ScriptArguments(customArgument, exception));\n' | |
696 ' if (!scriptArguments)\n' | |
697 ' goto fail;\n' | |
698 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::create
ScriptCallStack());\n' | |
699 ' if (!scriptCallStack->size())\n' | |
700 ' return;\n', | |
701 INDEX=len(arguments) + 1) | |
702 | |
703 if requires_script_arguments: | |
704 self._cpp_impl_includes.add('"ScriptArguments.h"') | |
705 body_emitter.Emit( | |
706 '\n' | |
707 ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $IN
DEX);\n' | |
708 ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::create
ScriptArguments(customArgument, exception));\n' | |
709 ' if (!scriptArguments)\n' | |
710 ' goto fail;\n' | |
711 ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::create
ScriptCallStack());\n' | |
712 ' if (!scriptCallStack->size())\n' | |
713 ' return;\n', | |
714 INDEX=len(arguments) + 1) | |
715 | |
716 # Emit arguments. | |
717 start_index = 1 if needs_receiver else 0 | |
718 for i, argument in enumerate(arguments): | |
719 type_info = self._TypeInfo(argument.type.id) | |
720 argument_expression_template, type, cls, function = \ | |
721 type_info.to_native_info(argument, self._interface.id) | |
722 | |
723 if ((IsOptional(argument) and not self._IsArgumentOptionalInWebCore(node,
argument)) or | |
724 (argument.ext_attrs.get('Optional') == 'DefaultIsNullString')): | |
725 function += 'WithNullCheck' | |
726 | |
727 argument_name = DartDomNameOfAttribute(argument) | |
728 if type_info.pass_native_by_ref(): | |
729 invocation_template =\ | |
730 ' $TYPE $ARGUMENT_NAME;\n'\ | |
731 ' $CLS::$FUNCTION(Dart_GetNativeArgument(args, $INDEX), $ARGU
MENT_NAME, exception);\n' | |
732 else: | |
733 invocation_template =\ | |
734 ' $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(Dart_GetNativeArgume
nt(args, $INDEX), exception);\n' | |
735 body_emitter.Emit( | |
736 '\n' + | |
737 invocation_template + | |
738 ' if (exception)\n' | |
739 ' goto fail;\n', | |
740 TYPE=type, | |
741 ARGUMENT_NAME=argument_name, | |
742 CLS=cls, | |
743 FUNCTION=function, | |
744 INDEX=start_index + i) | |
745 self._cpp_impl_includes.add('"%s.h"' % cls) | |
746 cpp_arguments.append(argument_expression_template % argument_name) | |
747 | |
748 body_emitter.Emit('\n') | |
749 | |
750 if 'NeedsUserGestureCheck' in ext_attrs: | |
751 cpp_arguments.append('DartUtilities::processingUserGesture') | |
752 | |
753 invocation_emitter = body_emitter | |
754 if raises_dom_exception: | |
755 cpp_arguments.append('ec') | |
756 invocation_emitter = body_emitter.Emit( | |
757 ' ExceptionCode ec = 0;\n' | |
758 '$!INVOCATION' | |
759 ' if (UNLIKELY(ec)) {\n' | |
760 ' exception = DartDOMWrapper::exceptionCodeToDartException(ec
);\n' | |
761 ' goto fail;\n' | |
762 ' }\n') | |
763 | |
764 function_call = '%s(%s)' % (function_expression, ', '.join(cpp_arguments)) | |
765 if return_type == 'void': | |
766 invocation_emitter.Emit( | |
767 ' $FUNCTION_CALL;\n', | |
768 FUNCTION_CALL=function_call) | |
769 else: | |
770 return_type_info = self._TypeInfo(return_type) | |
771 self._cpp_impl_includes |= set(return_type_info.conversion_includes()) | |
772 | |
773 # Generate to Dart conversion of C++ value. | |
774 to_dart_conversion = return_type_info.to_dart_conversion(function_call, se
lf._interface.id, ext_attrs) | |
775 invocation_emitter.Emit( | |
776 ' Dart_Handle returnValue = $TO_DART_CONVERSION;\n' | |
777 ' if (returnValue)\n' | |
778 ' Dart_SetReturnValue(args, returnValue);\n', | |
779 TO_DART_CONVERSION=to_dart_conversion) | |
780 | |
781 def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration, | |
782 native_suffix, is_custom): | |
783 annotations = FindCommonAnnotations(self._interface.id, idl_name) | |
784 if annotations: | |
785 annotation_str = '\n ' + '\n '.join(annotations) | |
786 else: | |
787 annotation_str = '' | |
788 | |
789 native_binding = '%s_%s_%s' % (self._interface.id, idl_name, native_suffix) | |
790 self._members_emitter.Emit( | |
791 '\n' | |
792 '\n /** @domName $DOMINTERFACE.$DOMNAME */' | |
793 '$ANNOTATIONS' | |
794 '\n $DART_DECLARATION native "$NATIVE_BINDING";\n', | |
795 DOMINTERFACE=self._interface.id, | |
796 DOMNAME=idl_name, | |
797 ANNOTATIONS=annotation_str, | |
798 DART_DECLARATION=dart_declaration, | |
799 NATIVE_BINDING=native_binding) | |
800 | |
801 cpp_callback_name = '%s%s' % (idl_name, native_suffix) | |
802 self._cpp_resolver_emitter.Emit( | |
803 ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n' | |
804 ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n', | |
805 ARGC=argument_count, | |
806 NATIVE_BINDING=native_binding, | |
807 INTERFACE_NAME=self._interface.id, | |
808 CPP_CALLBACK_NAME=cpp_callback_name) | |
809 | |
810 if is_custom: | |
811 self._cpp_declarations_emitter.Emit( | |
812 '\n' | |
813 'void $CPP_CALLBACK_NAME(Dart_NativeArguments);\n', | |
814 CPP_CALLBACK_NAME=cpp_callback_name) | |
815 | |
816 return cpp_callback_name | |
817 | |
818 def _GenerateWebCoreReflectionAttributeName(self, attr): | |
819 namespace = 'HTMLNames' | |
820 svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | |
821 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | |
822 'onmouseup', 'onresize', 'onscroll', 'onunload'] | |
823 if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | |
824 namespace = 'SVGNames' | |
825 self._cpp_impl_includes.add('"%s.h"' % namespace) | |
826 | |
827 attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | |
828 return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | |
829 | |
830 def _GenerateWebCoreFunctionExpression(self, function_name, idl_node): | |
831 if 'ImplementedBy' in idl_node.ext_attrs: | |
832 return '%s::%s' % (idl_node.ext_attrs['ImplementedBy'], function_name) | |
833 if idl_node.is_static: | |
834 return '%s::%s' % (self._interface_type_info.idl_type(), function_name) | |
835 return '%s%s' % (self._interface_type_info.receiver(), function_name) | |
836 | |
837 def _IsArgumentOptionalInWebCore(self, operation, argument): | |
838 if not IsOptional(argument): | |
839 return False | |
840 if 'Callback' in argument.ext_attrs: | |
841 return False | |
842 if operation.id in ['addEventListener', 'removeEventListener'] and argument.
id == 'useCapture': | |
843 return False | |
844 # Another option would be to adjust in IDLs, but let's keep it here for now | |
845 # as it's a single instance. | |
846 if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setPrope
rty' and argument.id == 'priority': | |
847 return False | |
848 if argument.type.id == 'Dictionary': | |
849 return False | |
850 return True | |
851 | |
852 def _GenerateCPPIncludes(self, includes): | |
853 return ''.join(['#include %s\n' % include for include in sorted(includes)]) | |
854 | |
855 def _ToWebKitName(self, name): | |
856 name = name[0].lower() + name[1:] | |
857 name = re.sub(r'^(hTML|uRL|jS|xML|xSLT)', lambda s: s.group(1).lower(), | |
858 name) | |
859 return re.sub(r'^(create|exclusive)', | |
860 lambda s: 'is' + s.group(1).capitalize(), | |
861 name) | |
862 | |
863 def _TypeInfo(self, type_name): | |
864 return self._type_registry.TypeInfo(type_name) | |
865 | |
866 def _DartType(self, type_name): | |
867 return self._type_registry.DartType(type_name) | |
868 | |
869 | |
870 class CPPLibraryEmitter(): | |
871 def __init__(self, emitters, cpp_sources_dir): | |
872 self._emitters = emitters | |
873 self._cpp_sources_dir = cpp_sources_dir | |
874 self._library_headers = {} | |
875 self._sources_list = [] | |
876 | |
877 def CreateHeaderEmitter(self, interface_name, library_name, is_callback=False)
: | |
878 path = os.path.join(self._cpp_sources_dir, 'Dart%s.h' % interface_name) | |
879 if not is_callback: | |
880 if not library_name in self._library_headers: | |
881 self._library_headers[library_name] = [] | |
882 self._library_headers[library_name].append(path) | |
883 return self._emitters.FileEmitter(path) | |
884 | |
885 def CreateSourceEmitter(self, interface_name): | |
886 path = os.path.join(self._cpp_sources_dir, 'Dart%s.cpp' % interface_name) | |
887 self._sources_list.append(path) | |
888 return self._emitters.FileEmitter(path) | |
889 | |
890 def EmitDerivedSources(self, template, output_dir): | |
891 partitions = 20 # FIXME: this should be configurable. | |
892 sources_count = len(self._sources_list) | |
893 for i in range(0, partitions): | |
894 file_path = os.path.join(output_dir, 'DartDerivedSources%02i.cpp' % (i + 1
)) | |
895 includes_emitter = self._emitters.FileEmitter(file_path).Emit(template) | |
896 for source_file in self._sources_list[i::partitions]: | |
897 path = os.path.relpath(source_file, output_dir) | |
898 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
899 | |
900 def EmitResolver(self, template, output_dir): | |
901 for library_name in self._library_headers.keys(): | |
902 file_path = os.path.join(output_dir, '%s_DartResolver.cpp' % library_name) | |
903 includes_emitter, body_emitter = self._emitters.FileEmitter(file_path).Emi
t( | |
904 template, | |
905 LIBRARY_NAME=library_name) | |
906 | |
907 headers = self._library_headers[library_name] | |
908 for header_file in headers: | |
909 path = os.path.relpath(header_file, output_dir) | |
910 includes_emitter.Emit('#include "$PATH"\n', PATH=path) | |
911 body_emitter.Emit( | |
912 ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argu
mentCount))\n' | |
913 ' return func;\n', | |
914 CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | |
OLD | NEW |