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 = (); |
+ } |
+} |