Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Unified Diff: Source/WebCore/bindings/scripts/CodeGeneratorDart.pm

Issue 8802010: Dart bindings for WebKit (Closed) Base URL: http://svn.webkit.org/repository/webkit/trunk
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/WebCore/bindings/scripts/CodeGeneratorDart.pm
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorDart.pm b/Source/WebCore/bindings/scripts/CodeGeneratorDart.pm
new file mode 100644
index 0000000000000000000000000000000000000000..352084eb48a25b13f6c4aa418e0ba7f9bcef13fc
--- /dev/null
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorDart.pm
@@ -0,0 +1,1742 @@
+# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
+# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
+# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
+# Copyright (C) 2006 Apple Computer, Inc.
+# Copyright (C) 2007, 2008, 2009 Google Inc.
+# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
+# Copyright (C) Research In Motion Limited 2010. All rights reserved.
+# Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+package CodeGeneratorDart;
+
+use Class::Struct;
+
+my $outputDir = "";
+my $outputHeadersDir = "";
+
+my @headerContent = ();
+my %headerIncludes = ();
+
+my @allParents = ();
+
+my @customCallbackDeclarations = ();
+my @implContentHeader = ();
+my @implFixedHeader = ();
+my @implContent = ();
+my %implIncludes = ();
+my @dartNatives = ();
+
+my @dartInterfaceContent = ();
+my @dartImplContent = ();
+
+# Default .h template
+my $headerTemplate = << "EOF";
+/*
+ This file is part of the WebKit open source project.
+ This file has been generated by generate-bindings.pl. DO NOT MODIFY!
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+EOF
+
+struct(NativeBindingDescriptor => {
+ cppCallbackName => '$',
+ nativeId => '$',
+ argumentCount => '$',
+});
+
+struct(IDLTypeInfoStruct => {
+ additionalInterfaces => '@',
+ superClass => '$',
+ auxilaryMethods => '@',
+});
+
+# Default constructor
+sub new
+{
+ my $object = shift;
+
+ $codeGenerator = shift;
+ $outputDir = shift;
+ $outputHeadersDir = shift;
+
+ my $reference = { };
+ bless($reference, $object);
+ return $reference;
+}
+
+sub finish
+{
+ my ($object,) = @_;
+
+ # Commit changes!
+ $object->WriteData();
+}
+
+sub GenerateModule
+{
+ my ($object, $dataNode) = @_;
+}
+
+sub GenerateInterface
+{
+ my ($object, $dataNode, $defines) = @_;
+
+ # Add parent classes (for multiple-inheritance) fields as needed.
+ @allParents = ();
+ $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 0);
+ # Prepare internal structures.
+ $codeGenerator->LinkOverloadedFunctions($dataNode);
+
+ # Start actual generation
+ if ($dataNode->extendedAttributes->{Callback}) {
+ $object->GenerateCallbackDartInterface($dataNode);
+ $object->GenerateCallbackHeader($dataNode);
+ $object->GenerateCallbackImplementation($dataNode);
+ } else {
+ $object->GenerateSource($dataNode);
+ $object->GenerateHeader($dataNode);
+ }
+
+ my $name = $dataNode->name;
+
+ # Open files for writing
+ my $headerFileName = "$outputHeadersDir/Dart${name}.h";
+ my $implFileName = "$outputDir/Dart${name}.cpp";
+ my $dartInterfaceFileName = "$outputHeadersDir/${name}.dart";
+ my $dartImplFileName = "$outputHeadersDir/${name}Implementation.dart";
+
+ open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
+ open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
+ open($DART_INTERFACE, ">$dartInterfaceFileName") || die "Couldn't open file $dartInterfaceFileName";
+ open($DART_IMPL, ">$dartImplFileName") || die "Couldn't open file $dartImplFileName";
+}
+
+# If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if.
+# FIXME: common with CodeGeneratorV8
+sub GenerateConditionalStringForAttributes
+{
+ my ($attributes,) = @_;
+
+ my $conditional = $attributes->{Conditional};
+ if ($conditional) {
+ if ($conditional =~ /&/) {
+ return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
+ } elsif ($conditional =~ /\|/) {
+ return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
+ } else {
+ return "ENABLE(" . $conditional . ")";
+ }
+ } else {
+ return "";
+ }
+}
+
+sub GenerateConditionalString
+{
+ my ($node,) = @_;
+ return GenerateConditionalStringForAttributes($node->extendedAttributes);
+}
+
+sub GenerateCustomCallbackDeclaration
+{
+ my ($callbackName) = @_;
+ return "void $callbackName(Dart_NativeArguments);";
+}
+
+sub ClassName
+{
+ my ($interfaceName,) = @_;
+ return "Dart$interfaceName";
+}
+
+sub HasOverloads
+{
+ my ($function,) = @_;
+ return 1 if @{$function->{overloads}} > 1;
+}
+
+sub MaxOverloadParameterCount
+{
+ my ($function,) = @_;
+
+ my $maxParameterCount = 0;
+ foreach my $overload (@{$function->{overloads}}) {
+ my $parameterCount = @{$overload->parameters};
+ $maxParameterCount = $maxParameterCount > $parameterCount ? $maxParameterCount : $parameterCount;
+ }
+ return $maxParameterCount;
+}
+
+sub HasOptionalParameters
+{
+ my ($function) = @_;
+
+ # FIXME: useCapture was marked as optional upstream, however native
+ # implementation still requires all three parameters. JavaScript bindings
+ # have custom generation for addEventListener and removeEventListener.
+ return 0 if $function->signature->name eq "addEventListener" || $function->signature->name eq "removeEventListener";
+
+ foreach my $parameter (@{$function->parameters}) {
+ return 1 if IsParameterOptionalInWebKit($parameter);
+ }
+}
+
+sub HasCustomConstructor
+{
+ my ($dataNode) = @_;
+
+ # FIXME: switch to using CanBeConstructed attribute.
+ return 1 if $dataNode->name eq "FileReader";
+ return 1 if $dataNode->name eq "XMLHttpRequest";
+ return 1 if $dataNode->name eq "WebKitCSSMatrix";
+ return 1 if $dataNode->name eq "WebKitPoint";
+
+ return 0;
+}
+
+sub IsParameterOptionalInWebKit
+{
+ my ($parameter) = @_;
+
+ # Optional callbacks are not optional parameters in native implementations, they always have a default value (0).
+ my $optional = $parameter->extendedAttributes->{Optional};
+ return $optional && $optional ne "CallWithDefaultValue" && !$parameter->extendedAttributes->{Callback};
+}
+
+my %renames = (
+ "IDBCursor" => {
+ "continue" => "continueFunction",
+ },
+ "IDBIndex" => {
+ "get" => "getObject",
+ },
+ "IDBObjectStore" => {
+ "get" => "getObject",
+ },
+ "Int8Array" => {
+ "set" => "setElements",
+ },
+ "Int16Array" => {
+ "set" => "setElements",
+ },
+ "Int32Array" => {
+ "set" => "setElements",
+ },
+ "Uint8Array" => {
+ "set" => "setElements",
+ },
+ "Uint16Array" => {
+ "set" => "setElements",
+ },
+ "Uint32Array" => {
+ "set" => "setElements",
+ },
+ "Float32Array" => {
+ "set" => "setElements",
+ },
+ "Float64Array" => {
+ "set" => "setElements",
+ },
+ "SVGFEMorphologyElement" => {
+ "operator" => "operatorValue",
+ },
+ "SVGFECompositeElement" => {
+ "operator" => "operatorValue",
+ },
+ "Console" => {
+ "assert" => "assert_",
+ },
+);
+
+sub DartName
+{
+ my ($interfaceName, $memberName) = @_;
+ return $memberName unless $renames{$interfaceName};
+ my $class = $renames{$interfaceName};
+ return $memberName unless $class->{$memberName};
+ return $class->{$memberName};
+}
+
+# FIXME: eventually those should go away.
+my %classesWithUnsupportedCustomGetters = (
+ "Clipboard" => 1,
+ "Console" => 1,
+ "Coordinates" => 1,
+ "DeviceMotionEvent" => 1,
+ "DeviceOrientationEvent" => 1,
+ "FileReader" => 1,
+ "JavaScriptCallFrame" => 1,
+ "HTMLInputElement" => 1,
+ "HTMLOptionsCollection" => 1,
+ "HTMLOutputElement" => 1,
+ "ScriptProfileNode" => 1,
+ "WebKitAnimation" => 1,
+);
+
+sub IgnoredAttribute
+{
+ my ($interfaceName, $attribute) = @_;
+
+ # FIXME: reconsider if need to be supported in Dart bindings at all.
+ return 1 if $attribute->signature->type =~ /Constructor$/;
+
+ # Attribute event listeners are not supported in Dart.
+ return 1 if $attribute->signature->type eq "EventListener";
+
+ # The only usage is HTMLIFrameElement.contentDocument.
+ return 1 if $attribute->signature->extendedAttributes->{CheckFrameSecurity};
+
+ return 1 if HasCustomGetter($attribute) && exists $classesWithUnsupportedCustomGetters{$interfaceName};
+
+ return 0;
+}
+
+
+sub HasSetter
+{
+ my ($attribute,) = @_;
+
+ return 0 if $attribute->type =~ /^readonly/;
+ # FIXME: Replaceable apparently means that the value can be overwritten by JS and
+ # hence there is no correspondence to this in Dart.
+ return 0 if $attribute->signature->extendedAttributes->{"Replaceable"};
+ return 1;
+}
+
+
+sub IgnoredCallback
+{
+ my ($interfaceName, $function) = @_;
+
+ # FIXME: WebGLContextEvent.initEvent overloads initEvent in base interface Event and adds
+ # another argument.
+ # In the current architecture it's difficult to solve as IDL files are processed one by one.
+ # As this is the only case, I'd suggest to put Custom attribute on WebGLContextEvent.initEvent.
+ return 1 if $interfaceName eq "WebGLContextEvent" && $function->signature->name eq "initEvent";
+
+ # FIXME: implement callbacks with ScriptState.
+ my $callWith = $function->signature->extendedAttributes->{CallWith};
+ return 1 if $callWith and $callWith eq "ScriptState";
+
+ return 0;
+}
+
+# FIXME: Consider adding this to IDL as an attribute.
+my %idlTypeToW3C = (
+ "DOMWindow" => "Window",
+ "DOMCoreException" => "DOMException"
+);
+
+sub HasW3CName
+{
+ my ($idlType,) = @_;
+ return 1 if exists $idlTypeToW3C{$idlType};
+ return 0;
+}
+
+sub IDLTypeToW3C
+{
+ my ($idlType,) = @_;
+ return $idlTypeToW3C{$idlType} if exists $idlTypeToW3C{$idlType};
+ return $idlType;
+}
+
+my %idlTypeToDart = (
+ "any" => "Object",
+ "boolean" => "bool",
+ "Array" => "List",
+ "DOMObject" => "Object",
+ "DOMString" => "String",
+ "DOMString[]" => "DOMStringList",
+ "DOMTimeStamp" => "int",
+ "ObjectArray" => "List",
+ "SerializedScriptValue" => "Object",
+ "Date" => "Date",
+ "float" => "num",
+ "short" => "int",
+ "long" => "int",
+ "long long" => "int",
+ "unsigned int" => "int",
+ "unsigned short" => "int",
+ "unsigned long" => "int",
+ "unsigned long long" => "int",
+ "string" => "String",
+);
+
+my %primitiveDartTypes = (
+ "int" => 1,
+ "String" => 1,
+ "Object" => 1,
+ "Date" => 1,
+ "SerializedScriptValue" => 1,
+);
+
+sub IDLTypeToDart
+{
+ my ($idlType,) = @_;
+ return $idlTypeToDart{$idlType} if exists $idlTypeToDart{$idlType};
+ return $idlType;
+}
+
+# FIXME: pretty much %non_wrapper_types in CodeGeneratorV8.
+my %nonWrapperTypes = (
+ "CompareHow" => 1,
+ "EventListener" => 1,
+ "EventTarget" => 1,
+ "MediaQueryListListener" => 1,
+ "OptionsObject" => 1,
+ "VoidCallback" => 1,
+);
+
+sub IsIDLTypeWithDartBindings
+{
+ my ($idlType,) = @_;
+
+ return 0 if exists $idlTypeToDart{$idlType};
+ return 0 if exists $primitiveDartTypes{$idlType};
+ return 0 if !IsRefPtrType(IDLTypeToDart($idlType));
+ return 0 if exists $nonWrapperTypes{$idlType};
+
+ return 1;
+}
+
+sub ParameterAdapterType
+{
+ my ($idlType,) = @_;
+
+ my $webkitParameterType = IDLTypeToWebkit($idlType);
+
+ my $suffix = "";
+ if (IsIDLTypeWithDartBindings($idlType)) {
+ my $bindingsClass = ClassName($idlType);
+ $implIncludes{"$bindingsClass.h"} = 1;
+ $suffix = ", $bindingsClass";
+ }
+
+ return "ParameterAdapter< $webkitParameterType$suffix >";
+}
+
+# FIXME: common with CodeGeneratorV8
+sub GetNativeTypeForConversions
+{
+ my ($type,) = @_;
+ $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type);
+ return $type;
+}
+
+
+sub AddHeaderForIDLType
+{
+ my ($idlType, $includes) = @_;
+
+ $idlType =~ s/Abs|Rel// if $idlType =~ /SVGPathSeg/;
+
+ return if $codeGenerator->IsPrimitiveType($idlType);
+
+ return if exists $primitiveDartTypes{IDLTypeToDart($idlType)};
+
+ return if $codeGenerator->AvoidInclusionOfType($idlType);
+
+ return if $idlType eq "CompareHow";
+
+ $includes->{"$idlType.h"} = 1;
+ $includes->{"SVGPropertyTearOff.h"} = 1 if $codeGenerator->IsSVGTypeNeedingTearOff($idlType);
+}
+
+# FIXME: common with CodeGeneratorV8
+sub AddHeaderClassIncludes
+{
+ my ($idlType,) = @_;
+
+ AddHeaderForIDLType($idlType, \%headerIncludes);
+
+ $headerIncludes{"DartDOMWrapper.h"} = 1;
+}
+
+sub GenerateIncludes
+{
+ return map { "#include " . (/wtf|dart_api\.h/ ? "<$_>" : "\"$_\"") . "\n"; } sort(@_);
+}
+
+my %withCustomConverters = (
+ "DOMWindow" => 1,
+ "Element" => 1,
+ "HTMLElement" => 1,
+ "SVGElement" => 1,
+);
+
+sub RequiresCustomToDartConverter
+{
+ my ($dataNode,) = @_;
+
+ return 1 if $dataNode->extendedAttributes->{CustomToJS};
+ return 1 if $dataNode->extendedAttributes->{PureInterface};
+ return exists $withCustomConverters{$dataNode->name};
+}
+
+sub GenerateHeader
+{
+ my ($object, $dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $className = ClassName($interfaceName);
+ my $webkitClassName = GetNativeTypeForConversions($interfaceName);
+
+ my $conditionalString = GenerateConditionalString($dataNode);
+
+ my $toDartValue = "";
+ if (!RequiresCustomToDartConverter($dataNode)) {
+ $toDartValue = <<END;
+inline Dart_Handle toDartValue($webkitClassName* value)
+{
+ return DartDOMWrapper::toDart<$className>(value);
+}
+END
+ } else {
+ $toDartValue = <<END;
+Dart_Handle toDartValue($webkitClassName*);
+END
+ }
+
+ my $customCallbackDeclarations = join("\n\n", @customCallbackDeclarations);
+
+ push(@headerContent, $headerTemplate);
+
+ push(@headerContent, "\n#if ${conditionalString}\n") if $conditionalString;
+ push(@headerContent, <<END);
+
+#ifndef ${className}_h
+#define ${className}_h
+
+END
+
+ AddHeaderClassIncludes($interfaceName);
+
+ $headerIncludes{"dart_api.h"} = 1;
+ push(@headerContent, GenerateIncludes(keys(%headerIncludes)));
+
+ push(@headerContent, <<END);
+
+namespace WebCore {
+
+struct $className {
+ static const char* const dartImplementationClassName;
+ typedef $webkitClassName NativeType;
+
+ static PassRefPtr<NativeType> toNative(Dart_Handle handle, Dart_Handle& exception)
+ {
+ return DartDOMWrapper::unwrapDartWrapper<$className>(handle, exception);
+ }
+};
+
+$toDartValue
+namespace Dart${interfaceName}Internal {
+
+$customCallbackDeclarations
+
+}
+
+}
+
+#endif // ${className}_h
+END
+
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub HasCustomGetter
+{
+ my ($attribute,) = @_;
+ my $extendedAttributes = $attribute->signature->extendedAttributes;
+ return $extendedAttributes->{"CustomGetter"} || $extendedAttributes->{"Custom"};
+}
+
+sub HasCustomSetter
+{
+ my ($attribute,) = @_;
+ my $extendedAttributes = $attribute->signature->extendedAttributes;
+ return $extendedAttributes->{"CustomSetter"} || $extendedAttributes->{"Custom"} || $extendedAttributes->{"V8CustomSetter"};
+}
+
+sub GenerateUnimplementedNative
+{
+ my ($name,) = @_;
+
+ push(@implContent, <<END);
+static void $name(Dart_NativeArguments args)
+{
+ DART_UNIMPLEMENTED();
+}
+
+END
+}
+
+sub WithTearOffNotList
+{
+ my ($interfaceName) = @_;
+
+ return ($codeGenerator->IsSVGTypeNeedingTearOff($interfaceName) and (not ($interfaceName =~ /List$/)));
+}
+
+sub PrepareInvocation
+{
+ my ($receiver, $interfaceName, $invocationPrefix, $invocationParameters) = @_;
+
+ my $invocationPostfix;
+ $receiver .= "->";
+ if ($interfaceName eq "SVGNumber") {
+ $receiver .= "propertyReference()";
+ if ($invocationPrefix =~ /^setValue/) {
+ $invocationPrefix = " = ";
+ } else {
+ $invocationPrefix = "";
+ }
+ $invocationPostfix = "";
+ } else {
+ $receiver .= "propertyReference()." if WithTearOffNotList($interfaceName);
+ $invocationPostfix = ")";
+ }
+ return "$receiver$invocationPrefix$invocationParameters$invocationPostfix";
+}
+
+my %svgPrimitiveTypes = (
+ "SVGAngle" => 1,
+ "SVGLength" => 1,
+ "SVGMatrix" => 1,
+ "SVGNumber" => 1,
+ "SVGPoint" => 1,
+ "SVGRect" => 1,
+ "SVGTransform" => 1);
+
+sub ProcessInvocationResult
+{
+ my ($invocation, $interfaceName, $returnType) = @_;
+ my $svgNativeReturnType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
+
+ return $invocation if (not $svgNativeReturnType);
+
+ return "static_cast<${svgNativeReturnType}*>(${invocation})" if ($interfaceName =~ /^SVGAnimated/);
+
+ return "${svgNativeReturnType}::create(receiver, ${invocation})" if ($returnType eq "SVGStringList");
+
+ return "static_cast<${svgNativeReturnType}*>(${invocation}.get())" if ($interfaceName =~ /List$/);
+
+ if (exists $svgPrimitiveTypes{$returnType}) {
+ return "${svgNativeReturnType}::create(${invocation})";
+ } else {
+ return "static_cast<${svgNativeReturnType}*>(${invocation})";
+ }
+}
+
+sub GenerateGenericBindingsFunction
+{
+ my ($name, $interfaceName, $invocationPrefix, $parameters, $returnType, $raisesExceptions, $attributes, $isSetter) = @_;
+
+ my $webkitClassName = GetNativeTypeForConversions($interfaceName);
+
+ my $exceptionManagementPrologue = "";
+ my $exceptionManagementEpilogue = "";
+ if (@{$parameters} || $raisesExceptions) {
+ $exceptionManagementPrologue = <<END;
+ Dart_Handle exception;
+END
+ $exceptionManagementEpilogue = <<END;
+
+fail:
+ Dart_ThrowException(exception);
+ ASSERT_NOT_REACHED();
+END
+ }
+
+ my @defineInvocationParameters = ();
+ my @invocationParameters = ();
+
+ my $callWith = $attributes->{CallWith};
+ if ($callWith) {
+ # Generate code for "CallWith" parameter.
+ if ($callWith eq "ScriptExecutionContext") {
+ push(@defineInvocationParameters, <<END);
+ ScriptExecutionContext* context = DartUtilities::scriptExecutionContext();
+ if (!context)
+ return;
+END
+ push(@invocationParameters, "context");
+ }
+ }
+
+ # Generate code for parameters conversion.
+ my $parameterCount = @$parameters;
+ foreach my $parameterIndex (0..$parameterCount - 1) {
+ my $parameter = @$parameters[$parameterIndex];
+ my $parameterType = $parameter->type;
+ $parameterType = "DOMStringList" if $parameterType eq "DOMString[]";
+ AddHeaderForIDLType($parameterType, \%implIncludes);
+ my $name = $parameter->name;
+ my $parameterAdapterType = ParameterAdapterType($parameterType);
+ my $dartArgumentIndex = $parameterIndex + 1; # 0 is for the receiver.
+ my @adapterParameters = ("Dart_GetNativeArgument(args, $dartArgumentIndex)");
+ my $adapterParameters = join(", ", @adapterParameters);
+ push(@defineInvocationParameters, <<END);
+ const $parameterAdapterType $name($adapterParameters);
+ if (!$name.conversionSuccessful()) {
+ exception = $name.exception();
+ goto fail;
+ }
+END
+ }
+ @invocationParameters = (@invocationParameters, map { $_->name; } @{$parameters});
+
+ if ($attributes->{CustomArgumentHandling}) {
+ $implIncludes{"ScriptArguments.h"} = 1;
+ $implIncludes{"ScriptCallStack.h"} = 1;
+ my $customArgument = $parameterCount + 1;
+ push(@defineInvocationParameters, <<END);
+ Dart_Handle customArgument = Dart_GetNativeArgument(args, $customArgument);
+ RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument));
+ size_t maxStackSize = receiver->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1;
+ RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::createScriptCallStack(maxStackSize));
+ if (!scriptCallStack->size())
+ return;
+END
+ push(@invocationParameters, "scriptArguments", "scriptCallStack");
+ }
+
+ if ($attributes->{NeedsUserGestureCheck}) {
+ push(@invocationParameters, "DartUtilities::processingUserGesture()");
+ }
+
+ if ($raisesExceptions) {
+ push(@invocationParameters, "ec");
+ }
+
+ my $defineInvocationParameters = join "", @defineInvocationParameters;
+ my $invocationParameters = join ", ", @invocationParameters;
+ my $invocation = PrepareInvocation("receiver", $interfaceName, $invocationPrefix, $invocationParameters);
+ # Generate code for setting return value.
+ my $invocationAndReturn = $invocation;
+ if ($returnType ne "void") {
+ $invocation = ProcessInvocationResult($invocation, $interfaceName, $returnType);
+ my $dartType = IDLTypeToDart($returnType);
+ if (!$codeGenerator->IsPrimitiveType($returnType) && !exists $primitiveDartTypes{$dartType}) {
+ $implIncludes{"@{[ClassName($dartType)]}.h"} = 1;
+ }
+ $invocation = "static_pointer_cast<SVGAnimatedEnumeration>($invocation)" if $returnType eq "SVGAnimatedEnumeration";
+ # FIXME: this is too simplistic for long return types, reconsider.
+ $invocation = "static_cast<int64_t>($invocation)" if $dartType eq "int";
+ # There is GC3Dboolean which is not a bool, but unsigned char for OpenGL compatibility.
+ $invocation = "static_cast<bool>($invocation)" if $dartType eq "bool";
+ $conversion = ($codeGenerator->IsStringType($returnType) and defined
+ $attributes->{ConvertNullStringTo}) ? ", ConvertDefaultToNull" : "";
+ $invocationAndReturn = "DartDOMWrapper::returnValue(args, $invocation$conversion)";
+ }
+
+ my $webkitInvocation = <<END;
+ $invocationAndReturn;
+END
+ if ($raisesExceptions) {
+ $implIncludes{"ExceptionCode.h"} = 1;
+ $webkitInvocation = <<END;
+ ExceptionCode ec = 0;
+ $invocationAndReturn;
+ if (UNLIKELY(ec)) {
+ exception = DartDOMWrapper::exceptionCodeToDartException(ec);
+ goto fail;
+ }
+END
+ }
+
+ my $conditionalString = GenerateConditionalStringForAttributes($attributes);
+ if ($conditionalString) {
+ push(@implContent, <<END);
+#if $conditionalString
+END
+ }
+
+ push(@implContent, <<END);
+static void $name(Dart_NativeArguments args)
+{
+ DartApiScope dartApiScope;
+$exceptionManagementPrologue {
+ $webkitClassName* receiver = DartDOMWrapper::receiver< $webkitClassName >(args);
+$defineInvocationParameters
+$webkitInvocation return;
+ }
+$exceptionManagementEpilogue}
+
+END
+
+ if ($conditionalString) {
+ push(@implContent, <<END);
+#else
+static void $name(Dart_NativeArguments args)
+{
+ DartApiScope dartApiScope;
+ Dart_ThrowException(DartUtilities::conditionalFunctionalityException());
+}
+#endif
+
+END
+ }
+}
+
+# FIXME: copied from CodeGeneratorV8.pm
+sub IsRefPtrType
+{
+ my ($type,) = @_;
+
+ return 0 if $type eq "boolean";
+ return 0 if $type eq "float";
+ return 0 if $type eq "int";
+ return 0 if $type eq "Date";
+ return 0 if $type eq "DOMString";
+ return 0 if $type eq "double";
+ return 0 if $type eq "short";
+ return 0 if $type eq "long";
+ return 0 if $type eq "unsigned";
+ return 0 if $type eq "unsigned long";
+ return 0 if $type eq "unsigned short";
+
+ return 1;
+}
+
+# FIXME: partially copied from GetNativeType of CodeGeneratorV8.pm
+sub IDLTypeToWebkit
+{
+ my ($type, $isParameter) = @_;
+
+ my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
+ if ($svgNativeType) {
+ if ($svgNativeType =~ /List$/) {
+ return "${svgNativeType}*";
+ } else {
+ return "RefPtr<${svgNativeType} >";
+ }
+ }
+
+ if ($type eq "float" or $type eq "double") {
+ return $type;
+ }
+
+ return ($isParameter ? "const String&" : "String") if ($type eq "DOMString" or $type eq "DOMUserData");
+ return "int" if $type eq "int";
+ return "int" if $type eq "short" or $type eq "unsigned short";
+ return "unsigned" if $type eq "unsigned long";
+ return "int" if $type eq "long";
+ return "long long" if $type eq "long long";
+ return "unsigned long long" if $type eq "unsigned long long";
+ return "bool" if $type eq "boolean";
+ return "Range::CompareHow" if $type eq "CompareHow";
+ return "DOMTimeStamp" if $type eq "DOMTimeStamp";
+ return "unsigned" if $type eq "unsigned int";
+ # FIXME: EventTarget are evils!
+ # return "Node*" if $type eq "EventTarget" and $isParameter;
+ return "double" if $type eq "Date";
+ return "ScriptValue" if $type eq "DOMObject";
+ return "OptionsObject" if $type eq "OptionsObject";
+
+ # temporary hack
+ return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
+
+ return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
+
+ return "RefPtr<IDBKey>" if $type eq "IDBKey";
+
+ # necessary as resolvers could be constructed on fly.
+ return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";
+
+ return ($isParameter ? "${type}*" : "RefPtr<${type}>") if IsRefPtrType($type);
+
+ return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
+
+ return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";
+
+ # Default, assume native type is a pointer with same type name as idl type
+ return "${type}*";
+}
+
+sub GenerateResolver
+{
+ my ($interfaceName,) = @_;
+
+ push(@implContent, <<END);
+
+static Dart_NativeFunction resolver(Dart_Handle name, int argumentCount)
+{
+ String str = DartUtilities::dartStringToString(name);
+
+END
+
+ foreach my $nativeDescriptor (@dartNatives) {
+ my $cppCallbackName = $nativeDescriptor->cppCallbackName;
+ my $nativeId = $nativeDescriptor->nativeId;
+ my $argumentCount = $nativeDescriptor->argumentCount;
+ push(@implContent, <<END);
+ if ($argumentCount == argumentCount && str == "$nativeId")
+ return $cppCallbackName;
+END
+ }
+
+ push(@implContent, <<END);
+ return 0;
+}
+
+END
+}
+
+sub GenerateScriptConstant
+{
+ push(@implContent, <<END);
+
+static const char* script =
+END
+
+ foreach my $element (@dartInterfaceContent, @dartImplContent) {
+ foreach my $line (split("\n", $element)) {
+ $line =~ s/\"/\\\"/g;
+ push(@implContent, " \"$line\\n\"\n")
+ }
+ }
+
+ push(@implContent, <<END);
+;
+END
+}
+
+sub GenerateCallbackScriptConstant
+{
+ push(@implContent, <<END);
+
+static const char* script =
+END
+
+ foreach my $element (@dartInterfaceContent) {
+ foreach my $line (split("\n", $element)) {
+ $line =~ s/\"/\\\"/g;
+ push(@implContent, " \"$line\\n\"\n")
+ }
+ }
+
+ push(@implContent, <<END);
+;
+END
+}
+
+sub GenerateDartImplementationClassname
+{
+ my ($interfaceName,) = @_;
+
+ my $className = ClassName($interfaceName);
+
+ push(@implContent, <<END);
+
+const char* const ${className}::dartImplementationClassName = "${interfaceName}Implementation";
+END
+}
+
+sub GenerateRegistryEntry
+{
+ my ($interfaceName,) = @_;
+
+ push(@implContent, <<END);
+
+REGISTER_API($interfaceName)
+
+END
+}
+
+sub GenerateImplementationPrologue
+{
+ my ($dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $className = ClassName($interfaceName);
+ my $internalNamespaceName = "Dart${interfaceName}Internal";
+
+ my $conditionalString = GenerateConditionalString($dataNode);
+
+ push(@implContentHeader, $headerTemplate);
+
+ push(@implContentHeader, <<END);
+
+#include "config.h"
+#include "$className.h"
+
+END
+
+ push(@implContentHeader, "#if $conditionalString\n\n") if $conditionalString;
+
+ $implIncludes{"DartBindingsCommonIncludes.h"} = 1;
+
+ push(@implContent, <<END);
+namespace WebCore {
+
+namespace $internalNamespaceName {
+END
+}
+
+sub GenerateImplementationEpilogue
+{
+ my ($dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $className = ClassName($interfaceName);
+ my $internalNamespaceName = "Dart${interfaceName}Internal";
+
+ my $conditionalString = GenerateConditionalString($dataNode);
+
+ push(@implContent, "\n// Class info.\n");
+ GenerateResolver($interfaceName);
+ GenerateScriptConstant();
+
+ push(@implContent, "}\n");
+
+ GenerateDartImplementationClassname($interfaceName);
+ GenerateRegistryEntry($interfaceName);
+
+ push(@implContent, <<END);
+}
+END
+
+ push(@implContent, "\n#endif // $conditionalString\n") if $conditionalString;
+
+ # We've already added the header for this file in implFixedHeader, so remove
+ # it from implIncludes to ensure we don't #include it twice.
+ delete $implIncludes{"$className.h"};
+}
+
+sub GenerateCallbackDartInterface
+{
+ my ($object, $dataNode) = @_;
+ my $function = $dataNode->functions->[0];
+ my $functionDecl = DartInterfaceMethodDeclaration($interfaceName, $function, $dataNode->name);
+ push(@dartInterfaceContent, $headerTemplate);
+ push(@dartInterfaceContent, <<END);
+typedef $functionDecl;
+END
+}
+
+sub FormatCallbackArgument
+{
+ my ($argument,) = @_;
+ my $webkitType = IDLTypeToWebkit($argument->type, 1);
+ my $name = $argument->name;
+ return "$webkitType $name";
+}
+
+sub GenerateCallbackHeader
+{
+ my ($object, $dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $className = ClassName($interfaceName);
+ my $webkitClassName = GetNativeTypeForConversions($interfaceName);
+
+ my $conditionalString = GenerateConditionalString($dataNode);
+
+ push(@headerContent, $headerTemplate);
+
+ push(@headerContent, "\n#if ${conditionalString}\n") if $conditionalString;
+ push(@headerContent, <<END);
+
+#ifndef ${className}_h
+#define ${className}_h
+
+END
+
+ AddHeaderClassIncludes($interfaceName);
+
+ $headerIncludes{"ActiveDOMCallback.h"} = 1;
+ $headerIncludes{"DartCallback.h"} = 1;
+ push(@headerContent, GenerateIncludes(keys(%headerIncludes)));
+
+ my @handleEventMethods = ();
+ foreach my $function (@{$dataNode->functions}) {
+ die "Expect only handleEvent methods" if ($function->signature->type ne "boolean") || ($function->signature->name ne "handleEvent");
+
+ my $arguments = join ", ", map { FormatCallbackArgument($_); } @{$function->parameters};
+ push(@handleEventMethods, " virtual bool handleEvent($arguments);");
+ }
+ my $methods = join "\n", @handleEventMethods;
+
+ push(@headerContent, <<END);
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class $className : public $interfaceName, public ActiveDOMCallback {
+public:
+ typedef $interfaceName NativeType;
+
+ static PassRefPtr<NativeType> toNative(Dart_Handle object, Dart_Handle& exception)
+ {
+ return adoptRef(new $className(object, exception, DartUtilities::scriptExecutionContext()));
+ }
+
+$methods
+
+private:
+ $className(Dart_Handle object, Dart_Handle& exception, ScriptExecutionContext* context)
+ : ActiveDOMCallback(context)
+ , m_callback(object, exception)
+ {
+ }
+
+ DartCallback m_callback;
+};
+
+}
+
+#endif // ${className}_h
+END
+
+ push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
+}
+
+sub GenerateCallbackImplementation
+{
+ my ($object, $dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $className = ClassName($interfaceName);
+ my $internalNamespaceName = "Dart${interfaceName}Internal";
+
+ my $conditionalString = GenerateConditionalString($dataNode);
+
+ push(@implContentHeader, $headerTemplate);
+
+ $implIncludes{"DartBindingsCommonIncludes.h"} = 1;
+
+ push(@implContentHeader, <<END);
+
+#include "config.h"
+#include "$className.h"
+
+END
+
+ push(@implContentHeader, "#if $conditionalString\n\n") if $conditionalString;
+
+ my @handleEventMethods = ();
+ foreach my $function (@{$dataNode->functions}) {
+ die "Expect only handleEvent methods" if ($function->signature->type ne "boolean") || ($function->signature->name ne "handleEvent");
+
+ my $arguments = join ", ", map { FormatCallbackArgument($_); } @{$function->parameters};
+ my $parameters = join ", ", map { $_->name; } @{$function->parameters};
+ push(@handleEventMethods, <<END);
+bool ${className}::handleEvent($arguments)
+{
+ return m_callback.handleEvent($parameters);
+}
+END
+ }
+ my $methods = join "\n", @handleEventMethods;
+
+ push(@implContent, <<END);
+namespace WebCore {
+
+$methods
+
+namespace $internalNamespaceName {
+END
+
+ GenerateCallbackScriptConstant();
+ push(@implContent, "}\n");
+
+ push(@implContent, <<END);
+
+REGISTER_CALLBACK($interfaceName)
+
+}
+END
+
+ push(@implContent, "\n#endif // $conditionalString\n") if $conditionalString;
+
+ # We've already added the header for this file in implFixedHeader, so remove
+ # it from implIncludes to ensure we don't #include it twice.
+ delete $implIncludes{"$className.h"};
+}
+
+sub DartMethodDeclaration
+{
+ my ($functionName, $parameters, $returnType) = @_;
+
+ $returnType = IDLTypeToDart($codeGenerator->StripModule($returnType));
+ return "$returnType $functionName($parameters)";
+}
+
+sub DartInterfaceMethodDeclaration
+{
+ my ($interfaceName, $function, $name) = @_;
+
+ my $parameters;
+ if (HasOverloads($function)) {
+ my $maxParameterCount = MaxOverloadParameterCount($function);
+ $parameters = DartAnonymousNamedOptionalParameters($maxParameterCount);
+ } else {
+ $parameters = DartParameters($function, $function->parameters, 1);
+ }
+ return DartMethodDeclaration($name || DartName($interfaceName, $function->signature->name), $parameters, $function->signature->type);
+}
+
+sub DartParameters
+{
+ my ($function, $parameters, $useDefaultValues) = @_;
+
+ my @mandatoryParameters = ();
+ my @optionalParameters = ();
+ foreach my $parameter (@{$parameters}) {
+ # FIXME: parameter modifiers.
+ my $type = IDLTypeToDart($parameter->type);
+ my $name = $parameter->name;
+ if ($useDefaultValues && IsParameterOptionalInWebKit($parameter)) {
+ push(@optionalParameters, "$type ${name}");
+ } else {
+ push(@mandatoryParameters, "$type ${name}");
+ }
+ }
+ if ($function->signature->extendedAttributes->{CustomArgumentHandling}) {
+ die "Optional parameters in function with custom argument handling. " if @optionalParameters;
+ push(@mandatoryParameters, "argument");
+ }
+ my $dartParameters = join(", ", @mandatoryParameters);
+ if (@optionalParameters) {
+ $dartParameters .= ", " if $dartParameters;
+ $dartParameters .= "[" . join(", ", @optionalParameters) . "]";
+ }
+ return $dartParameters;
+}
+
+sub DartParameterCount
+{
+ my ($function, $parameters) = @_;
+
+ my $parameterCount = @{$parameters};
+ $parameterCount += 1 if $function->signature->extendedAttributes->{CustomArgumentHandling};
+ return $parameterCount;
+}
+
+sub DartAnonymousArguments
+{
+ my ($parameterCount) = @_;
+ return "" unless $parameterCount;
+ return join(", ", map { "_arg$_" } (0..$parameterCount - 1));
+}
+
+sub DartAnonymousNamedOptionalParameters
+{
+ my ($parameterCount) = @_;
+ return "" unless $parameterCount;
+ return "[" . DartAnonymousArguments($parameterCount) . "]";
+}
+
+sub CreateFunctionNativeDescriptor
+{
+ my ($interfaceName, $functionName, $argumentCount) = @_;
+ my $descriptor = NativeBindingDescriptor->new(
+ cppCallbackName => "${functionName}Callback",
+ nativeId => "${interfaceName}_${functionName}_Callback",
+ argumentCount => $argumentCount);
+ push(@dartNatives, $descriptor);
+ return $descriptor;
+}
+
+sub CreateGetterNativeDescriptor
+{
+ my ($interfaceName, $attributeName) = @_;
+ my $descriptor = NativeBindingDescriptor->new(
+ cppCallbackName => "${attributeName}Getter",
+ nativeId => "${interfaceName}_${attributeName}_Getter",
+ argumentCount => 1);
+ push(@dartNatives, $descriptor);
+ return $descriptor;
+}
+
+sub CreateSetterNativeDescriptor
+{
+ my ($interfaceName, $attributeName) = @_;
+ my $descriptor = NativeBindingDescriptor->new(
+ cppCallbackName => "${attributeName}Setter",
+ nativeId => "${interfaceName}_${attributeName}_Setter",
+ argumentCount => 2);
+ push(@dartNatives, $descriptor);
+ return $descriptor;
+}
+
+sub GenerateDartOptionalArgumentsResolver
+{
+ my ($interfaceName, $function) = @_;
+
+ my $interfaceMethodDeclaration = DartInterfaceMethodDeclaration($interfaceName, $function);
+ push(@dartInterfaceContent, " $interfaceMethodDeclaration;\n");
+
+ my @resolver = ();
+ push(@resolver, " $interfaceMethodDeclaration {\n");
+ my @parameters = ();
+ foreach my $parameterIndex (0..@{$function->parameters}) {
+ my $parameter = @{$function->parameters}[$parameterIndex];
+ if (!$parameter || IsParameterOptionalInWebKit($parameter)) {
+ my $functionName = GenerateNativeBinding($interfaceName, $function, \@parameters);
+ if ($parameter) {
+ my $parameterName = $parameter->name;
+ push(@resolver, " if ($parameterName === null)\n ");
+ }
+ my $parameterNames = join(", ", map { $_->name } @parameters);
+ push(@resolver, " return $functionName($parameterNames);\n");
+ }
+ push(@parameters, $parameter);
+ }
+ push(@resolver, " }\n");
+ push(@dartImplContent, join("", @resolver));
+}
+
+sub GenerateDartOverloadResolver
+{
+ my ($interfaceName, $function) = @_;
+
+ # Generate code for choosing the correct overload to call. Overloads are
+ # chosen based on the the type of the arguments. When more than a single
+ # overload is applicable, precedence is given according to the order of
+ # declaration in the IDL.
+
+ my $interfaceMethodDeclaration = DartInterfaceMethodDeclaration($interfaceName, $function);
+ push(@dartInterfaceContent, " $interfaceMethodDeclaration;\n");
+
+ my @resolver = ();
+ push(@resolver, " $interfaceMethodDeclaration {\n");
+ my $maxParameterCount = MaxOverloadParameterCount($function);
+ foreach my $overload (@{$function->{overloads}}) {
+ my @parameters = ();
+ my @parameterNames = ();
+ my @parameterChecks = map { "_arg$_ === null" } (0..$maxParameterCount - 1);
+ foreach my $parameterIndex (0..@{$overload->parameters}) {
+ my $parameter = @{$overload->parameters}[$parameterIndex];
+ if (!$parameter || IsParameterOptionalInWebKit($parameter)) {
+ my $functionName = GenerateNativeBinding($interfaceName, $overload, \@parameters);
+ my $parameterNames = join(", ", @parameterNames);
+ my $parameterChecks = join(" && ", @parameterChecks);
+ push(@resolver, <<END);
+ if ($parameterChecks)
+ return $functionName($parameterNames);
+END
+ }
+ last if !$parameter;
+ my $idlType = $codeGenerator->StripModule($parameter->type);
+ my $dartType = IDLTypeToDart($idlType);
+ push(@parameterNames, "_arg$parameterIndex");
+ $parameterChecks[$parameterIndex] = "_arg$parameterIndex is $dartType";
+ push(@parameters, $parameter);
+ }
+ }
+
+ # FIXME: throw appropriate exception when overload is not found.
+ push(@resolver, <<END);
+ throw "Failed to find overload of @{[$function->signature->name]}";
+ }
+END
+ push(@dartImplContent, join("", @resolver));
+}
+
+sub ParentInterface
+{
+ my $dataNode = shift;
+
+ foreach (@{$dataNode->parents}) {
+ my $parent = $codeGenerator->StripModule($_);
+ if ($parent eq "EventTarget") {
+ next;
+ }
+ return $parent;
+ }
+}
+
+my %excludedInterfaces = (
+ "SVGURIReference" => 1, # Is not in the list of SVG idls files (see WebCore.gypi), v8 bindings do not immediately compile
+ # Explicitly excluded in WebCore.gyp
+ "ElementTimeControl" => 1,
+ "SVGExternalResourcesRequired" => 1,
+ "SVGFilterPrimitiveStandardAttributes" => 1,
+ "SVGFitToViewBox" => 1,
+ "SVGLangSpace" => 1,
+ "SVGLocatable" => 1,
+ "SVGStylable" => 1,
+ "SVGTests" => 1,
+ "SVGTransformable" => 1,
+ "SVGViewSpec" => 1,
+ "SVGZoomAndPan" => 1,
+);
+
+sub ListLike
+{
+ my ($elementType, $needsAuxiliaryAccessors) = @_;
+
+ my @auxiliaryMethods = ();
+ if ($needsAuxiliaryAccessors) {
+ push(@auxiliaryMethods, ["$elementType operator [] (int index)", "numericIndexGetter", 2]);
+ push(@auxiliaryMethods, ["void operator []= (int index, $elementType value)", "numericIndexSetter", 3]);
+ }
+
+ return IDLTypeInfoStruct->new(
+ additionalInterfaces => ["List<$elementType>"],
+ superClass => "ListBase<$elementType>",
+ auxilaryMethods => \@auxiliaryMethods
+ );
+}
+
+sub MapLike
+{
+ # FIXME: most probably we need to deduce more types using hints like
+ # HasNameGetter, CustomDeleteProperty, CustomGetPropertyNames, DelegatingPutFunction
+ # attributes.
+ # FIXME: technically at least DOMStringMap.setItem and DOMStringMap.item could be automatically
+ # generated and then used from [] and []=. I don't do it for now not to mess up with IDLs too
+ # much.
+ # FIXME: support removal of elements if allowed (it is at least for DOMStringMap.)
+ my ($interfaceName, $keyType, $elementType) = @_;
+ return IDLTypeInfoStruct->new(
+ additionalInterfaces => ["Map<$keyType, $elementType>"],
+ superClass => "MapBase<$keyType, $elementType>",
+ auxilaryMethods => [
+ ["Collection<$keyType> getKeys()", "getKeys", 1],
+ ["$elementType operator [] ($keyType k)", "item", 2],
+ ["operator []= ($keyType k, $elementType v)", "setItem", 3],
+ ["$elementType remove($keyType k)", "deleteItem", 2],
+ ],
+ );
+}
+
+my %idlTypeInfoOverrides = (
+ "CanvasPixelArray" => ListLike("int", 1),
+ "DOMStringMap" => MapLike("DOMStringMap", "String", "String"),
+ "HTMLCollection" => ListLike("Node"),
+ "NodeList" => ListLike("Node"),
+ "StyleSheetList" => ListLike("StyleSheet"),
+);
+
+# FIXME: turn into the single IDL type info registry.
+sub IDLTypeInfo
+{
+ my ($dataNode,) = @_;
+ my $override = $idlTypeInfoOverrides{$dataNode->name};
+ return $override if $override;
+
+ my $parentInterface = ParentInterface($dataNode);
+ return IDLTypeInfoStruct->new(
+ superClass => $parentInterface ? "${parentInterface}Implementation" : "DOMType",
+ );
+}
+
+sub GenerateSource
+{
+ my ($object, $dataNode) = @_;
+
+ my $interfaceName = $dataNode->name;
+ my $w3cInterfaceName = IDLTypeToW3C($interfaceName);
+
+ push(@dartInterfaceContent, $headerTemplate);
+
+ # Build extends clause if any.
+ my $extendsClause = "";
+ my $parentInterface = ParentInterface($dataNode);
+ my $isEventTarget = $dataNode->extendedAttributes->{EventTarget};
+ my @implementedInterfaces = ();
+ push(@implementedInterfaces, $parentInterface) if $parentInterface;
+ push(@implementedInterfaces, "EventTarget") if $isEventTarget;
+
+ push(@implementedInterfaces, @{IDLTypeInfo($dataNode)->additionalInterfaces});
+ push(@implementedInterfaces, @allParents);
+
+ if (@implementedInterfaces) {
+ $extendsClause = " extends " . join(", ", @implementedInterfaces);
+ }
+
+ # Build default clause if any.
+ my $defaultClause = "";
+ if (HasCustomConstructor($dataNode)) {
+ $defaultClause = " factory ${w3cInterfaceName}Implementation";
+ push(@customCallbackDeclarations, GenerateCustomCallbackDeclaration("constructorCallback"));
+ }
+
+ push(@dartInterfaceContent, "\ninterface ${w3cInterfaceName}${extendsClause}${defaultClause} {\n");
+ push(@dartInterfaceContent, "\n // Constants.\n");
+ foreach my $constant (@{$dataNode->constants}) {
+ my $name = $constant->name;
+ my $value = $constant->value;
+
+ push(@dartInterfaceContent, " static final int $name = $value;\n");
+ }
+
+ # Generate Dart implementation prologue.
+ my $implementationClassName = "${interfaceName}Implementation";
+ my $superClass = IDLTypeInfo($dataNode)->superClass;
+ push(@dartImplContent, $headerTemplate);
+ push(@dartImplContent, "\nclass $implementationClassName extends $superClass implements $interfaceName {\n");
+
+ GenerateImplementationPrologue($dataNode);
+
+ # Generate fields.
+ # FIXME: special treatment of constructors attributes (see V8 code generator).
+ push(@dartInterfaceContent, "\n // Fields.\n");
+ push(@dartImplContent, "\n // Fields.\n");
+ push(@implContent, "\n// Getters & setters.\n");
+ foreach my $attribute (@{$dataNode->attributes}) {
+ next if IgnoredAttribute($interfaceName, $attribute);
+ GenerateField($interfaceName, $attribute);
+ }
+
+ # Generate methods.
+ push(@dartInterfaceContent, "\n // Methods.\n");
+ push(@dartImplContent, "\n // Methods.\n");
+ push(@implContent, "\n// Callbacks.\n");
+ foreach my $function (@{$dataNode->functions}) {
+ next if IgnoredCallback($interfaceName, $function);
+ next if HasOverloads($function) && $function->{overloadIndex} != 1;
+ GenerateMethod($interfaceName, $function);
+ }
+
+ foreach my $auxilaryMethod (@{IDLTypeInfo($dataNode)->auxilaryMethods}) {
+ my $dartDeclaration = $auxilaryMethod->[0];
+ my $descriptor = CreateFunctionNativeDescriptor($interfaceName, $auxilaryMethod->[1], $auxilaryMethod->[2]);
+ my $nativeId = $descriptor->nativeId;
+ push(@dartImplContent, " $dartDeclaration native \"$nativeId\";\n");
+ push(@customCallbackDeclarations, GenerateCustomCallbackDeclaration($descriptor->cppCallbackName));
+ }
+
+ if (HasCustomConstructor($dataNode)) {
+ my $parameterCount = $dataNode->extendedAttributes->{"ConstructorParameters"} || 0;
+ my $descriptor = CreateFunctionNativeDescriptor($interfaceName, "constructor", 1 + $parameterCount);
+ my $nativeId = $descriptor->nativeId;
+ my $parameters = DartAnonymousNamedOptionalParameters($parameterCount);
+ my $arguments = DartAnonymousArguments($parameterCount);
+ push(@dartInterfaceContent, " $w3cInterfaceName($parameters);\n");
+ push(@dartImplContent, <<END);
+ $implementationClassName($parameters) {
+ this._bind($arguments);
+ }
+END
+ push(@dartImplContent, " void _bind($arguments) native \"$nativeId\";\n");
+ }
+
+ # Generate implementation support.
+ # FIXME: get rid of implementation support completely.
+ push(@dartImplContent, <<END);
+ // Implementation support.
+ static $implementationClassName _create$implementationClassName() => new $implementationClassName._create$implementationClassName();
+ $implementationClassName._create$implementationClassName();
+
+ String get typeName() => \"$interfaceName\";
+END
+
+ push(@dartInterfaceContent, "}\n");
+ push(@dartImplContent, "}\n");
+
+ if (HasW3CName($interfaceName)) {
+ push(@dartInterfaceContent, "\ninterface ${interfaceName} extends ${w3cInterfaceName} {}\n");
+ }
+
+ GenerateImplementationEpilogue($dataNode);
+}
+
+sub GenerateField
+{
+ my ($interfaceName, $attribute) = @_;
+
+ my $attributeName = DartName($interfaceName, $attribute->signature->name);
+ my $attributeType = $attribute->signature->type;
+ my $dartAttributeType = IDLTypeToDart($attributeType);
+
+ # Generate field declaration.
+ my $final = HasSetter($attribute) ? "" : "final ";
+ push(@dartInterfaceContent, " $final$dartAttributeType $attributeName;\n");
+
+ # Generate getter implementation.
+ my $getterDescriptor = CreateGetterNativeDescriptor($interfaceName, $attributeName);
+ my $getterNativeId = $getterDescriptor->nativeId;
+ push(@dartImplContent, " $dartAttributeType get $attributeName() native \"$getterNativeId\";\n");
+ if (HasCustomGetter($attribute)) {
+ push(@customCallbackDeclarations, GenerateCustomCallbackDeclaration($getterDescriptor->cppCallbackName));
+ } else {
+ my $invocationPrefix = $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
+ my $raisesExceptions = scalar(@{$attribute->getterExceptions});
+ GenerateGenericBindingsFunction($getterDescriptor->cppCallbackName, $interfaceName, $invocationPrefix, [], $attributeType, $raisesExceptions, $attribute->signature->extendedAttributes);
+ }
+
+ return unless HasSetter($attribute);
+
+ # Generate setter implementation.
+ my $setterDescriptor = CreateSetterNativeDescriptor($interfaceName, $attributeName);
+ my $setterNativeId = $setterDescriptor->nativeId;
+ push(@dartImplContent, " void set $attributeName($dartAttributeType) native \"$setterNativeId\";\n");
+ if (HasCustomSetter($attribute)) {
+ push(@customCallbackDeclarations, GenerateCustomCallbackDeclaration($setterDescriptor->cppCallbackName));
+ } else {
+ my $invocationPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
+ my $raisesExceptions = scalar(@{$attribute->setterExceptions});
+ GenerateGenericBindingsFunction($setterDescriptor->cppCallbackName, $interfaceName, $invocationPrefix, [$attribute->signature], "void", $raisesExceptions, $attribute->signature->extendedAttributes, 1);
+ }
+}
+
+sub GenerateMethod
+{
+ my ($interfaceName, $function) = @_;
+
+ my $functionName = DartName($interfaceName, $function->signature->name);
+
+ if (!$function->signature->extendedAttributes->{"Custom"}) {
+ if (HasOverloads($function)) {
+ GenerateDartOverloadResolver($interfaceName, $function);
+ } elsif (HasOptionalParameters($function)) {
+ GenerateDartOptionalArgumentsResolver($interfaceName, $function);
+ } else {
+ my $interfaceMethodDeclaration = DartInterfaceMethodDeclaration($interfaceName, $function);
+ push(@dartInterfaceContent, " $interfaceMethodDeclaration;\n");
+ my $bindingFunctionName = GenerateNativeBinding($interfaceName, $function, $function->parameters);
+ die if $bindingFunctionName ne $functionName;
+ }
+ } else {
+ my $parameters;
+ my $parameterCount;
+ if (HasOverloads($function)) {
+ $parameterCount = MaxOverloadParameterCount($function);
+ $parameters = DartAnonymousNamedOptionalParameters($parameterCount);
+ } else {
+ $parameters = DartParameters($function, $function->parameters, 1);
+ $parameterCount = DartParameterCount($function, $function->parameters);
+ }
+ my $methodDeclaration = DartMethodDeclaration($functionName, $parameters, $function->signature->type);
+ my $descriptor = CreateFunctionNativeDescriptor($interfaceName, $functionName, 1 + $parameterCount);
+ my $nativeId = $descriptor->nativeId;
+ push(@dartInterfaceContent, " $methodDeclaration;\n");
+ push(@dartImplContent, " $methodDeclaration native \"$nativeId\";\n");
+ push(@customCallbackDeclarations, GenerateCustomCallbackDeclaration($descriptor->cppCallbackName));
+ }
+
+ # If there is a method named "item", duplicate it as operator [].
+ if ($functionName eq "item") {
+ # Consider operator [] should support overloads and optional arguments.
+ die "$interfaceName.item has overloads" if HasOverloads($function);
+ die "$interfaceName.item has optional arguments" if HasOptionalParameters($function);
+
+ my $subscriptOperatorDeclaration = DartInterfaceMethodDeclaration($interfaceName, $function, "operator []");
+ my $parameters = join ", ", (map { $_->name } @{$function->parameters});
+ push(@dartInterfaceContent, " $subscriptOperatorDeclaration;\n");
+ push(@dartImplContent, " $subscriptOperatorDeclaration { return item($parameters); }\n");
+ }
+}
+
+sub GenerateNativeBinding
+{
+ my ($interfaceName, $function, $parameters) = @_;
+
+ my $functionName = DartName($interfaceName, $function->signature->name);
+ if (HasOverloads($function)) {
+ $functionName .= $function->{overloadIndex};
+ }
+ if (HasOptionalParameters($function)) {
+ $functionName .= "_" . @$parameters;
+ }
+
+ my $extendedAttributes = $function->signature->extendedAttributes;
+ my $returnType = $function->signature->type;
+
+ my $dartParameters = DartParameters($function, $parameters, 0);
+ my $dartParameterCount = DartParameterCount($function, $parameters);
+ my $methodDeclaration = DartMethodDeclaration($functionName, $dartParameters, $returnType);
+ my $descriptor = CreateFunctionNativeDescriptor($interfaceName, $functionName, 1 + $dartParameterCount);
+ my $nativeId = $descriptor->nativeId;
+ push(@dartImplContent, <<END);
+ $methodDeclaration native "$nativeId";
+END
+
+ my $invocationPrefix;
+ if ($extendedAttributes->{ImplementationFunction}) {
+ $invocationPrefix = $extendedAttributes->{ImplementationFunction} . "(";
+ } else {
+ $invocationPrefix = $function->signature->name . "(";
+ }
+ my $raisesExceptions = scalar(@{$function->raisesExceptions});
+ GenerateGenericBindingsFunction($descriptor->cppCallbackName, $interfaceName, $invocationPrefix, $parameters, $returnType, $raisesExceptions, $extendedAttributes);
+
+ return $functionName;
+}
+
+# Internal helper
+sub WriteData
+{
+ if (defined($IMPL)) {
+ # Write content to file.
+ print $IMPL @implContentHeader;
+
+ print $IMPL @implFixedHeader;
+
+ print $IMPL GenerateIncludes(keys(%implIncludes));
+
+ print $IMPL "\n";
+ print $IMPL @implContent;
+ close($IMPL);
+ undef($IMPL);
+
+ %implIncludes = ();
+ @implFixedHeader = ();
+ @implHeaderContent = ();
+ @implContent = ();
+ @dartNatives = ();
+ }
+
+ if (defined($HEADER)) {
+ # Write content to file.
+ print $HEADER @headerContent;
+ close($HEADER);
+ undef($HEADER);
+
+ @headerContent = ();
+ }
+
+ if (defined($DART_INTERFACE)) {
+ # Write content of Dart file.
+ print $DART_INTERFACE @dartInterfaceContent;
+ close($DART_INTERFACE);
+ undef($DART_INTERFACE);
+
+ @dartInterfaceContent = ();
+ }
+
+ if (defined($DART_IMPL)) {
+ # Write content of Dart file.
+ print $DART_IMPL @dartImplContent;
+ close($DART_IMPL);
+ undef($DART_IMPL);
+
+ @dartImplContent = ();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698