63b49dfc8e
TEST=No new behaviour, existing tests pass. Change-Id: Ia7a8e58543bd5e1d8dd14bd46c5083759333845b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/259104 Reviewed-by: Nate Bosch <nbosch@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Leaf Petersen <leafp@google.com>
1394 lines
57 KiB
Python
1394 lines
57 KiB
Python
#!/usr/bin/env python3
|
|
# 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 logging
|
|
import os
|
|
from generator import *
|
|
from htmldartgenerator import *
|
|
from idlnode import IDLArgument, IDLAttribute, IDLEnum, IDLMember
|
|
from systemhtml import js_support_checks, GetCallbackInfo, HTML_LIBRARY_NAMES
|
|
|
|
_logger = logging.getLogger('systemnative')
|
|
|
|
# TODO(vsm): This should be recoverable from IDL, but we appear to not
|
|
# track the necessary info.
|
|
_url_utils = [
|
|
'hash', 'host', 'hostname', 'origin', 'password', 'pathname', 'port',
|
|
'protocol', 'search', 'username'
|
|
]
|
|
|
|
_promise_to_future = Conversion('promiseToFuture', 'dynamic', 'Future')
|
|
|
|
|
|
def array_type(data_type):
|
|
matched = re.match(r'([\w\d_\s]+)\[\]', data_type)
|
|
if not matched:
|
|
return None
|
|
return matched.group(1)
|
|
|
|
|
|
_sequence_matcher = re.compile('sequence\<(.+)\>')
|
|
|
|
|
|
def TypeIdToBlinkName(interface_id, database):
|
|
# Maybe should use the type_registry here?
|
|
if database.HasEnum(interface_id):
|
|
return "DOMString" # All enums are strings.
|
|
|
|
seq_match = _sequence_matcher.match(interface_id)
|
|
if seq_match is not None:
|
|
t = TypeIdToBlinkName(seq_match.group(1), database)
|
|
return "sequence<%s>" % t
|
|
|
|
arr_match = array_type(interface_id)
|
|
if arr_match is not None:
|
|
t = TypeIdToBlinkName(arr_match, database)
|
|
return "%s[]" % t
|
|
|
|
return interface_id
|
|
|
|
|
|
def DeriveQualifiedName(library_name, name):
|
|
return library_name + "." + name
|
|
|
|
|
|
def DeriveBlinkClassName(name):
|
|
return "Blink" + name
|
|
|
|
|
|
_type_encoding_map = {
|
|
'long long': "ll",
|
|
'unsigned long': "ul",
|
|
'unsigned long long': "ull",
|
|
'unsigned short': "us",
|
|
}
|
|
|
|
|
|
def EncodeType(t):
|
|
|
|
seq_match = _sequence_matcher.match(t)
|
|
if seq_match is not None:
|
|
t2 = EncodeType(seq_match.group(1))
|
|
t = "SEQ_%s_SEQ" % t2
|
|
return t
|
|
|
|
arr_match = array_type(t)
|
|
if arr_match is not None:
|
|
t = EncodeType(arr_match)
|
|
return "A_%s_A" % t
|
|
|
|
return _type_encoding_map.get(t) or t
|
|
|
|
|
|
class DartiumBackend(HtmlDartGenerator):
|
|
"""Generates Dart implementation for one DOM IDL interface."""
|
|
|
|
def __init__(self, interface, cpp_library_emitter, options, loggerParent):
|
|
super(DartiumBackend, self).__init__(interface, options, True,
|
|
loggerParent)
|
|
|
|
self._interface = interface
|
|
self._cpp_library_emitter = cpp_library_emitter
|
|
self._database = options.database
|
|
self._template_loader = options.templates
|
|
self._type_registry = options.type_registry
|
|
self._interface_type_info = self._type_registry.TypeInfo(
|
|
self._interface.id)
|
|
self._metadata = options.metadata
|
|
# These get initialized by StartInterface
|
|
self._cpp_header_emitter = None
|
|
self._cpp_impl_emitter = None
|
|
self._members_emitter = None
|
|
self._cpp_declarations_emitter = None
|
|
self._cpp_impl_includes = None
|
|
self._cpp_definitions_emitter = None
|
|
self._cpp_resolver_emitter = None
|
|
self._dart_js_interop = options.dart_js_interop
|
|
_logger.setLevel(loggerParent.level)
|
|
|
|
def ImplementsMergedMembers(self):
|
|
# We could not add merged functions to implementation class because
|
|
# underlying c++ object doesn't implement them. Merged functions are
|
|
# generated on merged interface implementation instead.
|
|
return False
|
|
|
|
def CustomJSMembers(self):
|
|
return {}
|
|
|
|
def _OutputConversion(self, idl_type, member):
|
|
conversion = FindConversion(idl_type, 'get', self._interface.id, member)
|
|
# TODO(jacobr) handle promise consistently in dart2js and dartium.
|
|
if idl_type == 'Promise':
|
|
return _promise_to_future
|
|
if conversion:
|
|
if conversion.function_name in ('convertNativeToDart_DateTime',
|
|
'convertNativeToDart_ImageData'):
|
|
return None
|
|
return conversion
|
|
|
|
def _InputConversion(self, idl_type, member):
|
|
return FindConversion(idl_type, 'set', self._interface.id, member)
|
|
|
|
def GenerateCallback(self, info):
|
|
return None
|
|
|
|
def ImplementationTemplate(self):
|
|
template = None
|
|
interface_name = self._interface.doc_js_name
|
|
if interface_name == self._interface.id or not self._database.HasInterface(
|
|
interface_name):
|
|
template_file = 'impl_%s.darttemplate' % interface_name
|
|
template = self._template_loader.TryLoad(template_file)
|
|
if not template:
|
|
template = self._template_loader.Load(
|
|
'dart_implementation.darttemplate')
|
|
return template
|
|
|
|
def RootClassName(self):
|
|
return 'DartHtmlDomObject'
|
|
|
|
# This code matches up with the _generate_native_entry code in
|
|
# dart_utilities.py in the dartium repository. Any changes to this
|
|
# should have matching changes on that end.
|
|
def DeriveNativeEntry(self, name, kind, count):
|
|
interface_id = self._interface.id
|
|
database = self._database
|
|
tag = ""
|
|
if kind == 'Getter':
|
|
tag = "%s_Getter" % name
|
|
blink_entry = tag
|
|
elif kind == 'Setter':
|
|
tag = "%s_Setter" % name
|
|
blink_entry = tag
|
|
elif kind == 'Constructor':
|
|
tag = "constructorCallback"
|
|
blink_entry = tag
|
|
elif kind == 'Method':
|
|
tag = "%s_Callback" % name
|
|
blink_entry = tag
|
|
|
|
interface_id = TypeIdToBlinkName(interface_id, database)
|
|
|
|
def mkPublic(s):
|
|
if s.startswith("_") or s.startswith("$"):
|
|
return "$" + s
|
|
return s
|
|
|
|
if count is not None:
|
|
arity = str(count)
|
|
dart_name = mkPublic("_".join([tag, arity]))
|
|
else:
|
|
dart_name = mkPublic(tag)
|
|
resolver_string = "_".join([interface_id, tag])
|
|
|
|
return (dart_name, resolver_string)
|
|
|
|
def DeriveNativeName(self, name, suffix=""):
|
|
fields = ['$' + name]
|
|
if suffix != "":
|
|
fields.append(suffix)
|
|
return "_".join(fields)
|
|
|
|
def DeriveQualifiedBlinkName(self, interface_name, name):
|
|
blinkClass = DeriveQualifiedName("_blink",
|
|
DeriveBlinkClassName(interface_name))
|
|
blinkInstance = DeriveQualifiedName(blinkClass, "instance")
|
|
return DeriveQualifiedName(blinkInstance, name + "_")
|
|
|
|
def NativeSpec(self):
|
|
return ''
|
|
|
|
def StartInterface(self, members_emitter):
|
|
# Create emitters for c++ implementation.
|
|
if not IsPureInterface(self._interface.id, self._database) and \
|
|
not IsCustomType(self._interface.id):
|
|
self._cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter(
|
|
self._interface.id,
|
|
self._renamer.GetLibraryName(self._interface))
|
|
self._cpp_impl_emitter = \
|
|
self._cpp_library_emitter.CreateSourceEmitter(self._interface.id)
|
|
else:
|
|
self._cpp_header_emitter = emitter.Emitter()
|
|
self._cpp_impl_emitter = emitter.Emitter()
|
|
|
|
self._interface_type_info = self._TypeInfo(self._interface.id)
|
|
self._members_emitter = members_emitter
|
|
|
|
self._cpp_declarations_emitter = emitter.Emitter()
|
|
|
|
# This is a hack to work around a strange C++ compile error that we weren't
|
|
# able to track down the true cause of.
|
|
if self._interface.id == 'Timing':
|
|
self._cpp_impl_includes.add('"core/animation/TimedItem.h"')
|
|
|
|
self._cpp_definitions_emitter = emitter.Emitter()
|
|
self._cpp_resolver_emitter = emitter.Emitter()
|
|
|
|
# We need to revisit our treatment of typed arrays, right now
|
|
# it is full of hacks.
|
|
if self._interface.ext_attrs.get('ConstructorTemplate') == 'TypedArray':
|
|
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_impl_includes.add('"DartArrayBufferViewCustom.h"')
|
|
self._cpp_definitions_emitter.Emit(
|
|
'\n'
|
|
'static void constructorCallback(Dart_NativeArguments args)\n'
|
|
'{\n'
|
|
' WebCore::DartArrayBufferViewInternal::constructWebGLArray<Dart$(INTERFACE_NAME)>(args);\n'
|
|
'}\n',
|
|
INTERFACE_NAME=self._interface.id)
|
|
|
|
def _EmitConstructorInfrastructure(self,
|
|
constructor_info,
|
|
cpp_prefix,
|
|
cpp_suffix,
|
|
factory_method_name,
|
|
arguments=None,
|
|
emit_to_native=False,
|
|
is_custom=False):
|
|
|
|
constructor_callback_cpp_name = cpp_prefix + cpp_suffix
|
|
|
|
if arguments is None:
|
|
arguments = constructor_info.idl_args[0]
|
|
argument_count = len(arguments)
|
|
else:
|
|
argument_count = len(arguments)
|
|
|
|
typed_formals = constructor_info.ParametersAsArgumentList(
|
|
argument_count)
|
|
parameters = constructor_info.ParametersAsStringOfVariables(
|
|
argument_count)
|
|
interface_name = self._interface_type_info.interface_name()
|
|
|
|
dart_native_name, constructor_callback_id = \
|
|
self.DeriveNativeEntry(cpp_suffix, 'Constructor', argument_count)
|
|
|
|
# Then we emit the impedance matching wrapper to call out to the
|
|
# toplevel wrapper
|
|
if not emit_to_native:
|
|
toplevel_name = \
|
|
self.DeriveQualifiedBlinkName(self._interface.id,
|
|
dart_native_name)
|
|
self._members_emitter.Emit(
|
|
' static $INTERFACE_NAME $FACTORY_METHOD_NAME($PARAMETERS) => '
|
|
'$TOPLEVEL_NAME($OUTPARAMETERS);\n',
|
|
INTERFACE_NAME=self._interface_type_info.interface_name(),
|
|
FACTORY_METHOD_NAME=factory_method_name,
|
|
PARAMETERS=typed_formals,
|
|
TOPLEVEL_NAME=toplevel_name,
|
|
OUTPARAMETERS=parameters)
|
|
|
|
self._cpp_resolver_emitter.Emit(
|
|
' if (name == "$ID")\n'
|
|
' return Dart$(WEBKIT_INTERFACE_NAME)Internal::$CPP_CALLBACK;\n',
|
|
ID=constructor_callback_id,
|
|
WEBKIT_INTERFACE_NAME=self._interface.id,
|
|
CPP_CALLBACK=constructor_callback_cpp_name)
|
|
|
|
def GenerateCustomFactory(self, constructor_info):
|
|
if 'CustomConstructor' not in self._interface.ext_attrs:
|
|
return False
|
|
|
|
annotations = self._metadata.GetFormattedMetadata(
|
|
self._library_name, self._interface, self._interface.id, ' ')
|
|
|
|
self._members_emitter.Emit(
|
|
'\n $(ANNOTATIONS)factory $CTOR($PARAMS) => _create($FACTORY_PARAMS);\n',
|
|
ANNOTATIONS=annotations,
|
|
CTOR=constructor_info._ConstructorFullName(self._DartType),
|
|
PARAMS=constructor_info.ParametersAsDeclaration(self._DartType),
|
|
FACTORY_PARAMS= \
|
|
constructor_info.ParametersAsArgumentList())
|
|
|
|
# MutationObserver has custom _create. TODO(terry): Consider table but this is only one.
|
|
if self._interface.id != 'MutationObserver':
|
|
constructor_callback_cpp_name = 'constructorCallback'
|
|
self._EmitConstructorInfrastructure(
|
|
constructor_info,
|
|
"",
|
|
constructor_callback_cpp_name,
|
|
'_create',
|
|
is_custom=True)
|
|
|
|
self._cpp_declarations_emitter.Emit(
|
|
'\n'
|
|
'void $CPP_CALLBACK(Dart_NativeArguments);\n',
|
|
CPP_CALLBACK=constructor_callback_cpp_name)
|
|
|
|
return True
|
|
|
|
def IsConstructorArgumentOptional(self, argument):
|
|
return IsOptional(argument)
|
|
|
|
def MakeFactoryCall(self, factory, method, arguments, constructor_info):
|
|
return emitter.Format(
|
|
'$FACTORY.$METHOD($ARGUMENTS)',
|
|
FACTORY=factory,
|
|
METHOD=method,
|
|
ARGUMENTS=arguments)
|
|
|
|
def EmitStaticFactoryOverload(self, constructor_info, name, arguments):
|
|
constructor_callback_cpp_name = name + 'constructorCallback'
|
|
self._EmitConstructorInfrastructure(
|
|
constructor_info,
|
|
name,
|
|
'constructorCallback',
|
|
name,
|
|
arguments,
|
|
emit_to_native=True,
|
|
is_custom=False)
|
|
|
|
ext_attrs = self._interface.ext_attrs
|
|
|
|
create_function = 'create'
|
|
if 'NamedConstructor' in ext_attrs:
|
|
create_function = 'createForJSConstructor'
|
|
function_expression = '%s::%s' % (
|
|
self._interface_type_info.native_type(), create_function)
|
|
|
|
def HasSupportCheck(self):
|
|
# Need to omit a support check if it is conditional in JS.
|
|
return self._interface.doc_js_name in js_support_checks
|
|
|
|
def GetSupportCheck(self):
|
|
# Assume that everything is supported on Dartium.
|
|
value = js_support_checks.get(self._interface.doc_js_name)
|
|
if type(value) == tuple:
|
|
return (value[0], 'true')
|
|
else:
|
|
return 'true'
|
|
|
|
def FinishInterface(self):
|
|
interface = self._interface
|
|
if interface.parents:
|
|
supertype = '%sClassId' % interface.parents[0].type.id
|
|
else:
|
|
supertype = '-1'
|
|
|
|
self._GenerateCPPHeader()
|
|
|
|
self._cpp_impl_emitter.Emit(
|
|
self._template_loader.Load('cpp_implementation.template'),
|
|
INTERFACE=self._interface.id,
|
|
SUPER_INTERFACE=supertype,
|
|
INCLUDES=self._GenerateCPPIncludes(self._cpp_impl_includes),
|
|
CALLBACKS=self._cpp_definitions_emitter.Fragments(),
|
|
RESOLVER=self._cpp_resolver_emitter.Fragments(),
|
|
WEBCORE_CLASS_NAME=self._interface_type_info.native_type(),
|
|
WEBCORE_CLASS_NAME_ESCAPED=self._interface_type_info.native_type().
|
|
replace('<', '_').replace('>', '_'),
|
|
DART_IMPLEMENTATION_CLASS=self._interface_type_info.
|
|
implementation_name(),
|
|
DART_IMPLEMENTATION_LIBRARY_ID='Dart%sLibraryId' %
|
|
self._renamer.GetLibraryId(self._interface))
|
|
|
|
def _GenerateCPPHeader(self):
|
|
to_native_emitter = emitter.Emitter()
|
|
if self._interface_type_info.custom_to_native():
|
|
return_type = 'PassRefPtr<NativeType>'
|
|
to_native_body = ';'
|
|
to_native_arg_body = ';'
|
|
else:
|
|
return_type = 'NativeType*'
|
|
to_native_body = emitter.Format(
|
|
'\n'
|
|
' {\n'
|
|
' DartDOMData* domData = DartDOMData::current();\n'
|
|
' return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(domData, handle, exception);\n'
|
|
' }',
|
|
INTERFACE=self._interface.id)
|
|
to_native_arg_body = emitter.Format(
|
|
'\n'
|
|
' {\n'
|
|
' return DartDOMWrapper::unwrapDartWrapper<Dart$INTERFACE>(args, index, exception);\n'
|
|
' }',
|
|
INTERFACE=self._interface.id)
|
|
|
|
to_native_emitter.Emit(
|
|
' static $RETURN_TYPE toNative(Dart_Handle handle, Dart_Handle& exception)$TO_NATIVE_BODY\n'
|
|
'\n'
|
|
' static $RETURN_TYPE toNativeWithNullCheck(Dart_Handle handle, Dart_Handle& exception)\n'
|
|
' {\n'
|
|
' return Dart_IsNull(handle) ? 0 : toNative(handle, exception);\n'
|
|
' }\n'
|
|
'\n'
|
|
' static $RETURN_TYPE toNative(Dart_NativeArguments args, int index, Dart_Handle& exception)$TO_NATIVE_ARG_BODY\n'
|
|
'\n'
|
|
' static $RETURN_TYPE toNativeWithNullCheck(Dart_NativeArguments args, int index, Dart_Handle& exception)\n'
|
|
' {\n'
|
|
' // toNative accounts for Null objects also.\n'
|
|
' return toNative(args, index, exception);\n'
|
|
' }\n',
|
|
RETURN_TYPE=return_type,
|
|
TO_NATIVE_BODY=to_native_body,
|
|
TO_NATIVE_ARG_BODY=to_native_arg_body,
|
|
INTERFACE=self._interface.id)
|
|
|
|
to_dart_emitter = emitter.Emitter()
|
|
|
|
ext_attrs = self._interface.ext_attrs
|
|
|
|
to_dart_emitter.Emit(
|
|
' static Dart_Handle toDart(NativeType* value)\n'
|
|
' {\n'
|
|
' if (!value)\n'
|
|
' return Dart_Null();\n'
|
|
' DartDOMData* domData = DartDOMData::current();\n'
|
|
' Dart_WeakPersistentHandle result =\n'
|
|
' DartDOMWrapper::lookupWrapper<Dart$(INTERFACE)>(domData, value);\n'
|
|
' if (result)\n'
|
|
' return Dart_HandleFromWeakPersistent(result);\n'
|
|
' return createWrapper(domData, value);\n'
|
|
' }\n'
|
|
' static void returnToDart(Dart_NativeArguments args,\n'
|
|
' NativeType* value,\n'
|
|
' bool autoDartScope = true)\n'
|
|
' {\n'
|
|
' if (value) {\n'
|
|
' DartDOMData* domData = static_cast<DartDOMData*>(\n'
|
|
' Dart_GetNativeIsolateData(args));\n'
|
|
' Dart_WeakPersistentHandle result =\n'
|
|
' DartDOMWrapper::lookupWrapper<Dart$(INTERFACE)>(domData, value);\n'
|
|
' if (result)\n'
|
|
' Dart_SetWeakHandleReturnValue(args, result);\n'
|
|
' else {\n'
|
|
' if (autoDartScope) {\n'
|
|
' Dart_SetReturnValue(args, createWrapper(domData, value));\n'
|
|
' } else {\n'
|
|
' DartApiScope apiScope;\n'
|
|
' Dart_SetReturnValue(args, createWrapper(domData, value));\n'
|
|
' }\n'
|
|
' }\n'
|
|
' }\n'
|
|
' }\n',
|
|
INTERFACE=self._interface.id)
|
|
|
|
if ('CustomToV8' in ext_attrs or 'PureInterface' in ext_attrs or
|
|
'CPPPureInterface' in ext_attrs or
|
|
'SpecialWrapFor' in ext_attrs or
|
|
('Custom' in ext_attrs and ext_attrs['Custom'] == 'Wrap') or
|
|
('Custom' in ext_attrs and ext_attrs['Custom'] == 'ToV8') or
|
|
self._interface_type_info.custom_to_dart()):
|
|
to_dart_emitter.Emit(
|
|
' static Dart_Handle createWrapper(DartDOMData* domData, NativeType* value);\n'
|
|
)
|
|
else:
|
|
to_dart_emitter.Emit(
|
|
' static Dart_Handle createWrapper(DartDOMData* domData, NativeType* value)\n'
|
|
' {\n'
|
|
' return DartDOMWrapper::createWrapper<Dart$(INTERFACE)>(domData, value, Dart$(INTERFACE)::dartClassId);\n'
|
|
' }\n',
|
|
INTERFACE=self._interface.id)
|
|
|
|
webcore_includes = self._GenerateCPPIncludes(
|
|
self._interface_type_info.webcore_includes())
|
|
|
|
is_node_test = lambda interface: interface.id == 'Node'
|
|
is_active_test = lambda interface: 'ActiveDOMObject' in interface.ext_attrs
|
|
is_event_target_test = lambda interface: 'EventTarget' in interface.ext_attrs
|
|
|
|
def TypeCheckHelper(test):
|
|
return 'true' if any(
|
|
map(test, self._database.Hierarchy(
|
|
self._interface))) else 'false'
|
|
|
|
to_active_emitter = emitter.Emitter()
|
|
to_node_emitter = emitter.Emitter()
|
|
to_event_target_emitter = emitter.Emitter()
|
|
|
|
if (any(map(is_active_test,
|
|
self._database.Hierarchy(self._interface)))):
|
|
to_active_emitter.Emit('return toNative(value);')
|
|
else:
|
|
to_active_emitter.Emit('return 0;')
|
|
|
|
if (any(map(is_node_test, self._database.Hierarchy(self._interface)))):
|
|
to_node_emitter.Emit('return toNative(value);')
|
|
else:
|
|
to_node_emitter.Emit('return 0;')
|
|
|
|
if (any(
|
|
map(is_event_target_test,
|
|
self._database.Hierarchy(self._interface)))):
|
|
to_event_target_emitter.Emit('return toNative(value);')
|
|
else:
|
|
to_event_target_emitter.Emit('return 0;')
|
|
|
|
v8_interface_include = ''
|
|
# V8AbstractWorker.h does not exist so we have to hard code this case.
|
|
if self._interface.id != 'AbstractWorker':
|
|
# FIXME: We need this to access the WrapperTypeInfo.
|
|
v8_interface_include = '#include "V8%s.h"' % (self._interface.id)
|
|
|
|
self._cpp_header_emitter.Emit(
|
|
self._template_loader.Load('cpp_header.template'),
|
|
INTERFACE=self._interface.id,
|
|
WEBCORE_INCLUDES=webcore_includes,
|
|
V8_INTERFACE_INCLUDE=v8_interface_include,
|
|
WEBCORE_CLASS_NAME=self._interface_type_info.native_type(),
|
|
WEBCORE_CLASS_NAME_ESCAPED=self._interface_type_info.native_type().
|
|
replace('<', '_').replace('>', '_'),
|
|
DECLARATIONS=self._cpp_declarations_emitter.Fragments(),
|
|
IS_NODE=TypeCheckHelper(is_node_test),
|
|
IS_ACTIVE=TypeCheckHelper(is_active_test),
|
|
IS_EVENT_TARGET=TypeCheckHelper(is_event_target_test),
|
|
TO_NODE=to_node_emitter.Fragments(),
|
|
TO_ACTIVE=to_active_emitter.Fragments(),
|
|
TO_EVENT_TARGET=to_event_target_emitter.Fragments(),
|
|
TO_NATIVE=to_native_emitter.Fragments(),
|
|
TO_DART=to_dart_emitter.Fragments())
|
|
|
|
def EmitAttribute(self, attribute, html_name, read_only):
|
|
self._AddGetter(attribute, html_name, read_only)
|
|
if not read_only:
|
|
self._AddSetter(attribute, html_name)
|
|
|
|
def _GenerateAutoSetupScope(self, idl_name, native_suffix):
|
|
return None
|
|
|
|
def _AddGetter(self, attr, html_name, read_only):
|
|
# Temporary hack to force dart:scalarlist clamped array for ImageData.data.
|
|
# TODO(antonm): solve in principled way.
|
|
if self._interface.id == 'ImageData' and html_name == 'data':
|
|
html_name = '_data'
|
|
type_info = self._TypeInfo(attr.type.id)
|
|
|
|
return_type = self.SecureOutputType(
|
|
attr.type.id, False, False if self._dart_use_blink else True)
|
|
dictionary_returned = False
|
|
# Return type for dictionary is any (untyped).
|
|
if attr.type.id == 'Dictionary':
|
|
return_type = ''
|
|
dictionary_returned = True
|
|
|
|
parameters = []
|
|
dart_declaration = '%s get %s' % (return_type, html_name)
|
|
is_custom = _IsCustom(attr) and (_IsCustomValue(attr, None) or
|
|
_IsCustomValue(attr, 'Getter'))
|
|
|
|
# Operation uses blink?
|
|
wrap_unwrap_list = []
|
|
return_wrap_jso = False
|
|
if self._dart_use_blink:
|
|
# Unwrap the type to get the JsObject if Type is:
|
|
#
|
|
# - known IDL type
|
|
# - type_id is None then it's probably a union type or overloaded
|
|
# it's a dynamic/any type
|
|
# - type is Object
|
|
#
|
|
# JsObject maybe stored in the Dart class.
|
|
return_wrap_jso = wrap_return_type_blink(return_type, attr.type.id,
|
|
self._type_registry)
|
|
wrap_unwrap_list.append(return_wrap_jso) # wrap_jso the returned object
|
|
wrap_unwrap_list.append(self._dart_use_blink)
|
|
|
|
# This seems to have been replaced with Custom=Getter (see above), but
|
|
# check to be sure we don't see the old syntax
|
|
assert (not ('CustomGetter' in attr.ext_attrs))
|
|
native_suffix = 'Getter'
|
|
auto_scope_setup = self._GenerateAutoSetupScope(attr.id, native_suffix)
|
|
native_entry = \
|
|
self.DeriveNativeEntry(attr.id, 'Getter', None)
|
|
output_conversion = self._OutputConversion(attr.type.id, attr.id)
|
|
|
|
cpp_callback_name = self._GenerateNativeBinding(
|
|
attr.id,
|
|
1,
|
|
dart_declaration,
|
|
attr.is_static,
|
|
return_type,
|
|
parameters,
|
|
native_suffix,
|
|
is_custom,
|
|
auto_scope_setup,
|
|
native_entry=native_entry,
|
|
wrap_unwrap_list=wrap_unwrap_list,
|
|
dictionary_return=dictionary_returned,
|
|
output_conversion=output_conversion)
|
|
if is_custom:
|
|
return
|
|
|
|
if 'Reflect' in attr.ext_attrs:
|
|
webcore_function_name = self._TypeInfo(
|
|
attr.type.id).webcore_getter_name()
|
|
if 'URL' in attr.ext_attrs:
|
|
if 'NonEmpty' in attr.ext_attrs:
|
|
webcore_function_name = 'getNonEmptyURLAttribute'
|
|
else:
|
|
webcore_function_name = 'getURLAttribute'
|
|
elif 'ImplementedAs' in attr.ext_attrs:
|
|
webcore_function_name = attr.ext_attrs['ImplementedAs']
|
|
else:
|
|
if attr.id == 'operator':
|
|
webcore_function_name = '_operator'
|
|
elif attr.id == 'target' and attr.type.id == 'SVGAnimatedString':
|
|
webcore_function_name = 'svgTarget'
|
|
elif attr.id == 'CSS':
|
|
webcore_function_name = 'css'
|
|
else:
|
|
webcore_function_name = self._ToWebKitName(attr.id)
|
|
|
|
function_expression = self._GenerateWebCoreFunctionExpression(
|
|
webcore_function_name, attr)
|
|
raises = ('RaisesException' in attr.ext_attrs and
|
|
attr.ext_attrs['RaisesException'] != 'Setter')
|
|
|
|
def _AddSetter(self, attr, html_name):
|
|
return_type = 'void'
|
|
ptype = self._DartType(attr.type.id)
|
|
|
|
type_info = self._TypeInfo(attr.type.id)
|
|
|
|
# Is the setter value a DartClass (that has a JsObject) or the type is
|
|
# None (it's a dynamic/any type) then unwrap_jso before passing to blink.
|
|
parameters = ['value']
|
|
|
|
dart_declaration = 'set %s(%s value)' % (html_name, ptype)
|
|
is_custom = _IsCustom(attr) and (_IsCustomValue(attr, None) or
|
|
_IsCustomValue(attr, 'Setter'))
|
|
# This seems to have been replaced with Custom=Setter (see above), but
|
|
# check to be sure we don't see the old syntax
|
|
assert (not ('CustomSetter' in attr.ext_attrs))
|
|
assert (not ('V8CustomSetter' in attr.ext_attrs))
|
|
native_suffix = 'Setter'
|
|
auto_scope_setup = self._GenerateAutoSetupScope(attr.id, native_suffix)
|
|
native_entry = \
|
|
self.DeriveNativeEntry(attr.id, 'Setter', None)
|
|
|
|
# setters return no object and if blink this must be unwrapped.?
|
|
wrap_unwrap_list = [False, self._dart_use_blink]
|
|
|
|
cpp_callback_name = self._GenerateNativeBinding(
|
|
attr.id,
|
|
2,
|
|
dart_declaration,
|
|
attr.is_static,
|
|
return_type,
|
|
parameters,
|
|
native_suffix,
|
|
is_custom,
|
|
auto_scope_setup,
|
|
native_entry=native_entry,
|
|
wrap_unwrap_list=wrap_unwrap_list)
|
|
if is_custom:
|
|
return
|
|
|
|
if 'Reflect' in attr.ext_attrs:
|
|
webcore_function_name = self._TypeInfo(
|
|
attr.type.id).webcore_setter_name()
|
|
else:
|
|
if 'ImplementedAs' in attr.ext_attrs:
|
|
attr_name = attr.ext_attrs['ImplementedAs']
|
|
else:
|
|
attr_name = attr.id
|
|
webcore_function_name = re.sub(r'^(xml|css|(?=[A-Z])|\w)',
|
|
lambda s: s.group(1).upper(),
|
|
attr_name)
|
|
webcore_function_name = 'set%s' % webcore_function_name
|
|
|
|
function_expression = self._GenerateWebCoreFunctionExpression(
|
|
webcore_function_name, attr)
|
|
raises = ('RaisesException' in attr.ext_attrs and
|
|
attr.ext_attrs['RaisesException'] != 'Getter')
|
|
|
|
def AddIndexer(self, element_type, nullable):
|
|
"""Adds all the methods required to complete implementation of List."""
|
|
# We would like to simply inherit the implementation of everything except
|
|
# length, [], and maybe []=. It is possible to extend from a base
|
|
# array implementation class only when there is no other implementation
|
|
# inheritance. There might be no implementation inheritance other than
|
|
# DOMBaseWrapper for many classes, but there might be some where the
|
|
# array-ness is introduced by a non-root interface:
|
|
#
|
|
# interface Y extends X, List<T> ...
|
|
#
|
|
# In the non-root case we have to choose between:
|
|
#
|
|
# class YImpl extends XImpl { add List<T> methods; }
|
|
#
|
|
# and
|
|
#
|
|
# class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
|
|
#
|
|
dart_element_type = self._DartType(element_type)
|
|
if self._HasNativeIndexGetter():
|
|
self._EmitNativeIndexGetter(dart_element_type)
|
|
elif self._HasExplicitIndexedGetter():
|
|
self._EmitExplicitIndexedGetter(dart_element_type)
|
|
else:
|
|
is_custom = any((op.id == 'item' and _IsCustom(op))
|
|
for op in self._interface.operations)
|
|
|
|
output_conversion = self._OutputConversion(element_type, 'item')
|
|
conversion_name = ''
|
|
if output_conversion:
|
|
conversion_name = output_conversion.function_name
|
|
|
|
# First emit a toplevel function to do the native call
|
|
# Calls to this are emitted elsewhere,
|
|
dart_native_name, resolver_string = \
|
|
self.DeriveNativeEntry("item", 'Method', 1)
|
|
|
|
# Emit the method which calls the toplevel function, along with
|
|
# the [] operator.
|
|
dart_qualified_name = \
|
|
self.DeriveQualifiedBlinkName(self._interface.id,
|
|
dart_native_name)
|
|
|
|
type_info = self._TypeInfo(element_type)
|
|
blinkNativeIndexed = """
|
|
$TYPE operator[](int index) {
|
|
if (index < 0 || index >= length)
|
|
throw new IndexError.withLength(index, length, indexable: this);
|
|
return _nativeIndexedGetter(index);
|
|
}
|
|
|
|
$TYPE _nativeIndexedGetter(int index) => $(CONVERSION_NAME)($(DART_NATIVE_NAME)(this, index));
|
|
"""
|
|
blinkNativeIndexedGetter = \
|
|
' $(DART_NATIVE_NAME)(this, index);\n'
|
|
self._members_emitter.Emit(
|
|
blinkNativeIndexed,
|
|
DART_NATIVE_NAME=dart_qualified_name,
|
|
TYPE=self.SecureOutputType(element_type),
|
|
INTERFACE=self._interface.id,
|
|
CONVERSION_NAME=conversion_name)
|
|
|
|
if self._HasNativeIndexSetter():
|
|
self._EmitNativeIndexSetter(dart_element_type)
|
|
else:
|
|
self._members_emitter.Emit(
|
|
'\n'
|
|
' void operator[]=(int index, $TYPE value) {\n'
|
|
' throw new UnsupportedError("Cannot assign element of immutable List.");\n'
|
|
' }\n',
|
|
TYPE=dart_element_type)
|
|
|
|
self.EmitListMixin(dart_element_type, nullable)
|
|
|
|
def AmendIndexer(self, element_type):
|
|
# If interface is marked as having native indexed
|
|
# getter or setter, we must emit overrides as it's not
|
|
# guaranteed that the corresponding methods in C++ would be
|
|
# virtual. For example, as of time of writing, even though
|
|
# Uint8ClampedArray inherits from Uint8Array, ::set method
|
|
# is not virtual and accessing it through Uint8Array pointer
|
|
# would lead to wrong semantics (modulo vs. clamping.)
|
|
dart_element_type = self._DartType(element_type)
|
|
|
|
if self._HasNativeIndexGetter():
|
|
self._EmitNativeIndexGetter(dart_element_type)
|
|
if self._HasNativeIndexSetter():
|
|
self._EmitNativeIndexSetter(dart_element_type)
|
|
|
|
def _HasNativeIndexGetter(self):
|
|
return 'CustomIndexedGetter' in self._interface.ext_attrs
|
|
|
|
def _EmitNativeIndexGetter(self, element_type):
|
|
return_type = self.SecureOutputType(element_type, True)
|
|
parameters = ['index']
|
|
dart_declaration = '%s operator[](int index)' % return_type
|
|
self._GenerateNativeBinding('numericIndexGetter', 2, dart_declaration,
|
|
False, return_type, parameters, 'Callback',
|
|
True, False)
|
|
|
|
def _HasExplicitIndexedGetter(self):
|
|
return any(op.id == 'getItem' for op in self._interface.operations)
|
|
|
|
def _EmitExplicitIndexedGetter(self, dart_element_type):
|
|
if any(op.id == 'getItem' for op in self._interface.operations):
|
|
indexed_getter = 'getItem'
|
|
|
|
self._members_emitter.Emit(
|
|
'\n'
|
|
' $TYPE operator[](int index) {\n'
|
|
' if (index < 0 || index >= length)\n'
|
|
' throw new IndexError.withLength(index, length, indexable: this);\n'
|
|
' return $INDEXED_GETTER(index);\n'
|
|
' }\n',
|
|
TYPE=dart_element_type,
|
|
INDEXED_GETTER=indexed_getter)
|
|
|
|
def _HasNativeIndexSetter(self):
|
|
return 'CustomIndexedSetter' in self._interface.ext_attrs
|
|
|
|
def _EmitNativeIndexSetter(self, element_type):
|
|
return_type = 'void'
|
|
formals = ', '.join(['int index', '%s value' % element_type])
|
|
parameters = ['index', 'value']
|
|
dart_declaration = 'void operator[]=(%s)' % formals
|
|
self._GenerateNativeBinding('numericIndexSetter', 3, dart_declaration,
|
|
False, return_type, parameters, 'Callback',
|
|
True, False)
|
|
|
|
def _ChangePrivateOpMapArgToAny(self, operations):
|
|
# TODO(terry): Hack to map any operations marked as private to not
|
|
# handle converting Map to native (JsObject) the public
|
|
# members that call the private method will have done
|
|
# conversions.
|
|
for operation in operations:
|
|
for arg in operation.arguments:
|
|
type = arg.type
|
|
if type.id == 'Dictionary':
|
|
type.id = 'any'
|
|
|
|
def EmitOperation(self, info, html_name, dart_js_interop=False):
|
|
"""
|
|
Arguments:
|
|
info: An OperationInfo object.
|
|
"""
|
|
if self._renamer.isPrivate(self._interface, info.operations[0].id):
|
|
# Any private operations with Maps parameters changed to any type.
|
|
# The public method that delegates to this private operation has already
|
|
# converted from Map to native (JsObject) e.g., Element.animate.
|
|
self._ChangePrivateOpMapArgToAny(info.operations)
|
|
|
|
return_type = self.SecureOutputType(info.type_name, False,
|
|
False if dart_js_interop else True)
|
|
|
|
formals = info.ParametersAsDeclaration(self._DartType)
|
|
|
|
parameters = info.ParametersAsListOfVariables(
|
|
None, self._type_registry if self._dart_use_blink else None,
|
|
dart_js_interop, self)
|
|
|
|
operation = info.operations[0]
|
|
|
|
output_conversion = self._OutputConversion(operation.type.id,
|
|
operation.id)
|
|
|
|
dictionary_returned = False
|
|
# Return type for dictionary is any (untyped).
|
|
if operation.type.id == 'Dictionary':
|
|
return_type = ''
|
|
dictionary_returned = True
|
|
|
|
dart_declaration = '%s%s %s(%s)' % ('static ' if info.IsStatic() else
|
|
'', return_type, html_name, formals)
|
|
|
|
is_custom = _IsCustom(operation)
|
|
has_optional_arguments = any(
|
|
IsOptional(argument) for argument in operation.arguments)
|
|
needs_dispatcher = not is_custom and (len(info.operations) > 1 or
|
|
has_optional_arguments)
|
|
|
|
# Operation uses blink?
|
|
wrap_unwrap_list = []
|
|
return_wrap_jso = False
|
|
# return type wrapped?
|
|
if self._dart_use_blink:
|
|
# Wrap the type to store the JsObject if Type is:
|
|
#
|
|
# it's a dynamic/any type
|
|
# - type is Object
|
|
#
|
|
# JsObject maybe stored in the Dart class.
|
|
return_wrap_jso = wrap_return_type_blink(
|
|
return_type, info.type_name, self._type_registry)
|
|
return_type_info = self._type_registry.TypeInfo(info.type_name)
|
|
# wrap_jso the returned object
|
|
wrap_unwrap_list.append(return_wrap_jso)
|
|
wrap_unwrap_list.append(self._dart_use_blink)
|
|
|
|
if info.callback_args:
|
|
self._AddFutureifiedOperation(info, html_name)
|
|
elif not needs_dispatcher:
|
|
# Bind directly to native implementation
|
|
argument_count = (0 if info.IsStatic() else 1) + len(
|
|
info.param_infos)
|
|
native_suffix = 'Callback'
|
|
auto_scope_setup = self._GenerateAutoSetupScope(
|
|
info.name, native_suffix)
|
|
native_entry = \
|
|
self.DeriveNativeEntry(operation.id, 'Method', len(info.param_infos))
|
|
cpp_callback_name = self._GenerateNativeBinding(
|
|
info.name,
|
|
argument_count,
|
|
dart_declaration,
|
|
info.IsStatic(),
|
|
return_type,
|
|
parameters,
|
|
native_suffix,
|
|
is_custom,
|
|
auto_scope_setup,
|
|
native_entry=native_entry,
|
|
wrap_unwrap_list=wrap_unwrap_list,
|
|
dictionary_return=dictionary_returned,
|
|
output_conversion=output_conversion)
|
|
if not is_custom:
|
|
self._GenerateOperationNativeCallback(
|
|
operation, operation.arguments, cpp_callback_name,
|
|
auto_scope_setup)
|
|
else:
|
|
self._GenerateDispatcher(info, info.operations, dart_declaration,
|
|
html_name)
|
|
|
|
def _GenerateDispatcher(self, info, operations, dart_declaration,
|
|
html_name):
|
|
|
|
def GenerateCall(stmts_emitter, call_emitter, version, operation,
|
|
argument_count):
|
|
native_suffix = 'Callback'
|
|
actuals = info.ParametersAsListOfVariables(
|
|
argument_count,
|
|
self._type_registry if self._dart_use_blink else None,
|
|
self._dart_js_interop, self)
|
|
actuals_s = ", ".join(actuals)
|
|
formals = actuals
|
|
return_type = self.SecureOutputType(operation.type.id)
|
|
|
|
return_wrap_jso = False
|
|
if self._dart_use_blink:
|
|
return_wrap_jso = wrap_return_type_blink(
|
|
return_type, info.type_name, self._type_registry)
|
|
|
|
native_suffix = 'Callback'
|
|
is_custom = _IsCustom(operation)
|
|
base_name = '_%s_%s' % (operation.id, version)
|
|
static = True
|
|
if not operation.is_static:
|
|
actuals = ['this'] + actuals
|
|
formals = ['mthis'] + formals
|
|
actuals_s = ", ".join(actuals)
|
|
formals_s = ", ".join(formals)
|
|
dart_declaration = '%s(%s)' % (base_name, formals_s)
|
|
native_entry = \
|
|
self.DeriveNativeEntry(operation.id, 'Method', argument_count)
|
|
overload_base_name = native_entry[0]
|
|
overload_name = \
|
|
self.DeriveQualifiedBlinkName(self._interface.id,
|
|
overload_base_name)
|
|
call_emitter.Emit(
|
|
'$NAME($ARGS)', NAME=overload_name, ARGS=actuals_s)
|
|
auto_scope_setup = \
|
|
self._GenerateAutoSetupScope(base_name, native_suffix)
|
|
cpp_callback_name = self._GenerateNativeBinding(
|
|
base_name, (0 if static else 1) + argument_count,
|
|
dart_declaration,
|
|
static,
|
|
return_type,
|
|
formals,
|
|
native_suffix,
|
|
is_custom,
|
|
auto_scope_setup,
|
|
emit_metadata=False,
|
|
emit_to_native=True,
|
|
native_entry=native_entry)
|
|
if not is_custom:
|
|
self._GenerateOperationNativeCallback(
|
|
operation, operation.arguments[:argument_count],
|
|
cpp_callback_name, auto_scope_setup)
|
|
|
|
self._GenerateDispatcherBody(info, operations, dart_declaration,
|
|
GenerateCall, IsOptional)
|
|
|
|
def SecondaryContext(self, interface):
|
|
pass
|
|
|
|
def _GenerateOperationNativeCallback(self,
|
|
operation,
|
|
arguments,
|
|
cpp_callback_name,
|
|
auto_scope_setup=True):
|
|
webcore_function_name = operation.ext_attrs.get('ImplementedAs',
|
|
operation.id)
|
|
|
|
function_expression = self._GenerateWebCoreFunctionExpression(
|
|
webcore_function_name, operation, cpp_callback_name)
|
|
|
|
def _GenerateNativeBinding(self,
|
|
idl_name,
|
|
argument_count,
|
|
dart_declaration,
|
|
static,
|
|
return_type,
|
|
parameters,
|
|
native_suffix,
|
|
is_custom,
|
|
auto_scope_setup=True,
|
|
emit_metadata=True,
|
|
emit_to_native=False,
|
|
native_entry=None,
|
|
wrap_unwrap_list=[],
|
|
dictionary_return=False,
|
|
output_conversion=None):
|
|
metadata = []
|
|
if emit_metadata:
|
|
metadata = self._metadata.GetFormattedMetadata(
|
|
self._renamer.GetLibraryName(self._interface), self._interface,
|
|
idl_name, ' ')
|
|
|
|
if (native_entry):
|
|
dart_native_name, native_binding = native_entry
|
|
else:
|
|
dart_native_name = \
|
|
self.DeriveNativeName(idl_name, native_suffix)
|
|
native_binding_id = self._interface.id
|
|
native_binding_id = TypeIdToBlinkName(native_binding_id,
|
|
self._database)
|
|
native_binding = \
|
|
'%s_%s_%s' % (native_binding_id, idl_name, native_suffix)
|
|
|
|
if not static:
|
|
formals = ", ".join(['mthis'] + parameters)
|
|
actuals = ", ".join(['this'] + parameters)
|
|
else:
|
|
formals = ", ".join(parameters)
|
|
actuals = ", ".join(parameters)
|
|
|
|
if not emit_to_native:
|
|
caller_emitter = self._members_emitter
|
|
full_dart_name = \
|
|
self.DeriveQualifiedBlinkName(self._interface.id,
|
|
dart_native_name)
|
|
if IsPureInterface(self._interface.id, self._database):
|
|
caller_emitter.Emit('\n'
|
|
' $METADATA$DART_DECLARATION;\n',
|
|
METADATA=metadata,
|
|
DART_DECLARATION=dart_declaration)
|
|
else:
|
|
emit_template = '''
|
|
$METADATA$DART_DECLARATION => $DART_NAME($ACTUALS);
|
|
'''
|
|
if output_conversion and not dictionary_return:
|
|
conversion_template = '''
|
|
$METADATA$DART_DECLARATION => %s($DART_NAME($ACTUALS));
|
|
'''
|
|
emit_template = conversion_template % output_conversion.function_name
|
|
|
|
elif wrap_unwrap_list and wrap_unwrap_list[0]:
|
|
if return_type == 'Rectangle':
|
|
jso_util_method = 'make_dart_rectangle'
|
|
elif wrap_unwrap_list[0]:
|
|
jso_util_method = ''
|
|
|
|
if dictionary_return:
|
|
emit_jso_template = '''
|
|
$METADATA$DART_DECLARATION => convertNativeDictionaryToDartDictionary(%s($DART_NAME($ACTUALS)));
|
|
'''
|
|
else:
|
|
emit_jso_template = '''
|
|
$METADATA$DART_DECLARATION => %s($DART_NAME($ACTUALS));
|
|
'''
|
|
emit_template = emit_jso_template % jso_util_method
|
|
|
|
if caller_emitter:
|
|
caller_emitter.Emit(
|
|
emit_template,
|
|
METADATA=metadata,
|
|
DART_DECLARATION=dart_declaration,
|
|
DART_NAME=full_dart_name,
|
|
ACTUALS=actuals)
|
|
cpp_callback_name = '%s%s' % (idl_name, native_suffix)
|
|
|
|
self._cpp_resolver_emitter.Emit(
|
|
' if (argumentCount == $ARGC && name == "$NATIVE_BINDING") {\n'
|
|
' *autoSetupScope = $AUTO_SCOPE_SETUP;\n'
|
|
' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n'
|
|
' }\n',
|
|
ARGC=argument_count,
|
|
NATIVE_BINDING=native_binding,
|
|
INTERFACE_NAME=self._interface.id,
|
|
AUTO_SCOPE_SETUP='true' if auto_scope_setup else 'false',
|
|
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.add('"%s.h"' % namespace)
|
|
|
|
attribute_name = attr.ext_attrs['Reflect'] or attr.id.lower()
|
|
return 'WebCore::%s::%sAttr' % (namespace, attribute_name)
|
|
|
|
def _IsStatic(self, attribute_name):
|
|
return False
|
|
|
|
def _GenerateWebCoreFunctionExpression(self,
|
|
function_name,
|
|
idl_node,
|
|
cpp_callback_name=None):
|
|
return None
|
|
|
|
def _IsArgumentOptionalInWebCore(self, operation, argument):
|
|
if not IsOptional(argument):
|
|
return False
|
|
if 'Callback' in argument.ext_attrs:
|
|
return False
|
|
if operation.id in ['addEventListener', 'removeEventListener'
|
|
] and argument.id == 'useCapture':
|
|
return False
|
|
if 'DartForceOptional' in argument.ext_attrs:
|
|
return False
|
|
if argument.type.id == 'Dictionary':
|
|
return False
|
|
return True
|
|
|
|
def _GenerateCPPIncludes(self, includes):
|
|
return None
|
|
|
|
def _ToWebKitName(self, name):
|
|
name = name[0].lower() + name[1:]
|
|
name = re.sub(r'^(hTML|uRL|jS|xML|xSLT)', lambda s: s.group(1).lower(),
|
|
name)
|
|
return re.sub(r'^(create|exclusive)',
|
|
lambda s: 'is' + s.group(1).capitalize(), name)
|
|
|
|
|
|
class CPPLibraryEmitter():
|
|
|
|
def __init__(self, emitters, cpp_sources_dir):
|
|
self._emitters = emitters
|
|
self._cpp_sources_dir = cpp_sources_dir
|
|
self._library_headers = dict((lib, []) for lib in HTML_LIBRARY_NAMES)
|
|
self._sources_list = []
|
|
|
|
def CreateHeaderEmitter(self,
|
|
interface_name,
|
|
library_name,
|
|
is_callback=False):
|
|
path = os.path.join(self._cpp_sources_dir, 'Dart%s.h' % interface_name)
|
|
if not is_callback:
|
|
self._library_headers[library_name].append(path)
|
|
return self._emitters.FileEmitter(path)
|
|
|
|
def CreateSourceEmitter(self, interface_name):
|
|
path = os.path.join(self._cpp_sources_dir,
|
|
'Dart%s.cpp' % interface_name)
|
|
self._sources_list.append(path)
|
|
return self._emitters.FileEmitter(path)
|
|
|
|
def EmitDerivedSources(self, template, output_dir):
|
|
partitions = 20 # FIXME: this should be configurable.
|
|
sources_count = len(self._sources_list)
|
|
for i in range(0, partitions):
|
|
file_path = os.path.join(output_dir,
|
|
'DartDerivedSources%02i.cpp' % (i + 1))
|
|
includes_emitter = self._emitters.FileEmitter(file_path).Emit(
|
|
template)
|
|
for source_file in self._sources_list[i::partitions]:
|
|
path = os.path.relpath(source_file, output_dir)
|
|
includes_emitter.Emit('#include "$PATH"\n', PATH=path)
|
|
|
|
def EmitResolver(self, template, output_dir):
|
|
for library_name in self._library_headers.keys():
|
|
file_path = os.path.join(output_dir,
|
|
'%s_DartResolver.cpp' % library_name)
|
|
includes_emitter, body_emitter = self._emitters.FileEmitter(
|
|
file_path).Emit(
|
|
template, LIBRARY_NAME=library_name)
|
|
|
|
headers = self._library_headers[library_name]
|
|
for header_file in headers:
|
|
path = os.path.relpath(header_file, output_dir)
|
|
includes_emitter.Emit('#include "$PATH"\n', PATH=path)
|
|
body_emitter.Emit(
|
|
' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argumentCount, autoSetupScope))\n'
|
|
' return func;\n',
|
|
CLASS_NAME=os.path.splitext(os.path.basename(path))[0])
|
|
|
|
def EmitClassIdTable(self, database, output_dir, type_registry, renamer):
|
|
|
|
def HasConverters(interface):
|
|
is_node_test = lambda interface: interface.id == 'Node'
|
|
is_active_test = lambda interface: 'ActiveDOMObject' in interface.ext_attrs
|
|
is_event_target_test = lambda interface: 'EventTarget' in interface.ext_attrs
|
|
|
|
return (
|
|
any(map(is_node_test, database.Hierarchy(interface))) or
|
|
any(map(is_active_test, database.Hierarchy(interface))) or
|
|
any(map(is_event_target_test, database.Hierarchy(interface))))
|
|
|
|
path = os.path.join(output_dir, 'DartWebkitClassIds.h')
|
|
e = self._emitters.FileEmitter(path)
|
|
e.Emit(
|
|
'// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file\n'
|
|
)
|
|
e.Emit(
|
|
'// for details. All rights reserved. Use of this source code is governed by a\n'
|
|
)
|
|
e.Emit('// BSD-style license that can be found in the LICENSE file.\n')
|
|
e.Emit('// WARNING: Do not edit - generated code.\n')
|
|
e.Emit('// See dart/tools/dom/scripts/systemnative.py\n')
|
|
e.Emit('\n')
|
|
e.Emit('#ifndef DartWebkitClassIds_h\n')
|
|
e.Emit('#define DartWebkitClassIds_h\n')
|
|
e.Emit('\n')
|
|
e.Emit('namespace WebCore {\n')
|
|
e.Emit('\n')
|
|
e.Emit('enum {\n')
|
|
e.Emit(' _InvalidClassId = 0,\n')
|
|
e.Emit(' _HistoryCrossFrameClassId,\n')
|
|
e.Emit(' _LocationCrossFrameClassId,\n')
|
|
e.Emit(' _DOMWindowCrossFrameClassId,\n')
|
|
e.Emit(' _DateTimeClassId,\n')
|
|
e.Emit(' _JsObjectClassId,\n')
|
|
e.Emit(' _JsFunctionClassId,\n')
|
|
e.Emit(' _JsArrayClassId,\n')
|
|
e.Emit(
|
|
' // New types that are not auto-generated should be added here.\n'
|
|
)
|
|
e.Emit('\n')
|
|
for interface in database.GetInterfaces():
|
|
e.Emit(' %sClassId,\n' % interface.id)
|
|
e.Emit(' NumWebkitClassIds\n')
|
|
e.Emit('};\n')
|
|
e.Emit(
|
|
'class ActiveDOMObject;\n'
|
|
'class EventTarget;\n'
|
|
'class Node;\n'
|
|
'typedef ActiveDOMObject* (*ToActiveDOMObject)(void* value);\n'
|
|
'typedef EventTarget* (*ToEventTarget)(void* value);\n'
|
|
'typedef Node* (*ToNode)(void* value);\n'
|
|
'typedef struct {\n'
|
|
' const char* class_name;\n'
|
|
' int library_id;\n'
|
|
' int base_class_id;\n'
|
|
' ToActiveDOMObject toActiveDOMObject;\n'
|
|
' ToEventTarget toEventTarget;\n'
|
|
' ToNode toNode;\n'
|
|
'} DartWrapperTypeInfo;\n'
|
|
'typedef DartWrapperTypeInfo _DartWebkitClassInfo[NumWebkitClassIds];\n'
|
|
'\n'
|
|
'extern _DartWebkitClassInfo DartWebkitClassInfo;\n'
|
|
'\n'
|
|
'} // namespace WebCore\n'
|
|
'#endif // DartWebkitClassIds_h\n')
|
|
|
|
path = os.path.join(output_dir, 'DartWebkitClassIds.cpp')
|
|
e = self._emitters.FileEmitter(path)
|
|
e.Emit(
|
|
'// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file\n'
|
|
)
|
|
e.Emit(
|
|
'// for details. All rights reserved. Use of this source code is governed by a\n'
|
|
)
|
|
e.Emit('// BSD-style license that can be found in the LICENSE file.\n')
|
|
e.Emit('// WARNING: Do not edit - generated code.\n')
|
|
e.Emit('// See dart/tools/dom/scripts/systemnative.py\n')
|
|
e.Emit('\n')
|
|
e.Emit('#include "config.h"\n')
|
|
e.Emit('#include "DartWebkitClassIds.h"\n')
|
|
e.Emit('\n')
|
|
e.Emit('#include "bindings/dart/DartLibraryIds.h"\n')
|
|
for interface in database.GetInterfaces():
|
|
if HasConverters(interface):
|
|
e.Emit('#include "Dart%s.h"\n' % interface.id)
|
|
e.Emit('\n')
|
|
|
|
e.Emit('namespace WebCore {\n')
|
|
|
|
e.Emit('\n')
|
|
|
|
e.Emit(
|
|
'ActiveDOMObject* toNullActiveDOMObject(void* value) { return 0; }\n'
|
|
)
|
|
e.Emit('EventTarget* toNullEventTarget(void* value) { return 0; }\n')
|
|
e.Emit('Node* toNullNode(void* value) { return 0; }\n')
|
|
|
|
e.Emit("_DartWebkitClassInfo DartWebkitClassInfo = {\n")
|
|
|
|
e.Emit(' {\n'
|
|
' "_InvalidClassId", -1, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "_HistoryCrossFrame", DartHtmlLibraryId, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "_LocationCrossFrame", DartHtmlLibraryId, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "_DOMWindowCrossFrame", DartHtmlLibraryId, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "DateTime", DartCoreLibraryId, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "JsObject", DartJsLibraryId, -1,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "JsFunction", DartJsLibraryId, _JsObjectClassId,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(' {\n'
|
|
' "JsArray", DartJsLibraryId, _JsObjectClassId,\n'
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
' },\n')
|
|
e.Emit(
|
|
' // New types that are not auto-generated should be added here.\n'
|
|
)
|
|
for interface in database.GetInterfaces():
|
|
name = interface.id
|
|
type_info = type_registry.TypeInfo(name)
|
|
type_info.native_type().replace('<', '_').replace('>', '_')
|
|
e.Emit(' {\n')
|
|
e.Emit(' "%s", ' % type_info.implementation_name())
|
|
e.Emit('Dart%sLibraryId, ' % renamer.GetLibraryId(interface))
|
|
if interface.parents:
|
|
supertype = interface.parents[0].type.id
|
|
e.Emit('%sClassId,\n' % supertype)
|
|
else:
|
|
e.Emit(' -1,\n')
|
|
if HasConverters(interface):
|
|
e.Emit(
|
|
' Dart%s::toActiveDOMObject, Dart%s::toEventTarget,'
|
|
' Dart%s::toNode\n' % (name, name, name))
|
|
else:
|
|
e.Emit(
|
|
' toNullActiveDOMObject, toNullEventTarget, toNullNode\n'
|
|
)
|
|
e.Emit(' },\n')
|
|
|
|
e.Emit("};\n")
|
|
e.Emit('\n')
|
|
e.Emit('} // namespace WebCore\n')
|
|
|
|
|
|
def _IsOptionalStringArgumentInInitEventMethod(interface, operation, argument):
|
|
return (interface.id.endswith('Event') and
|
|
operation.id.startswith('init') and
|
|
argument.default_value == 'Undefined' and
|
|
argument.type.id == 'DOMString')
|
|
|
|
|
|
def _IsCustom(op_or_attr):
|
|
assert (isinstance(op_or_attr, IDLMember))
|
|
return 'Custom' in op_or_attr.ext_attrs or 'DartCustom' in op_or_attr.ext_attrs
|
|
|
|
|
|
def _IsCustomValue(op_or_attr, value):
|
|
if _IsCustom(op_or_attr):
|
|
return op_or_attr.ext_attrs.get('Custom') == value \
|
|
or op_or_attr.ext_attrs.get('DartCustom') == value
|
|
return False
|