Chromium Code Reviews| Index: client/dom/scripts/systemnative.py | 
| diff --git a/client/dom/scripts/systemnative.py b/client/dom/scripts/systemnative.py | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..03aa72dfa02b65ecab1e96b59d01a708361f7d98 | 
| --- /dev/null | 
| +++ b/client/dom/scripts/systemnative.py | 
| @@ -0,0 +1,740 @@ | 
| +#!/usr/bin/python | 
| +# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 
| +# for details. All rights reserved. Use of this source code is governed by a | 
| +# BSD-style license that can be found in the LICENSE file. | 
| + | 
| +"""This module provides shared functionality for the systems to generate | 
| +native binding from the IDL database.""" | 
| + | 
| +import emitter | 
| +import os | 
| +import systemwrapping | 
| +from generator import * | 
| +from systembase import * | 
| + | 
| +class NativeImplementationSystem(System): | 
| + | 
| + def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): | 
| + super(NativeImplementationSystem, self).__init__( | 
| + templates, database, emitters, output_dir) | 
| + | 
| + self._auxiliary_dir = auxiliary_dir | 
| + self._dom_public_files = [] | 
| + self._dom_impl_files = [] | 
| + self._cpp_header_files = [] | 
| + self._cpp_impl_files = [] | 
| + | 
| + def InterfaceGenerator(self, | 
| + interface, | 
| + common_prefix, | 
| + super_interface_name, | 
| + source_filter): | 
| + interface_name = interface.id | 
| + | 
| + dart_interface_path = self._FilePathForDartInterface(interface_name) | 
| + self._dom_public_files.append(dart_interface_path) | 
| + | 
| + pure_interfaces = set([ | 
| 
 
sra1
2012/02/21 19:22:13
This could be moved to generator.py
 
 | 
| + 'ElementTimeControl', | 
| + 'ElementTraversal', | 
| + 'MediaQueryListListener', | 
| + 'NodeSelector', | 
| + 'SVGExternalResourcesRequired', | 
| + 'SVGFilterPrimitiveStandardAttributes', | 
| + 'SVGFitToViewBox', | 
| + 'SVGLangSpace', | 
| + 'SVGLocatable', | 
| + 'SVGStylable', | 
| + 'SVGTests', | 
| + 'SVGTransformable', | 
| + 'SVGURIReference', | 
| + 'SVGViewSpec', | 
| + 'SVGZoomAndPan']) | 
| + if interface_name in pure_interfaces: | 
| + return None | 
| + | 
| + dart_impl_path = self._FilePathForDartImplementation(interface_name) | 
| + self._dom_impl_files.append(dart_impl_path) | 
| + | 
| + cpp_header_path = self._FilePathForCppHeader(interface_name) | 
| + self._cpp_header_files.append(cpp_header_path) | 
| + | 
| + cpp_impl_path = self._FilePathForCppImplementation(interface_name) | 
| + self._cpp_impl_files.append(cpp_impl_path) | 
| + | 
| + return NativeImplementationGenerator(interface, super_interface_name, | 
| + self._emitters.FileEmitter(dart_impl_path), | 
| + self._emitters.FileEmitter(cpp_header_path), | 
| + self._emitters.FileEmitter(cpp_impl_path), | 
| + self._BaseDefines(interface), | 
| + self._templates) | 
| + | 
| + def ProcessCallback(self, interface, info): | 
| + self._interface = interface | 
| + | 
| + dart_interface_path = self._FilePathForDartInterface(self._interface.id) | 
| + self._dom_public_files.append(dart_interface_path) | 
| + | 
| + cpp_header_handlers_emitter = emitter.Emitter() | 
| + cpp_impl_handlers_emitter = emitter.Emitter() | 
| + class_name = 'Dart%s' % self._interface.id | 
| + for operation in interface.operations: | 
| + if operation.type.id == 'void': | 
| + return_type = 'void' | 
| + return_prefix = '' | 
| + else: | 
| + return_type = 'bool' | 
| + return_prefix = 'return ' | 
| + | 
| + parameters = [] | 
| + arguments = [] | 
| + for argument in operation.arguments: | 
| + argument_type_info = GetIDLTypeInfo(argument.type) | 
| + parameters.append('%s %s' % (argument_type_info.parameter_type(), | 
| + argument.id)) | 
| + arguments.append(argument.id) | 
| + | 
| + cpp_header_handlers_emitter.Emit( | 
| + '\n' | 
| + ' virtual $TYPE handleEvent($PARAMETERS);\n', | 
| + TYPE=return_type, PARAMETERS=', '.join(parameters)) | 
| + | 
| + cpp_impl_handlers_emitter.Emit( | 
| + '\n' | 
| + '$TYPE $CLASS_NAME::handleEvent($PARAMETERS)\n' | 
| + '{\n' | 
| + ' $(RETURN_PREFIX)m_callback.handleEvent($ARGUMENTS);\n' | 
| + '}\n', | 
| + TYPE=return_type, | 
| + CLASS_NAME=class_name, | 
| + PARAMETERS=', '.join(parameters), | 
| + RETURN_PREFIX=return_prefix, | 
| + ARGUMENTS=', '.join(arguments)) | 
| + | 
| + cpp_header_path = self._FilePathForCppHeader(self._interface.id) | 
| + cpp_header_emitter = self._emitters.FileEmitter(cpp_header_path) | 
| + cpp_header_emitter.Emit( | 
| + self._templates.Load('cpp_callback_header.template'), | 
| + INTERFACE=self._interface.id, | 
| + HANDLERS=cpp_header_handlers_emitter.Fragments()) | 
| + | 
| + cpp_impl_path = self._FilePathForCppImplementation(self._interface.id) | 
| + self._cpp_impl_files.append(cpp_impl_path) | 
| + cpp_impl_emitter = self._emitters.FileEmitter(cpp_impl_path) | 
| + cpp_impl_emitter.Emit( | 
| + self._templates.Load('cpp_callback_implementation.template'), | 
| + INTERFACE=self._interface.id, | 
| + HANDLERS=cpp_impl_handlers_emitter.Fragments()) | 
| + | 
| + def GenerateLibraries(self, lib_dir): | 
| + auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) | 
| + | 
| + # Generate dom_public.dart. | 
| + self._GenerateLibFile( | 
| + 'dom_public.darttemplate', | 
| + os.path.join(self._output_dir, 'dom_public.dart'), | 
| + self._dom_public_files, | 
| + AUXILIARY_DIR=auxiliary_dir); | 
| + | 
| + # Generate dom_impl.dart. | 
| + self._GenerateLibFile( | 
| + 'dom_impl.darttemplate', | 
| + os.path.join(self._output_dir, 'dom_impl.dart'), | 
| + self._dom_impl_files, | 
| + AUXILIARY_DIR=auxiliary_dir); | 
| + | 
| + # Generate DartDerivedSourcesAll.cpp. | 
| + cpp_all_in_one_path = os.path.join(self._output_dir, | 
| + 'DartDerivedSourcesAll.cpp') | 
| + | 
| + includes_emitter = emitter.Emitter() | 
| + for f in self._cpp_impl_files: | 
| + path = os.path.relpath(f, os.path.dirname(cpp_all_in_one_path)) | 
| + includes_emitter.Emit('#include "$PATH"\n', PATH=path) | 
| + | 
| + cpp_all_in_one_emitter = self._emitters.FileEmitter(cpp_all_in_one_path) | 
| + cpp_all_in_one_emitter.Emit( | 
| + self._templates.Load('cpp_all_in_one.template'), | 
| + INCLUDES=includes_emitter.Fragments()) | 
| + | 
| + # Generate DartResolver.cpp. | 
| + cpp_resolver_path = os.path.join(self._output_dir, 'DartResolver.cpp') | 
| + | 
| + includes_emitter = emitter.Emitter() | 
| + resolver_body_emitter = emitter.Emitter() | 
| + for f in self._cpp_header_files: | 
| + path = os.path.relpath(f, os.path.dirname(cpp_resolver_path)) | 
| + includes_emitter.Emit('#include "$PATH"\n', PATH=path) | 
| + resolver_body_emitter.Emit( | 
| + ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argumentCount))\n' | 
| + ' return func;\n', | 
| + CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | 
| + | 
| + cpp_resolver_emitter = self._emitters.FileEmitter(cpp_resolver_path) | 
| + cpp_resolver_emitter.Emit( | 
| + self._templates.Load('cpp_resolver.template'), | 
| + INCLUDES=includes_emitter.Fragments(), | 
| + RESOLVER_BODY=resolver_body_emitter.Fragments()) | 
| + | 
| + # Generate DartDerivedSourcesAll.cpp | 
| + cpp_all_in_one_path = os.path.join(self._output_dir, | 
| + 'DartDerivedSourcesAll.cpp') | 
| + | 
| + includes_emitter = emitter.Emitter() | 
| + for file in self._cpp_impl_files: | 
| + path = os.path.relpath(file, os.path.dirname(cpp_all_in_one_path)) | 
| + includes_emitter.Emit('#include "$PATH"\n', PATH=path) | 
| + | 
| + cpp_all_in_one_emitter = self._emitters.FileEmitter(cpp_all_in_one_path) | 
| + cpp_all_in_one_emitter.Emit( | 
| + self._templates.Load('cpp_all_in_one.template'), | 
| + INCLUDES=includes_emitter.Fragments()) | 
| + | 
| + # Generate DartResolver.cpp | 
| + cpp_resolver_path = os.path.join(self._output_dir, 'DartResolver.cpp') | 
| + | 
| + includes_emitter = emitter.Emitter() | 
| + resolver_body_emitter = emitter.Emitter() | 
| + for file in self._cpp_header_files: | 
| + path = os.path.relpath(file, os.path.dirname(cpp_resolver_path)) | 
| + includes_emitter.Emit('#include "$PATH"\n', PATH=path) | 
| + resolver_body_emitter.Emit( | 
| + ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argumentCount))\n' | 
| + ' return func;\n', | 
| + CLASS_NAME=os.path.splitext(os.path.basename(path))[0]) | 
| + | 
| + cpp_resolver_emitter = self._emitters.FileEmitter(cpp_resolver_path) | 
| + cpp_resolver_emitter.Emit( | 
| + self._templates.Load('cpp_resolver.template'), | 
| + INCLUDES=includes_emitter.Fragments(), | 
| + RESOLVER_BODY=resolver_body_emitter.Fragments()) | 
| + | 
| + def Finish(self): | 
| + pass | 
| + | 
| + def _FilePathForDartInterface(self, interface_name): | 
| + return os.path.join(self._output_dir, 'src', 'interface', | 
| + '%s.dart' % interface_name) | 
| + | 
| + def _FilePathForDartImplementation(self, interface_name): | 
| + return os.path.join(self._output_dir, 'dart', | 
| + '%sImplementation.dart' % interface_name) | 
| + | 
| + def _FilePathForCppHeader(self, interface_name): | 
| + return os.path.join(self._output_dir, 'cpp', 'Dart%s.h' % interface_name) | 
| + | 
| + def _FilePathForCppImplementation(self, interface_name): | 
| + return os.path.join(self._output_dir, 'cpp', 'Dart%s.cpp' % interface_name) | 
| + | 
| + | 
| +class NativeImplementationGenerator(systemwrapping.WrappingInterfaceGenerator): | 
| + """Generates Dart implementation for one DOM IDL interface.""" | 
| + | 
| + def __init__(self, interface, super_interface, | 
| + dart_impl_emitter, cpp_header_emitter, cpp_impl_emitter, | 
| + base_members, templates): | 
| + """Generates Dart and C++ code for the given interface. | 
| + | 
| + Args: | 
| + | 
| + interface: an IDLInterface instance. It is assumed that all types have | 
| + been converted to Dart types (e.g. int, String), unless they are in | 
| + the same package as the interface. | 
| + super_interface: A string or None, the name of the common interface that | 
| + this interface implements, if any. | 
| + dart_impl_emitter: an Emitter for the file containing the Dart | 
| + implementation class. | 
| + cpp_header_emitter: an Emitter for the file containing the C++ header. | 
| + cpp_impl_emitter: an Emitter for the file containing the C++ | 
| + implementation. | 
| + base_members: a set of names of members defined in a base class. This is | 
| + used to avoid static member 'overriding' in the generated Dart code. | 
| + """ | 
| + self._interface = interface | 
| + self._super_interface = super_interface | 
| + self._dart_impl_emitter = dart_impl_emitter | 
| + self._cpp_header_emitter = cpp_header_emitter | 
| + self._cpp_impl_emitter = cpp_impl_emitter | 
| + self._base_members = base_members | 
| + self._templates = templates | 
| + self._current_secondary_parent = None | 
| + | 
| + def StartInterface(self): | 
| + self._class_name = self._ImplClassName(self._interface.id) | 
| + self._interface_type_info = GetIDLTypeInfoByName(self._interface.id) | 
| + self._members_emitter = emitter.Emitter() | 
| + self._cpp_declarations_emitter = emitter.Emitter() | 
| + self._cpp_impl_includes = {} | 
| + self._cpp_definitions_emitter = emitter.Emitter() | 
| + self._cpp_resolver_emitter = emitter.Emitter() | 
| + | 
| + # Generate constructor. | 
| + # FIXME: add proper support for non-custom constructors. | 
| + if ('CustomConstructor' in self._interface.ext_attrs or | 
| + 'V8CustomConstructor' in self._interface.ext_attrs or | 
| + self._interface.id in ['FileReader', 'WebKitCSSMatrix', 'XSLTProcessor']): | 
| + self._cpp_resolver_emitter.Emit( | 
| + ' if (name == "$(INTERFACE_NAME)_constructor_Callback")\n' | 
| + ' return Dart$(INTERFACE_NAME)Internal::constructorCallback;\n', | 
| + INTERFACE_NAME=self._interface.id) | 
| + self._cpp_declarations_emitter.Emit( | 
| + '\n' | 
| + 'void constructorCallback(Dart_NativeArguments);\n') | 
| + | 
| + def _ImplClassName(self, interface_name): | 
| + return interface_name + 'Implementation' | 
| + | 
| + def FinishInterface(self): | 
| + base = self._BaseClassName(self._interface) | 
| + self._dart_impl_emitter.Emit( | 
| + self._templates.Load('dart_implementation.darttemplate'), | 
| + CLASS=self._class_name, BASE=base, INTERFACE=self._interface.id, | 
| + MEMBERS=self._members_emitter.Fragments()) | 
| + | 
| + self._GenerateCppHeader() | 
| + | 
| + self._cpp_impl_emitter.Emit( | 
| + self._templates.Load('cpp_implementation.template'), | 
| + INTERFACE=self._interface.id, | 
| + INCLUDES=''.join(['#include "%s.h"\n' % | 
| + k for k in self._cpp_impl_includes.keys()]), | 
| + CALLBACKS=self._cpp_definitions_emitter.Fragments(), | 
| + RESOLVER=self._cpp_resolver_emitter.Fragments()) | 
| + | 
| + def _GenerateCppHeader(self): | 
| + webcore_include = self._interface_type_info.webcore_include() | 
| + if webcore_include: | 
| + webcore_include = '#include "%s.h"\n' % webcore_include | 
| + else: | 
| + webcore_include = '' | 
| + | 
| + if ('CustomToJS' in self._interface.ext_attrs or | 
| + 'CustomToJSObject' in self._interface.ext_attrs or | 
| + 'PureInterface' in self._interface.ext_attrs or | 
| + 'CPPPureInterface' in self._interface.ext_attrs or | 
| + self._interface_type_info.custom_to_dart()): | 
| + to_dart_value_template = ( | 
| + 'Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value);\n') | 
| + else: | 
| + to_dart_value_template = ( | 
| + 'inline Dart_Handle toDartValue($(WEBCORE_CLASS_NAME)* value)\n' | 
| + '{\n' | 
| + ' return DartDOMWrapper::toDart<Dart$(INTERFACE)>(value);\n' | 
| + '}\n') | 
| + to_dart_value_emitter = emitter.Emitter() | 
| + to_dart_value_emitter.Emit( | 
| + to_dart_value_template, | 
| + INTERFACE=self._interface.id, | 
| + WEBCORE_CLASS_NAME=self._interface_type_info.native_type()) | 
| + | 
| + self._cpp_header_emitter.Emit( | 
| + self._templates.Load('cpp_header.template'), | 
| + INTERFACE=self._interface.id, | 
| + WEBCORE_INCLUDE=webcore_include, | 
| + ADDITIONAL_INCLUDES='', | 
| + WEBCORE_CLASS_NAME=self._interface_type_info.native_type(), | 
| + TO_DART_VALUE=to_dart_value_emitter.Fragments(), | 
| + DECLARATIONS=self._cpp_declarations_emitter.Fragments()) | 
| + | 
| + def AddAttribute(self, getter, setter): | 
| + # FIXME: Dartium does not support attribute event listeners. However, JS | 
| + # implementation falls back to them when addEventListener is not available. | 
| + # Make sure addEventListener is available in all EventTargets and remove | 
| + # this check. | 
| + if (getter or setter).type.id == 'EventListener': | 
| + return | 
| + | 
| + # FIXME: support 'ImplementedBy'. | 
| + if 'ImplementedBy' in (getter or setter).ext_attrs: | 
| + return | 
| + | 
| + # FIXME: these should go away. | 
| + classes_with_unsupported_custom_getters = [ | 
| + 'Clipboard', 'Console', 'Coordinates', 'DeviceMotionEvent', | 
| + 'DeviceOrientationEvent', 'FileReader', 'JavaScriptCallFrame', | 
| + 'HTMLInputElement', 'HTMLOptionsCollection', 'HTMLOutputElement', | 
| + 'ScriptProfileNode', 'WebKitAnimation'] | 
| + if (self._interface.id in classes_with_unsupported_custom_getters and | 
| + getter and set(['Custom', 'CustomGetter']) & set(getter.ext_attrs)): | 
| + return | 
| + | 
| + if getter: | 
| + self._AddGetter(getter) | 
| + if setter: | 
| + self._AddSetter(setter) | 
| + | 
| + def _AddGetter(self, attr): | 
| + dart_declaration = '%s get %s()' % (attr.type.id, attr.id) | 
| + is_custom = 'Custom' in attr.ext_attrs or 'CustomGetter' in attr.ext_attrs | 
| + cpp_callback_name = self._GenerateNativeBinding(attr.id, 1, | 
| + dart_declaration, 'Getter', is_custom) | 
| + if is_custom: | 
| + return | 
| + | 
| + arguments = [] | 
| + if 'Reflect' in attr.ext_attrs: | 
| + webcore_function_name = GetIDLTypeInfo(attr.type).webcore_getter_name() | 
| + if 'URL' in attr.ext_attrs: | 
| + if 'NonEmpty' in attr.ext_attrs: | 
| + webcore_function_name = 'getNonEmptyURLAttribute' | 
| + else: | 
| + webcore_function_name = 'getURLAttribute' | 
| + arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | 
| + else: | 
| + if attr.id == 'operator': | 
| + webcore_function_name = '_operator' | 
| + elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString': | 
| + webcore_function_name = 'svgTarget' | 
| + else: | 
| + webcore_function_name = re.sub(r'^(HTML|URL|JS|XML|XSLT|\w)', | 
| + lambda s: s.group(1).lower(), | 
| + attr.id) | 
| + webcore_function_name = re.sub(r'^(create|exclusive)', | 
| + lambda s: 'is' + s.group(1).capitalize(), | 
| + webcore_function_name) | 
| + if attr.type.id.startswith('SVGAnimated'): | 
| + webcore_function_name += 'Animated' | 
| + | 
| + self._GenerateNativeCallback(cpp_callback_name, attr, '', | 
| + webcore_function_name, arguments, idl_return_type=attr.type, | 
| + raises_dart_exceptions=attr.get_raises, | 
| + raises_dom_exceptions=attr.get_raises) | 
| + | 
| + def _AddSetter(self, attr): | 
| + dart_declaration = 'void set %s(%s)' % (attr.id, attr.type.id) | 
| + is_custom = set(['Custom', 'CustomSetter', 'V8CustomSetter']) & set(attr.ext_attrs) | 
| + cpp_callback_name = self._GenerateNativeBinding(attr.id, 2, | 
| + dart_declaration, 'Setter', is_custom) | 
| + if is_custom: | 
| + return | 
| + | 
| + arguments = [] | 
| + if 'Reflect' in attr.ext_attrs: | 
| + webcore_function_name = GetIDLTypeInfo(attr.type).webcore_setter_name() | 
| + arguments.append(self._GenerateWebCoreReflectionAttributeName(attr)) | 
| + else: | 
| + webcore_function_name = re.sub(r'^(xml(?=[A-Z])|\w)', | 
| + lambda s: s.group(1).upper(), | 
| + attr.id) | 
| + webcore_function_name = 'set%s' % webcore_function_name | 
| + if attr.type.id.startswith('SVGAnimated'): | 
| + webcore_function_name += 'Animated' | 
| + | 
| + arguments.append(attr.id) | 
| + parameter_definitions_emitter = emitter.Emitter() | 
| + self._GenerateParameterAdapter(parameter_definitions_emitter, attr, 0) | 
| + parameter_definitions = parameter_definitions_emitter.Fragments() | 
| + self._GenerateNativeCallback(cpp_callback_name, attr, parameter_definitions, | 
| + webcore_function_name, arguments, idl_return_type=None, | 
| + raises_dart_exceptions=True, | 
| + raises_dom_exceptions=attr.set_raises) | 
| + | 
| + def _HasNativeIndexGetter(self, interface): | 
| + return ('CustomIndexedGetter' in interface.ext_attrs or | 
| + 'NumericIndexedGetter' in interface.ext_attrs) | 
| + | 
| + def _EmitNativeIndexGetter(self, interface, element_type): | 
| + dart_declaration = '%s operator[](int index)' % element_type | 
| + self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration, | 
| + 'Callback', True) | 
| + | 
| + def _EmitNativeIndexSetter(self, interface, element_type): | 
| + dart_declaration = 'void operator[]=(int index, %s value)' % element_type | 
| + self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration, | 
| + 'Callback', True) | 
| + | 
| + def AddOperation(self, info): | 
| + """ | 
| + Arguments: | 
| + info: An OperationInfo object. | 
| + """ | 
| + | 
| + if 'Custom' in info.overloads[0].ext_attrs: | 
| + parameters = info.ParametersImplementationDeclaration() | 
| + dart_declaration = '%s %s(%s)' % (info.type_name, info.name, parameters) | 
| + argument_count = 1 + len(info.arg_infos) | 
| + self._GenerateNativeBinding(info.name, argument_count, dart_declaration, | 
| + 'Callback', True) | 
| + return | 
| + | 
| + body = self._members_emitter.Emit( | 
| + '\n' | 
| + ' $TYPE $NAME($PARAMETERS) {\n' | 
| + '$!BODY' | 
| + ' }\n', | 
| + TYPE=info.type_name, | 
| + NAME=info.name, | 
| + PARAMETERS=info.ParametersImplementationDeclaration()) | 
| + | 
| + # Process in order of ascending number of arguments to ensure missing | 
| + # optional arguments are processed early. | 
| + overloads = sorted(info.overloads, | 
| + key=lambda overload: len(overload.arguments)) | 
| + self._native_version = 0 | 
| + fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | 
| + if fallthrough: | 
| + body.Emit(' throw "Incorrect number or type of arguments";\n'); | 
| + | 
| + def GenerateSingleOperation(self, dispatch_emitter, info, indent, operation): | 
| + """Generates a call to a single operation. | 
| + | 
| + Arguments: | 
| + dispatch_emitter: an dispatch_emitter for the body of a block of code. | 
| + info: the compound information about the operation and its overloads. | 
| + indent: an indentation string for generated code. | 
| + operation: the IDLOperation to call. | 
| + """ | 
| + | 
| + # FIXME: support ImplementedBy callbacks. | 
| + if 'ImplementedBy' in operation.ext_attrs: | 
| + return | 
| + | 
| + for op in self._interface.operations: | 
| + if op.id != operation.id or len(op.arguments) <= len(operation.arguments): | 
| + continue | 
| + next_argument = op.arguments[len(operation.arguments)] | 
| + if next_argument.is_optional and 'Callback' in next_argument.ext_attrs: | 
| + # FIXME: '[Optional, Callback]' arguments could be non-optional in | 
| + # webcore. We need to fix overloads handling to generate native | 
| + # callbacks properly. | 
| + return | 
| + | 
| + self._native_version += 1 | 
| + native_name = info.name | 
| + if self._native_version > 1: | 
| + native_name = '%s_%s' % (native_name, self._native_version) | 
| + argument_list = ', '.join([info.arg_infos[i][0] | 
| + for (i, arg) in enumerate(operation.arguments)]) | 
| + | 
| + # Generate dispatcher. | 
| + if info.type_name != 'void': | 
| + dispatch_emitter.Emit('$(INDENT)return _$NATIVENAME($ARGS);\n', | 
| + INDENT=indent, | 
| + NATIVENAME=native_name, | 
| + ARGS=argument_list) | 
| + else: | 
| + dispatch_emitter.Emit('$(INDENT)_$NATIVENAME($ARGS);\n' | 
| + '$(INDENT)return;\n', | 
| + INDENT=indent, | 
| + NATIVENAME=native_name, | 
| + ARGS=argument_list) | 
| + # Generate binding. | 
| + dart_declaration = '%s _%s(%s)' % (info.type_name, native_name, | 
| + argument_list) | 
| + is_custom = 'Custom' in operation.ext_attrs | 
| + cpp_callback_name = self._GenerateNativeBinding( | 
| + native_name, 1 + len(operation.arguments), dart_declaration, 'Callback', | 
| + is_custom) | 
| + if is_custom: | 
| + return | 
| + | 
| + # Generate callback. | 
| + webcore_function_name = operation.id | 
| + if 'ImplementedAs' in operation.ext_attrs: | 
| + webcore_function_name = operation.ext_attrs['ImplementedAs'] | 
| + | 
| + parameter_definitions_emitter = emitter.Emitter() | 
| + raises_dart_exceptions = len(operation.arguments) > 0 or operation.raises | 
| + arguments = [] | 
| + | 
| + # Process 'CallWith' argument. | 
| + if 'CallWith' in operation.ext_attrs: | 
| + call_with = operation.ext_attrs['CallWith'] | 
| + if call_with == 'ScriptExecutionContext': | 
| + parameter_definitions_emitter.Emit( | 
| + ' ScriptExecutionContext* context = DartUtilities::scriptExecutionContext();\n' | 
| + ' if (!context)\n' | 
| + ' return;\n') | 
| + arguments.append('context') | 
| + elif call_with == 'ScriptArguments|CallStack': | 
| + raises_dart_exceptions = True | 
| + self._cpp_impl_includes['ScriptArguments'] = 1 | 
| + self._cpp_impl_includes['ScriptCallStack'] = 1 | 
| + self._cpp_impl_includes['V8Proxy'] = 1 | 
| + self._cpp_impl_includes['v8'] = 1 | 
| + parameter_definitions_emitter.Emit( | 
| + ' v8::HandleScope handleScope;\n' | 
| + ' v8::Context::Scope scope(V8Proxy::mainWorldContext(DartUtilities::domWindowForCurrentIsolate()->frame()));\n' | 
| + ' Dart_Handle customArgument = Dart_GetNativeArgument(args, $INDEX);\n' | 
| + ' RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));\n' | 
| + ' if (!scriptArguments)\n' | 
| + ' goto fail;\n' | 
| + ' RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::createScriptCallStack());\n' | 
| + ' if (!scriptCallStack->size())\n' | 
| + ' return;\n', | 
| + INDEX=len(operation.arguments)) | 
| + arguments.extend(['scriptArguments', 'scriptCallStack']) | 
| + | 
| + # Process Dart arguments. | 
| + for (i, argument) in enumerate(operation.arguments): | 
| + if i == len(operation.arguments) - 1 and self._interface.id == 'Console' and argument.id == 'arg': | 
| + # FIXME: we are skipping last argument here because it was added in | 
| + # supplemental dart.idl. Cleanup dart.idl and remove this check. | 
| + break | 
| + self._GenerateParameterAdapter(parameter_definitions_emitter, argument, i) | 
| + arguments.append(argument.id) | 
| + | 
| + if operation.id in ['addEventListener', 'removeEventListener']: | 
| + # addEventListener's and removeEventListener's last argument is marked | 
| + # as optional in idl, but is not optional in webcore implementation. | 
| + if len(operation.arguments) == 2: | 
| + arguments.append('false') | 
| + | 
| + if self._interface.id == 'CSSStyleDeclaration' and operation.id == 'setProperty': | 
| + # CSSStyleDeclaration.setProperty priority parameter is optional in Dart | 
| + # idl, but is not optional in webcore implementation. | 
| + if len(operation.arguments) == 2: | 
| + arguments.append('String()') | 
| + | 
| + if 'NeedsUserGestureCheck' in operation.ext_attrs: | 
| + arguments.extend('DartUtilities::processingUserGesture') | 
| + | 
| + parameter_definitions = parameter_definitions_emitter.Fragments() | 
| + self._GenerateNativeCallback(cpp_callback_name, operation, | 
| + parameter_definitions, webcore_function_name, arguments, | 
| + idl_return_type=operation.type, | 
| + raises_dart_exceptions=raises_dart_exceptions, | 
| + raises_dom_exceptions=operation.raises) | 
| + | 
| + def _GenerateNativeCallback(self, callback_name, idl_node, | 
| + parameter_definitions, function_name, arguments, idl_return_type, | 
| + raises_dart_exceptions, raises_dom_exceptions): | 
| + receiver = self._interface_type_info.receiver() | 
| + if raises_dom_exceptions: | 
| + arguments.append('ec') | 
| + callback = '%s%s(%s)' % (receiver, function_name, ', '.join(arguments)) | 
| + | 
| + nested_templates = [] | 
| + if idl_return_type and idl_return_type.id != 'void': | 
| + return_type_info = GetIDLTypeInfo(idl_return_type) | 
| + conversion_cast = return_type_info.conversion_cast('$BODY') | 
| + if isinstance(return_type_info, SVGTearOffIDLTypeInfo): | 
| + svg_primitive_types = ['SVGAngle', 'SVGLength', 'SVGMatrix', | 
| + 'SVGNumber', 'SVGPoint', 'SVGRect', 'SVGTransform'] | 
| + conversion_cast = '%s::create($BODY)' | 
| + if self._interface.id.startswith('SVGAnimated'): | 
| + conversion_cast = 'static_cast<%s*>($BODY)' | 
| + elif return_type_info.idl_type() == 'SVGStringList': | 
| + conversion_cast = '%s::create(receiver, $BODY)' | 
| + elif self._interface.id.endswith('List'): | 
| + conversion_cast = 'static_cast<%s*>($BODY.get())' | 
| + elif return_type_info.idl_type() in svg_primitive_types: | 
| + conversion_cast = '%s::create($BODY)' | 
| + else: | 
| + conversion_cast = 'static_cast<%s*>($BODY)' | 
| + conversion_cast = conversion_cast % return_type_info.native_type() | 
| + nested_templates.append(conversion_cast) | 
| + | 
| + if return_type_info.conversion_include(): | 
| + self._cpp_impl_includes[return_type_info.conversion_include()] = 1 | 
| + if (return_type_info.idl_type() in ['DOMString', 'AtomicString'] and | 
| + 'TreatReturnedNullStringAs' in idl_node.ext_attrs): | 
| + nested_templates.append('$BODY, ConvertDefaultToNull') | 
| + nested_templates.append( | 
| + ' Dart_Handle returnValue = toDartValue($BODY);\n' | 
| + ' if (returnValue)\n' | 
| + ' Dart_SetReturnValue(args, returnValue);\n') | 
| + else: | 
| + nested_templates.append(' $BODY;\n') | 
| + | 
| + if raises_dom_exceptions: | 
| + nested_templates.append( | 
| + ' ExceptionCode ec = 0;\n' | 
| + '$BODY' | 
| + ' if (UNLIKELY(ec)) {\n' | 
| + ' exception = DartDOMWrapper::exceptionCodeToDartException(ec);\n' | 
| + ' goto fail;\n' | 
| + ' }\n') | 
| + | 
| + nested_templates.append( | 
| + ' {\n' | 
| + ' $WEBCORE_CLASS_NAME* receiver = DartDOMWrapper::receiver< $WEBCORE_CLASS_NAME >(args);\n' | 
| + '$PARAMETER_DEFINITIONS' | 
| + '\n' | 
| + '$BODY' | 
| + ' return;\n' | 
| + ' }\n') | 
| + | 
| + if raises_dart_exceptions: | 
| + nested_templates.append( | 
| + ' Dart_Handle exception;\n' | 
| + '$BODY' | 
| + '\n' | 
| + 'fail:\n' | 
| + ' Dart_ThrowException(exception);\n' | 
| + ' ASSERT_NOT_REACHED();\n') | 
| + | 
| + nested_templates.append( | 
| + '\n' | 
| + 'static void $CALLBACK_NAME(Dart_NativeArguments args)\n' | 
| + '{\n' | 
| + ' DartApiScope dartApiScope;\n' | 
| + '$BODY' | 
| + '}\n') | 
| + | 
| + template_parameters = { | 
| + 'CALLBACK_NAME': callback_name, | 
| + 'WEBCORE_CLASS_NAME': self._interface_type_info.native_type(), | 
| + 'PARAMETER_DEFINITIONS': parameter_definitions, | 
| + } | 
| + for template in nested_templates: | 
| + template_parameters['BODY'] = callback | 
| + callback_emitter = emitter.Emitter() | 
| + callback_emitter.Emit(template, **template_parameters) | 
| + callback = ''.join(callback_emitter.Fragments()) | 
| + | 
| + self._cpp_definitions_emitter.Emit(callback) | 
| + | 
| + def _GenerateParameterAdapter(self, emitter, idl_argument, index): | 
| + type_info = GetIDLTypeInfo(idl_argument.type) | 
| + (adapter_type, include_name) = type_info.parameter_adapter_info() | 
| + if include_name: | 
| + self._cpp_impl_includes[include_name] = 1 | 
| + emitter.Emit( | 
| + '\n' | 
| + ' const $ADAPTER_TYPE $NAME(Dart_GetNativeArgument(args, $INDEX));\n' | 
| + ' if (!$NAME.conversionSuccessful()) {\n' | 
| + ' exception = $NAME.exception();\n' | 
| + ' goto fail;\n' | 
| + ' }\n', | 
| + ADAPTER_TYPE=adapter_type, | 
| + NAME=idl_argument.id, | 
| + INDEX=index + 1) | 
| + | 
| + def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration, | 
| + native_suffix, is_custom): | 
| + native_binding = '%s_%s_%s' % (self._interface.id, idl_name, native_suffix) | 
| + self._members_emitter.Emit( | 
| + '\n' | 
| + ' $DART_DECLARATION native "$NATIVE_BINDING";\n', | 
| + DART_DECLARATION=dart_declaration, NATIVE_BINDING=native_binding) | 
| + | 
| + cpp_callback_name = '%s%s' % (idl_name, native_suffix) | 
| + self._cpp_resolver_emitter.Emit( | 
| + ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n' | 
| + ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n', | 
| + ARGC=argument_count, | 
| + NATIVE_BINDING=native_binding, | 
| + INTERFACE_NAME=self._interface.id, | 
| + CPP_CALLBACK_NAME=cpp_callback_name) | 
| + | 
| + if is_custom: | 
| + self._cpp_declarations_emitter.Emit( | 
| + '\n' | 
| + 'void $CPP_CALLBACK_NAME(Dart_NativeArguments);\n', | 
| + CPP_CALLBACK_NAME=cpp_callback_name) | 
| + | 
| + return cpp_callback_name | 
| + | 
| + def _GenerateWebCoreReflectionAttributeName(self, attr): | 
| + namespace = 'HTMLNames' | 
| + svg_exceptions = ['class', 'id', 'onabort', 'onclick', 'onerror', 'onload', | 
| + 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', | 
| + 'onmouseup', 'onresize', 'onscroll', 'onunload'] | 
| + if self._interface.id.startswith('SVG') and not attr.id in svg_exceptions: | 
| + namespace = 'SVGNames' | 
| + self._cpp_impl_includes[namespace] = 1 | 
| + | 
| + attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower() | 
| + return 'WebCore::%s::%sAttr' % (namespace, attribute_name) | 
| + |