| # 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 CodeGeneratorV8; |
| |
| use Digest::MD5; |
| |
| my $module = ""; |
| my $outputDir = ""; |
| my $outputHeadersDir = ""; |
| |
| my @headerContent = (); |
| my @implContentHeader = (); |
| my @implFixedHeader = (); |
| my @implContent = (); |
| my @implContentDecls = (); |
| my %implIncludes = (); |
| my %headerIncludes = (); |
| |
| my @allParents = (); |
| |
| # 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 |
| |
| # Default constructor |
| sub new |
| { |
| my $object = shift; |
| my $reference = { }; |
| |
| $codeGenerator = shift; |
| $outputDir = shift; |
| $outputHeadersDir = shift; |
| |
| bless($reference, $object); |
| return $reference; |
| } |
| |
| sub finish |
| { |
| my $object = shift; |
| |
| # Commit changes! |
| $object->WriteData(); |
| } |
| |
| # Params: 'domClass' struct |
| sub GenerateInterface |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| my $defines = shift; |
| |
| # Start actual generation |
| if ($dataNode->extendedAttributes->{"Callback"}) { |
| $object->GenerateCallbackHeader($dataNode); |
| $object->GenerateCallbackImplementation($dataNode); |
| } else { |
| $object->GenerateHeader($dataNode); |
| $object->GenerateImplementation($dataNode); |
| } |
| |
| my $name = $dataNode->name; |
| |
| # Open files for writing |
| my $headerFileName = "$outputHeadersDir/V8$name.h"; |
| my $implFileName = "$outputDir/V8$name.cpp"; |
| |
| open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName"; |
| open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName"; |
| } |
| |
| # Params: 'idlDocument' struct |
| sub GenerateModule |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| |
| $module = $dataNode->module; |
| } |
| |
| sub AddIncludesForType |
| { |
| my $type = $codeGenerator->StripModule(shift); |
| |
| # When we're finished with the one-file-per-class |
| # reorganization, we won't need these special cases. |
| if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->AvoidInclusionOfType($type) and $type ne "Date") { |
| # default, include the same named file |
| $implIncludes{GetV8HeaderName(${type})} = 1; |
| |
| if ($type =~ /SVGPathSeg/) { |
| $joinedName = $type; |
| $joinedName =~ s/Abs|Rel//; |
| $implIncludes{"${joinedName}.h"} = 1; |
| } |
| } |
| |
| # additional includes (things needed to compile the bindings but not the header) |
| |
| if ($type eq "CanvasRenderingContext2D") { |
| $implIncludes{"CanvasGradient.h"} = 1; |
| $implIncludes{"CanvasPattern.h"} = 1; |
| $implIncludes{"CanvasStyle.h"} = 1; |
| } |
| |
| if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") { |
| $implIncludes{"PlatformString.h"} = 1; |
| } |
| |
| if ($type eq "CSSStyleDeclaration") { |
| $implIncludes{"CSSMutableStyleDeclaration.h"} = 1; |
| } |
| |
| if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") { |
| # So we can get String -> AtomicString conversion for namedItem(). |
| $implIncludes{"wtf/text/AtomicString.h"} = 1; |
| } |
| } |
| |
| # If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if. |
| sub GenerateConditionalString |
| { |
| my $node = shift; |
| my $conditional = $node->extendedAttributes->{"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 GetSVGPropertyTypes |
| { |
| my $implType = shift; |
| |
| my $svgPropertyType; |
| my $svgListPropertyType; |
| my $svgNativeType; |
| |
| return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/; |
| |
| $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType); |
| return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType; |
| |
| # Append space to avoid compilation errors when using PassRefPtr<$svgNativeType> |
| $svgNativeType = "$svgNativeType "; |
| |
| my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType); |
| if ($svgNativeType =~ /SVGPropertyTearOff/) { |
| $svgPropertyType = $svgWrappedNativeType; |
| $implIncludes{"SVGAnimatedPropertyTearOff.h"} = 1; |
| } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) { |
| $svgListPropertyType = $svgWrappedNativeType; |
| $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; |
| $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1; |
| } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) { |
| $svgListPropertyType = $svgWrappedNativeType; |
| $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; |
| $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1; |
| } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) { |
| $svgListPropertyType = $svgWrappedNativeType; |
| $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1; |
| } |
| |
| if ($svgPropertyType) { |
| $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint"; |
| } |
| |
| return ($svgPropertyType, $svgListPropertyType, $svgNativeType); |
| } |
| |
| sub GenerateHeader |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| |
| my $interfaceName = $dataNode->name; |
| my $className = "V8$interfaceName"; |
| my $implClassName = $interfaceName; |
| |
| # Copy contents of parent classes except the first parent or if it is |
| # EventTarget. |
| $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1); |
| |
| my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; |
| |
| # - Add default header template |
| push(@headerContent, GenerateHeaderContentHeader($dataNode)); |
| |
| $headerIncludes{"wtf/text/StringHash.h"} = 1; |
| $headerIncludes{"WrapperTypeInfo.h"} = 1; |
| $headerIncludes{"V8DOMWrapper.h"} = 1; |
| |
| my $headerClassInclude = GetHeaderClassInclude($implClassName); |
| $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne ""; |
| |
| my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName); |
| |
| foreach my $headerInclude (sort keys(%headerIncludes)) { |
| push(@headerContent, "#include \"${headerInclude}\"\n"); |
| } |
| |
| push(@headerContent, "#include <v8.h>\n"); |
| push(@headerContent, "#include <wtf/HashMap.h>\n"); |
| |
| push(@headerContent, "\nnamespace WebCore {\n"); |
| push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType; |
| if ($svgNativeType) { |
| if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) { |
| push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n"); |
| } else { |
| push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n"); |
| } |
| } |
| push(@headerContent, "\nclass FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect"; |
| push(@headerContent, "\nclass $className {\n"); |
| |
| my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName); |
| my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName); |
| my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : ""; |
| my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : ""; |
| my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : ""; |
| |
| push(@headerContent, <<END); |
| |
| public: |
| static bool HasInstance(v8::Handle<v8::Value> value); |
| static v8::Persistent<v8::FunctionTemplate> GetRawTemplate(); |
| static v8::Persistent<v8::FunctionTemplate> GetTemplate(); |
| static ${nativeType}* toNative(v8::Handle<v8::Object> object) |
| { |
| return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex)); |
| } |
| inline static v8::Handle<v8::Object> wrap(${nativeType}*${forceNewObjectParameter}); |
| static void derefObject(void*); |
| static WrapperTypeInfo info; |
| END |
| if (IsActiveDomType($implClassName)) { |
| push(@headerContent, " static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n"); |
| } |
| |
| if ($implClassName eq "DOMWindow") { |
| push(@headerContent, <<END); |
| static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate(); |
| END |
| } |
| |
| if ($implClassName eq "HTMLDocument") { |
| push(@headerContent, <<END); |
| static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl); |
| static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key); |
| END |
| } |
| |
| my @enabledAtRuntime; |
| foreach my $function (@{$dataNode->functions}) { |
| my $name = $function->signature->name; |
| my $attrExt = $function->signature->extendedAttributes; |
| |
| if ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&); |
| END |
| } |
| |
| if ($attrExt->{"EnabledAtRuntime"}) { |
| push(@enabledAtRuntime, $function); |
| } |
| } |
| |
| if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> constructorCallback(const v8::Arguments& args); |
| END |
| } |
| |
| foreach my $attribute (@{$dataNode->attributes}) { |
| my $name = $attribute->signature->name; |
| my $attrExt = $attribute->signature->extendedAttributes; |
| if ($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"} |
| || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info); |
| END |
| } |
| if ($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"} |
| || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) { |
| push(@headerContent, <<END); |
| static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info); |
| END |
| } |
| if ($attrExt->{"EnabledAtRuntime"}) { |
| push(@enabledAtRuntime, $attribute); |
| } |
| } |
| |
| GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode); |
| GenerateHeaderCustomCall($dataNode); |
| GenerateHeaderCustomInternalFieldIndices($dataNode); |
| |
| if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) { |
| push(@headerContent, <<END); |
| static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data); |
| static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data); |
| END |
| } |
| |
| push(@headerContent, <<END); |
| private: |
| static v8::Handle<v8::Object> wrapSlow(${nativeType}*); |
| }; |
| |
| END |
| |
| push(@headerContent, <<END); |
| |
| v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl${forceNewObjectInput}) |
| { |
| END |
| if ($domMapFunction) { |
| push(@headerContent, " if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName); |
| my $getWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getWrapper(impl)" : "${domMapFunction}.get(impl)"; |
| push(@headerContent, <<END); |
| v8::Handle<v8::Object> wrapper = ${getWrapper}; |
| if (!wrapper.IsEmpty()) |
| return wrapper; |
| END |
| push(@headerContent, " }\n") if IsDOMNodeType($interfaceName); |
| } |
| push(@headerContent, <<END); |
| return ${className}::wrapSlow(impl); |
| } |
| END |
| |
| if (!HasCustomToV8Implementation($dataNode, $interfaceName)) { |
| push(@headerContent, <<END); |
| |
| inline v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectParameter}) |
| { |
| if (!impl) |
| return v8::Null(); |
| return ${className}::wrap(impl${forceNewObjectCall}); |
| } |
| END |
| } elsif ($interfaceName ne 'Node') { |
| push(@headerContent, <<END); |
| |
| v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter}); |
| END |
| } else { |
| push(@headerContent, <<END); |
| |
| v8::Handle<v8::Value> toV8Slow(Node*, bool); |
| |
| inline v8::Handle<v8::Value> toV8(Node* impl, bool forceNewObject = false) |
| { |
| if (!impl) |
| return v8::Null(); |
| if (!forceNewObject) { |
| v8::Handle<v8::Value> wrapper = V8DOMWrapper::getWrapper(impl); |
| if (!wrapper.IsEmpty()) |
| return wrapper; |
| } |
| return toV8Slow(impl, forceNewObject); |
| } |
| END |
| } |
| |
| if (IsRefPtrType($implClassName)) { |
| push(@headerContent, <<END); |
| inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl${forceNewObjectParameter}) |
| { |
| return toV8(impl.get()${forceNewObjectCall}); |
| } |
| END |
| } |
| |
| push(@headerContent, "}\n\n"); |
| push(@headerContent, "#endif // $className" . "_h\n"); |
| |
| my $conditionalString = GenerateConditionalString($dataNode); |
| push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| } |
| |
| sub GetInternalFields |
| { |
| my $dataNode = shift; |
| my $name = $dataNode->name; |
| |
| my @customInternalFields = (); |
| |
| # We can't ask whether a parent type has a given extendedAttribute, so special-case Node, AbstractWorker and WorkerContext to include all sub-types. |
| # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't. |
| if ($dataNode->extendedAttributes->{"EventTarget"} || IsNodeSubType($dataNode) || IsSubType($dataNode, "AbstractWorker") || IsSubType($dataNode, "WorkerContext") |
| || $name eq "SVGElementInstance") { |
| push(@customInternalFields, "eventListenerCacheIndex"); |
| } |
| |
| if (IsSubType($dataNode, "Document")) { |
| push(@customInternalFields, "implementationIndex"); |
| } elsif ($name eq "DOMWindow") { |
| push(@customInternalFields, "enteredIsolatedWorldIndex"); |
| } |
| return @customInternalFields; |
| } |
| |
| sub GetHeaderClassInclude |
| { |
| my $className = shift; |
| if ($className =~ /SVGPathSeg/) { |
| $className =~ s/Abs|Rel//; |
| } |
| return "" if ($codeGenerator->AvoidInclusionOfType($className)); |
| return "${className}.h"; |
| } |
| |
| sub GenerateHeaderCustomInternalFieldIndices |
| { |
| my $dataNode = shift; |
| my @customInternalFields = GetInternalFields($dataNode); |
| my $customFieldCounter = 0; |
| foreach my $customInternalField (@customInternalFields) { |
| push(@headerContent, <<END); |
| static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; |
| END |
| $customFieldCounter++; |
| } |
| push(@headerContent, <<END); |
| static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; |
| END |
| } |
| |
| my %indexerSpecialCases = ( |
| "Storage" => 1, |
| "HTMLAppletElement" => 1, |
| "HTMLEmbedElement" => 1, |
| "HTMLObjectElement" => 1 |
| ); |
| |
| sub GenerateHeaderNamedAndIndexedPropertyAccessors |
| { |
| my $dataNode = shift; |
| my $interfaceName = $dataNode->name; |
| my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; |
| my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"}; |
| my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; |
| my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"}; |
| my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; |
| my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"}; |
| if ($interfaceName eq "HTMLOptionsCollection") { |
| $interfaceName = "HTMLCollection"; |
| $hasCustomIndexedGetter = 1; |
| $hasCustomNamedGetter = 1; |
| } |
| if ($interfaceName eq "DOMWindow") { |
| $hasCustomDeleterr = 0; |
| $hasEnumerator = 0; |
| } |
| if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") { |
| $hasCustomNamedGetter = 1; |
| } |
| if ($interfaceName eq "HTMLDocument") { |
| $hasCustomNamedGetter = 0; |
| $hasCustomIndexedGetter = 0; |
| } |
| my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName}; |
| |
| if ($hasCustomIndexedGetter || $isIndexerSpecialCase) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&); |
| END |
| } |
| |
| if ($isIndexerSpecialCase || $hasCustomIndexedSetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&); |
| END |
| } |
| if ($hasCustomDeleters) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&); |
| END |
| } |
| if ($hasCustomNamedGetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&); |
| END |
| } |
| if ($hasCustomNamedSetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&); |
| END |
| } |
| if ($hasCustomDeleters) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&); |
| END |
| } |
| if ($hasCustomEnumerator) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&); |
| static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&); |
| END |
| } |
| } |
| |
| sub GenerateHeaderCustomCall |
| { |
| my $dataNode = shift; |
| |
| if ($dataNode->extendedAttributes->{"CustomCall"}) { |
| push(@headerContent, " static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n"); |
| } |
| if ($dataNode->name eq "Event") { |
| push(@headerContent, " static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); |
| push(@headerContent, " static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);\n"); |
| } |
| if ($dataNode->name eq "Location") { |
| push(@headerContent, " static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); |
| push(@headerContent, " static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); |
| push(@headerContent, " static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); |
| } |
| } |
| |
| sub GenerateSetDOMException |
| { |
| my $indent = shift; |
| my $result = ""; |
| |
| $result .= $indent . "if (UNLIKELY(ec)) {\n"; |
| $result .= $indent . " V8Proxy::setDOMException(ec);\n"; |
| $result .= $indent . " return v8::Handle<v8::Value>();\n"; |
| $result .= $indent . "}\n"; |
| |
| return $result; |
| } |
| |
| sub IsSubType |
| { |
| my $dataNode = shift; |
| my $parentType = shift; |
| return 1 if ($dataNode->name eq $parentType); |
| foreach (@allParents) { |
| my $parent = $codeGenerator->StripModule($_); |
| return 1 if $parent eq $parentType; |
| } |
| return 0; |
| } |
| |
| sub IsNodeSubType |
| { |
| my $dataNode = shift; |
| return IsSubType($dataNode, "Node"); |
| } |
| |
| sub GenerateDomainSafeFunctionGetter |
| { |
| my $function = shift; |
| my $implClassName = shift; |
| |
| my $className = "V8" . $implClassName; |
| my $funcName = $function->signature->name; |
| |
| my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())"; |
| if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) { |
| $signature = "v8::Local<v8::Signature>()"; |
| } |
| |
| my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature); |
| |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) |
| { |
| INC_STATS(\"DOM.$implClassName.$funcName._get\"); |
| static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); |
| v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This()); |
| if (holder.IsEmpty()) { |
| // can only reach here by 'object.__proto__.func', and it should passed |
| // domain security check already |
| return privateTemplate->GetFunction(); |
| } |
| ${implClassName}* imp = ${className}::toNative(holder); |
| if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { |
| static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); |
| return sharedTemplate->GetFunction(); |
| } |
| return privateTemplate->GetFunction(); |
| } |
| |
| END |
| } |
| |
| sub GenerateConstructorGetter |
| { |
| my $implClassName = shift; |
| |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) |
| { |
| INC_STATS(\"DOM.$implClassName.constructors._get\"); |
| v8::Handle<v8::Value> data = info.Data(); |
| ASSERT(data->IsExternal() || data->IsNumber()); |
| WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data); |
| END |
| |
| if ($implClassName eq "DOMWindow") { |
| push(@implContentDecls, <<END); |
| // Get the proxy corresponding to the DOMWindow if possible to |
| // make sure that the constructor function is constructed in the |
| // context of the DOMWindow and not in the context of the caller. |
| return V8DOMWrapper::getConstructor(type, V8DOMWindow::toNative(info.Holder())); |
| END |
| } elsif ($implClassName eq "DedicatedWorkerContext" or $implClassName eq "WorkerContext" or $implClassName eq "SharedWorkerContext") { |
| push(@implContentDecls, <<END); |
| return V8DOMWrapper::getConstructor(type, V8WorkerContext::toNative(info.Holder())); |
| END |
| } else { |
| push(@implContentDecls, " return v8::Handle<v8::Value>();"); |
| } |
| |
| push(@implContentDecls, <<END); |
| } |
| |
| END |
| } |
| |
| sub GenerateNormalAttrGetter |
| { |
| my $attribute = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| my $interfaceName = shift; |
| |
| my $attrExt = $attribute->signature->extendedAttributes; |
| my $attrName = $attribute->signature->name; |
| my $attrType = GetTypeFromSignature($attribute->signature); |
| my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1); |
| |
| my $getterStringUsesImp = $implClassName ne "SVGNumber"; |
| my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName); |
| |
| # Getter |
| my $conditionalString = GenerateConditionalString($attribute->signature); |
| push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString; |
| |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) |
| { |
| INC_STATS(\"DOM.$implClassName.$attrName._get\"); |
| END |
| |
| if ($svgNativeType) { |
| my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); |
| if ($svgWrappedNativeType =~ /List/) { |
| push(@implContentDecls, <<END); |
| $svgNativeType* imp = V8${implClassName}::toNative(info.Holder()); |
| END |
| } else { |
| push(@implContentDecls, <<END); |
| $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder()); |
| $svgWrappedNativeType& impInstance = wrapper->propertyReference(); |
| END |
| if ($getterStringUsesImp) { |
| push(@implContentDecls, <<END); |
| $svgWrappedNativeType* imp = &impInstance; |
| END |
| } |
| } |
| } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) { |
| if ($interfaceName eq "DOMWindow") { |
| push(@implContentDecls, <<END); |
| v8::Handle<v8::Object> holder = info.Holder(); |
| END |
| } else { |
| # perform lookup first |
| push(@implContentDecls, <<END); |
| v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This()); |
| if (holder.IsEmpty()) |
| return v8::Handle<v8::Value>(); |
| END |
| } |
| push(@implContentDecls, <<END); |
| ${implClassName}* imp = V8${implClassName}::toNative(holder); |
| END |
| } else { |
| my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; |
| my $url = $attribute->signature->extendedAttributes->{"URL"}; |
| if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { |
| # Generate super-compact call for regular attribute getter: |
| my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect; |
| my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); |
| $implIncludes{"${namespace}.h"} = 1; |
| push(@implContentDecls, " return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n"); |
| push(@implContentDecls, "}\n\n"); |
| push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| return; |
| # Skip the rest of the function! |
| } |
| push(@implContentDecls, <<END); |
| ${implClassName}* imp = V8${implClassName}::toNative(info.Holder()); |
| END |
| } |
| |
| # Generate security checks if necessary |
| if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) { |
| push(@implContentDecls, " if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->$attrName()))\n return v8::Handle<v8::Value>();\n\n"); |
| } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) { |
| push(@implContentDecls, " if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->contentDocument()))\n return v8::Handle<v8::Value>();\n\n"); |
| } |
| |
| my $useExceptions = 1 if @{$attribute->getterExceptions}; |
| if ($useExceptions) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, " ExceptionCode ec = 0;\n"); |
| } |
| |
| if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) { |
| $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; |
| } |
| |
| my $returnType = GetTypeFromSignature($attribute->signature); |
| |
| my $getterString; |
| if ($getterStringUsesImp) { |
| $getterString = "imp->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute); |
| $getterString .= "ec" if $useExceptions; |
| $getterString .= ")"; |
| } else { |
| $getterString = "impInstance"; |
| } |
| |
| my $result; |
| my $wrapper; |
| |
| if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") { |
| push(@implContentDecls, " if (!imp->document())\n"); |
| push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); |
| } |
| |
| if ($useExceptions) { |
| if ($nativeType =~ /^V8Parameter/) { |
| push(@implContentDecls, " " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n"); |
| } else { |
| push(@implContentDecls, " $nativeType v = $getterString;\n"); |
| } |
| push(@implContentDecls, GenerateSetDOMException(" ")); |
| $result = "v"; |
| $result .= ".release()" if (IsRefPtrType($returnType)); |
| } else { |
| # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary |
| $result = $getterString; |
| } |
| |
| # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get |
| # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to |
| # the newly created wrapper into an internal field of the holder object. |
| if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"}) |
| && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" |
| && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) { |
| AddIncludesForType($returnType); |
| my $domMapFunction = GetDomMapFunction(0, $returnType); |
| # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already |
| # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference. |
| push(@implContentDecls, " RefPtr<$returnType> result = ${getterString};\n"); |
| push(@implContentDecls, " v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Value>();\n"); |
| push(@implContentDecls, " if (wrapper.IsEmpty()) {\n"); |
| push(@implContentDecls, " wrapper = toV8(result.get());\n"); |
| push(@implContentDecls, " if (!wrapper.IsEmpty())\n"); |
| if ($dataNode->name eq "DOMWindow") { |
| push(@implContentDecls, " V8DOMWrapper::setHiddenWindowReference(imp->frame(), wrapper);\n"); |
| } else { |
| push(@implContentDecls, " V8DOMWrapper::setHiddenReference(info.Holder(), wrapper);\n"); |
| } |
| push(@implContentDecls, " }\n"); |
| push(@implContentDecls, " return wrapper;\n"); |
| push(@implContentDecls, "}\n\n"); |
| push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| return; |
| } |
| |
| if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) { |
| $implIncludes{"V8$attrType.h"} = 1; |
| my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType); |
| # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked. |
| push(@implContentDecls, " return toV8(static_cast<$svgNativeType*>($result));\n"); |
| } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) { |
| $implIncludes{"V8$attrType.h"} = 1; |
| $implIncludes{"SVGPropertyTearOff.h"} = 1; |
| my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType); |
| if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { |
| my $getter = $result; |
| $getter =~ s/imp->//; |
| $getter =~ s/\(\)//; |
| |
| my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter); |
| |
| my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName); |
| if ($selfIsTearOffType) { |
| $implIncludes{"SVGStaticPropertyWithParentTearOff.h"} = 1; |
| $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /; |
| |
| if ($result =~ /matrix/ and $implClassName eq "SVGTransform") { |
| # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform |
| # and a svgMatrix() method returning a SVGMatrix, used for the bindings. |
| $result =~ s/matrix/svgMatrix/; |
| } |
| |
| push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)));\n"); |
| } else { |
| $implIncludes{"SVGStaticPropertyTearOff.h"} = 1; |
| $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /; |
| |
| push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)));\n"); |
| } |
| } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) { |
| my $extraImp = "GetOwnerElementForType<$implClassName, IsDerivedFromSVGElement<$implClassName>::value>::ownerElement(imp), "; |
| push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create($extraImp$result)));\n"); |
| } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) { |
| push(@implContentDecls, " return toV8(WTF::getPtr($result));\n"); |
| } else { |
| push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create($result)));\n"); |
| } |
| } else { |
| push(@implContentDecls, " " . ReturnNativeToJSValue($attribute->signature, $result, " ").";\n"); |
| } |
| |
| push(@implContentDecls, "}\n\n"); # end of getter |
| push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| } |
| |
| sub GenerateNormalAttrSetter |
| { |
| my $attribute = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| my $interfaceName = shift; |
| |
| $implIncludes{"V8BindingMacros.h"} = 1; |
| |
| my $attrExt = $attribute->signature->extendedAttributes; |
| |
| my $conditionalString = GenerateConditionalString($attribute->signature); |
| push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString; |
| |
| push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n"); |
| push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); |
| |
| # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an |
| # interface type, then if the incoming value does not implement that interface, a TypeError is |
| # thrown rather than silently passing NULL to the C++ code. |
| # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both |
| # strings and numbers, so do not throw TypeError if the attribute is of these types. |
| if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) { |
| my $argType = GetTypeFromSignature($attribute->signature); |
| if (IsWrapperType($argType)) { |
| push(@implContentDecls, " if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n"); |
| push(@implContentDecls, " V8Proxy::throwTypeError();\n"); |
| push(@implContentDecls, " return;\n"); |
| push(@implContentDecls, " }\n"); |
| } |
| } |
| |
| my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName); |
| if ($svgNativeType) { |
| my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); |
| if ($svgWrappedNativeType =~ /List$/) { |
| push(@implContentDecls, <<END); |
| $svgNativeType* imp = V8${implClassName}::toNative(info.Holder()); |
| END |
| } else { |
| push(@implContentDecls, " $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n"); |
| push(@implContentDecls, " if (wrapper->role() == AnimValRole) {\n"); |
| push(@implContentDecls, " V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n"); |
| push(@implContentDecls, " return;\n"); |
| push(@implContentDecls, " }\n"); |
| push(@implContentDecls, " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"); |
| push(@implContentDecls, " $svgWrappedNativeType* imp = &impInstance;\n"); |
| } |
| } elsif ($attrExt->{"v8OnProto"}) { |
| if ($interfaceName eq "DOMWindow") { |
| push(@implContentDecls, <<END); |
| v8::Handle<v8::Object> holder = info.Holder(); |
| END |
| } else { |
| # perform lookup first |
| push(@implContentDecls, <<END); |
| v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This()); |
| if (holder.IsEmpty()) |
| return; |
| END |
| } |
| push(@implContentDecls, <<END); |
| ${implClassName}* imp = V8${implClassName}::toNative(holder); |
| END |
| } else { |
| my $attrType = GetTypeFromSignature($attribute->signature); |
| my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; |
| if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { |
| # Generate super-compact call for regular attribute setter: |
| my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect; |
| my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); |
| $implIncludes{"${namespace}.h"} = 1; |
| push(@implContentDecls, " setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n"); |
| push(@implContentDecls, "}\n\n"); |
| push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| return; |
| # Skip the rest of the function! |
| } |
| |
| push(@implContentDecls, <<END); |
| ${implClassName}* imp = V8${implClassName}::toNative(info.Holder()); |
| END |
| } |
| |
| my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); |
| if ($attribute->signature->type eq "EventListener") { |
| if ($dataNode->name eq "DOMWindow") { |
| push(@implContentDecls, " if (!imp->document())\n"); |
| push(@implContentDecls, " return;\n"); |
| } |
| } else { |
| my $value = JSValueToNative($attribute->signature, "value"); |
| if ($nativeType =~ /^V8Parameter/) { |
| push(@implContentDecls, " " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n"); |
| } else { |
| push(@implContentDecls, " $nativeType v = $value;\n"); |
| } |
| } |
| |
| my $result = "v"; |
| my $returnType = GetTypeFromSignature($attribute->signature); |
| if (IsRefPtrType($returnType)) { |
| $result = "WTF::getPtr(" . $result . ")"; |
| } |
| |
| my $useExceptions = 1 if @{$attribute->setterExceptions}; |
| |
| if ($useExceptions) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, " ExceptionCode ec = 0;\n"); |
| } |
| |
| if ($implClassName eq "SVGNumber") { |
| push(@implContentDecls, " *imp = $result;\n"); |
| } else { |
| if ($attribute->signature->type eq "EventListener") { |
| my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName); |
| $implIncludes{"V8AbstractEventListener.h"} = 1; |
| push(@implContentDecls, " transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n"); |
| if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") { |
| $implIncludes{"V8EventListenerList.h"} = 1; |
| $implIncludes{"V8WorkerContextErrorHandler.h"} = 1; |
| push(@implContentDecls, " imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)"); |
| } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") { |
| $implIncludes{"V8EventListenerList.h"} = 1; |
| $implIncludes{"V8WindowErrorHandler.h"} = 1; |
| push(@implContentDecls, " imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)"); |
| } else { |
| push(@implContentDecls, " imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)"); |
| } |
| } else { |
| my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute); |
| push(@implContentDecls, " imp->$setterExpressionPrefix$result"); |
| } |
| push(@implContentDecls, ", ec") if $useExceptions; |
| push(@implContentDecls, ");\n"); |
| } |
| |
| if ($useExceptions) { |
| push(@implContentDecls, " if (UNLIKELY(ec))\n"); |
| push(@implContentDecls, " V8Proxy::setDOMException(ec);\n"); |
| } |
| |
| if ($svgNativeType) { |
| if ($useExceptions) { |
| push(@implContentDecls, " if (!ec)\n"); |
| push(@implContentDecls, " wrapper->commitChange();\n"); |
| } else { |
| push(@implContentDecls, " wrapper->commitChange();\n"); |
| } |
| } |
| |
| push(@implContentDecls, " return;\n"); |
| push(@implContentDecls, "}\n\n"); # end of setter |
| push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; |
| } |
| |
| sub GetFunctionTemplateCallbackName |
| { |
| $function = shift; |
| $interfaceName = shift; |
| |
| my $name = $function->signature->name; |
| |
| if ($function->signature->extendedAttributes->{"Custom"} || |
| $function->signature->extendedAttributes->{"V8Custom"}) { |
| if ($function->signature->extendedAttributes->{"Custom"} && |
| $function->signature->extendedAttributes->{"V8Custom"}) { |
| die "Custom and V8Custom should be mutually exclusive!" |
| } |
| return "V8${interfaceName}::${name}Callback"; |
| } else { |
| return "${interfaceName}Internal::${name}Callback"; |
| } |
| } |
| |
| sub GenerateNewFunctionTemplate |
| { |
| $function = shift; |
| $interfaceName = shift; |
| $signature = shift; |
| |
| my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); |
| return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)"; |
| } |
| |
| sub GenerateEventListenerCallback |
| { |
| my $implClassName = shift; |
| my $functionName = shift; |
| my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only"; |
| my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()"; |
| my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove"; |
| |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args) |
| { |
| INC_STATS("DOM.${implClassName}.${functionName}EventListener()"); |
| RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType}); |
| if (listener) { |
| V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue()); |
| ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex); |
| } |
| return v8::Undefined(); |
| } |
| |
| END |
| } |
| |
| sub GenerateParametersCheckExpression |
| { |
| my $numParameters = shift; |
| my $function = shift; |
| |
| my @andExpression = (); |
| push(@andExpression, "args.Length() == $numParameters"); |
| my $parameterIndex = 0; |
| foreach $parameter (@{$function->parameters}) { |
| last if $parameterIndex >= $numParameters; |
| my $value = "args[$parameterIndex]"; |
| my $type = GetTypeFromSignature($parameter); |
| |
| # Only DOMString or wrapper types are checked. |
| # For DOMString, Null, Undefined and any Object are accepted too, as |
| # these are acceptable values for a DOMString argument (any Object can |
| # be converted to a string via .toString). |
| if ($codeGenerator->IsStringType($type)) { |
| push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())"); |
| } elsif ($parameter->extendedAttributes->{"Callback"}) { |
| # For Callbacks only checks if the value is null or object. |
| push(@andExpression, "(${value}->IsNull() || ${value}->IsObject())"); |
| } elsif (IsWrapperType($type)) { |
| push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))"); |
| } |
| |
| $parameterIndex++; |
| } |
| my $res = join(" && ", @andExpression); |
| $res = "($res)" if @andExpression > 1; |
| return $res; |
| } |
| |
| sub GenerateFunctionParametersCheck |
| { |
| my $function = shift; |
| |
| my @orExpression = (); |
| my $numParameters = 0; |
| foreach $parameter (@{$function->parameters}) { |
| if ($parameter->extendedAttributes->{"Optional"}) { |
| push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); |
| } |
| $numParameters++; |
| } |
| push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); |
| return join(" || ", @orExpression); |
| } |
| |
| sub GenerateOverloadedFunctionCallback |
| { |
| my $function = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| |
| # Generate code for choosing the correct overload to call. Overloads are |
| # chosen based on the total number of arguments passed and the type of |
| # values passed in non-primitive argument slots. When more than a single |
| # overload is applicable, precedence is given according to the order of |
| # declaration in the IDL. |
| |
| my $name = $function->signature->name; |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) |
| { |
| INC_STATS(\"DOM.$implClassName.$name\"); |
| END |
| |
| foreach my $overload (@{$function->{overloads}}) { |
| my $parametersCheck = GenerateFunctionParametersCheck($overload); |
| push(@implContentDecls, " if ($parametersCheck)\n"); |
| push(@implContentDecls, " return ${name}$overload->{overloadIndex}Callback(args);\n"); |
| } |
| push(@implContentDecls, <<END); |
| V8Proxy::throwTypeError(); |
| return notHandledByInterceptor(); |
| END |
| push(@implContentDecls, "}\n\n"); |
| } |
| |
| sub GenerateFunctionCallback |
| { |
| my $function = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| |
| my $interfaceName = $dataNode->name; |
| my $name = $function->signature->name; |
| |
| if (@{$function->{overloads}} > 1) { |
| # Append a number to an overloaded method's name to make it unique: |
| $name = $name . $function->{overloadIndex}; |
| } |
| |
| # Adding and removing event listeners are not standard callback behavior, |
| # but they are extremely consistent across the various classes that take event listeners, |
| # so we can generate them as a "special case". |
| if ($name eq "addEventListener") { |
| GenerateEventListenerCallback($implClassName, "add"); |
| return; |
| } elsif ($name eq "removeEventListener") { |
| GenerateEventListenerCallback($implClassName, "remove"); |
| return; |
| } |
| |
| push(@implContentDecls, <<END); |
| static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) |
| { |
| INC_STATS(\"DOM.$implClassName.$name\"); |
| END |
| |
| my $numParameters = @{$function->parameters}; |
| |
| my $requiresAllArguments = $function->signature->extendedAttributes->{"RequiresAllArguments"}; |
| if ($requiresAllArguments) { |
| my $numMandatoryParams = @{$function->parameters}; |
| foreach my $param (reverse(@{$function->parameters})) { |
| if ($param->extendedAttributes->{"Optional"}) { |
| $numMandatoryParams--; |
| } else { |
| last; |
| } |
| } |
| push(@implContentDecls, " if (args.Length() < $numMandatoryParams)\n"); |
| if ($requiresAllArguments eq "Raise") { |
| push(@implContentDecls, " return throwError(\"Not enough arguments\", V8Proxy::SyntaxError);\n"); |
| } else { |
| push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); |
| } |
| } |
| |
| my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName); |
| |
| if ($svgNativeType) { |
| my $nativeClassName = GetNativeType($implClassName); |
| if ($implClassName =~ /List$/) { |
| push(@implContentDecls, " $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n"); |
| } else { |
| push(@implContentDecls, " $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n"); |
| push(@implContentDecls, " if (wrapper->role() == AnimValRole) {\n"); |
| push(@implContentDecls, " V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n"); |
| push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); |
| push(@implContentDecls, " }\n"); |
| my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); |
| push(@implContentDecls, " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"); |
| push(@implContentDecls, " $svgWrappedNativeType* imp = &impInstance;\n"); |
| } |
| } elsif (!$function->signature->extendedAttributes->{"ClassMethod"}) { |
| push(@implContentDecls, <<END); |
| ${implClassName}* imp = V8${implClassName}::toNative(args.Holder()); |
| END |
| } |
| |
| # Check domain security if needed |
| if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} |
| || $interfaceName eq "DOMWindow") |
| && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { |
| # We have not find real use cases yet. |
| push(@implContentDecls, <<END); |
| if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true)) |
| return v8::Handle<v8::Value>(); |
| END |
| } |
| |
| my $raisesExceptions = @{$function->raisesExceptions}; |
| if (!$raisesExceptions) { |
| foreach my $parameter (@{$function->parameters}) { |
| if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) { |
| $raisesExceptions = 1; |
| } |
| } |
| } |
| |
| if ($raisesExceptions) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, " ExceptionCode ec = 0;\n"); |
| push(@implContentDecls, " {\n"); |
| # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors |
| # of objects (like Strings) declared later, causing compile errors. The block scope ends |
| # right before the label 'fail:'. |
| } |
| |
| if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { |
| push(@implContentDecls, <<END); |
| RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, $numParameters)); |
| size_t maxStackSize = imp->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1; |
| RefPtr<ScriptCallStack> callStack(createScriptCallStack(maxStackSize)); |
| if (!callStack) |
| return v8::Undefined(); |
| END |
| $implIncludes{"ScriptArguments.h"} = 1; |
| $implIncludes{"ScriptCallStack.h"} = 1; |
| $implIncludes{"ScriptCallStackFactory.h"} = 1; |
| } |
| if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) { |
| push(@implContentDecls, <<END); |
| if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->getSVGDocument(ec))) |
| return v8::Handle<v8::Value>(); |
| END |
| } |
| |
| my $paramIndex = 0; |
| foreach my $parameter (@{$function->parameters}) { |
| TranslateParameter($parameter); |
| |
| my $parameterName = $parameter->name; |
| |
| # Optional callbacks should be treated differently, because they always have a default value (0), |
| # and we can reduce the number of overloaded functions that take a different number of parameters. |
| if ($parameter->extendedAttributes->{"Optional"} && !$parameter->extendedAttributes->{"Callback"}) { |
| # Generate early call if there are not enough parameters. |
| push(@implContentDecls, " if (args.Length() <= $paramIndex) {\n"); |
| my $functionCall = GenerateFunctionCallString($function, $paramIndex, " " x 2, $implClassName); |
| push(@implContentDecls, $functionCall); |
| push(@implContentDecls, " }\n"); |
| } |
| |
| $implIncludes{"ExceptionCode.h"} = 1; |
| my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex); |
| if ($parameter->extendedAttributes->{"Callback"}) { |
| my $className = GetCallbackClassName($parameter->type); |
| $implIncludes{"$className.h"} = 1; |
| if ($parameter->extendedAttributes->{"Optional"}) { |
| push(@implContentDecls, " RefPtr<" . $parameter->type . "> $parameterName;\n"); |
| push(@implContentDecls, " if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n"); |
| push(@implContentDecls, " if (!args[$paramIndex]->IsObject())\n"); |
| push(@implContentDecls, " return throwError(TYPE_MISMATCH_ERR);\n"); |
| push(@implContentDecls, " $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n"); |
| push(@implContentDecls, " }\n"); |
| } else { |
| push(@implContentDecls, " if (args.Length() <= $paramIndex || !args[$paramIndex]->IsObject())\n"); |
| push(@implContentDecls, " return throwError(TYPE_MISMATCH_ERR);\n"); |
| push(@implContentDecls, " RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n"); |
| } |
| } elsif ($parameter->type eq "SerializedScriptValue") { |
| $implIncludes{"SerializedScriptValue.h"} = 1; |
| push(@implContentDecls, " bool ${parameterName}DidThrow = false;\n"); |
| push(@implContentDecls, " $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], ${parameterName}DidThrow);\n"); |
| push(@implContentDecls, " if (${parameterName}DidThrow)\n"); |
| push(@implContentDecls, " return v8::Undefined();\n"); |
| } elsif (TypeCanFailConversion($parameter)) { |
| push(@implContentDecls, " $nativeType $parameterName = " . |
| JSValueToNative($parameter, "args[$paramIndex]") . ";\n"); |
| push(@implContentDecls, " if (UNLIKELY(!$parameterName)) {\n"); |
| push(@implContentDecls, " ec = TYPE_MISMATCH_ERR;\n"); |
| push(@implContentDecls, " goto fail;\n"); |
| push(@implContentDecls, " }\n"); |
| } elsif ($nativeType =~ /^V8Parameter/) { |
| my $value = JSValueToNative($parameter, "args[$paramIndex]"); |
| push(@implContentDecls, " " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n"); |
| } else { |
| $implIncludes{"V8BindingMacros.h"} = 1; |
| # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an |
| # interface type, then if the incoming value does not implement that interface, a TypeError |
| # is thrown rather than silently passing NULL to the C++ code. |
| # Per the Web IDL and ECMAScript specifications, incoming values can always be converted |
| # to both strings and numbers, so do not throw TypeError if the argument is of these |
| # types. |
| if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) { |
| my $argValue = "args[$paramIndex]"; |
| my $argType = GetTypeFromSignature($parameter); |
| if (IsWrapperType($argType)) { |
| push(@implContentDecls, " if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n"); |
| push(@implContentDecls, " V8Proxy::throwTypeError();\n"); |
| push(@implContentDecls, " return notHandledByInterceptor();\n"); |
| push(@implContentDecls, " }\n"); |
| } |
| } |
| push(@implContentDecls, " EXCEPTION_BLOCK($nativeType, $parameterName, " . |
| JSValueToNative($parameter, "args[$paramIndex]") . ");\n"); |
| } |
| |
| if ($parameter->extendedAttributes->{"IsIndex"}) { |
| push(@implContentDecls, " if (UNLIKELY($parameterName < 0)) {\n"); |
| push(@implContentDecls, " ec = INDEX_SIZE_ERR;\n"); |
| push(@implContentDecls, " goto fail;\n"); |
| push(@implContentDecls, " }\n"); |
| } |
| |
| $paramIndex++; |
| } |
| |
| # Build the function call string. |
| my $callString = GenerateFunctionCallString($function, $paramIndex, " ", $implClassName); |
| push(@implContentDecls, "$callString"); |
| |
| if ($raisesExceptions) { |
| push(@implContentDecls, " }\n"); |
| push(@implContentDecls, " fail:\n"); |
| push(@implContentDecls, " V8Proxy::setDOMException(ec);\n"); |
| push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); |
| } |
| |
| push(@implContentDecls, "}\n\n"); |
| } |
| |
| sub GenerateBatchedAttributeData |
| { |
| my $dataNode = shift; |
| my $interfaceName = $dataNode->name; |
| my $attributes = shift; |
| |
| foreach my $attribute (@$attributes) { |
| my $conditionalString = GenerateConditionalString($attribute->signature); |
| push(@implContent, "#if ${conditionalString}\n") if $conditionalString; |
| GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", ""); |
| push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString; |
| } |
| } |
| |
| sub GenerateSingleBatchedAttribute |
| { |
| my $interfaceName = shift; |
| my $attribute = shift; |
| my $delimiter = shift; |
| my $indent = shift; |
| my $attrName = $attribute->signature->name; |
| my $attrExt = $attribute->signature->extendedAttributes; |
| |
| # Attributes of type SerializedScriptValue are set in the |
| # constructor and don't require callbacks. |
| return if ($attribute->signature->type eq "SerializedScriptValue"); |
| |
| my $accessControl = "v8::DEFAULT"; |
| if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) { |
| $accessControl = "v8::ALL_CAN_READ"; |
| } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) { |
| $accessControl = "v8::ALL_CAN_WRITE"; |
| } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) { |
| $accessControl = "v8::ALL_CAN_READ"; |
| if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) { |
| $accessControl .= " | v8::ALL_CAN_WRITE"; |
| } |
| } |
| if ($attrExt->{"V8DisallowShadowing"}) { |
| $accessControl .= " | v8::PROHIBITS_OVERWRITING"; |
| } |
| $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")"; |
| |
| my $customAccessor = |
| $attrExt->{"Custom"} || |
| $attrExt->{"CustomSetter"} || |
| $attrExt->{"CustomGetter"} || |
| $attrExt->{"V8Custom"} || |
| $attrExt->{"V8CustomSetter"} || |
| $attrExt->{"V8CustomGetter"} || |
| ""; |
| if ($customAccessor eq 1) { |
| # use the naming convension, interface + (capitalize) attr name |
| $customAccessor = $interfaceName . "::" . $attrName; |
| } |
| |
| my $getter; |
| my $setter; |
| my $propAttr = "v8::None"; |
| my $hasCustomSetter = 0; |
| |
| # Check attributes. |
| if ($attrExt->{"DontEnum"}) { |
| $propAttr .= " | v8::DontEnum"; |
| } |
| if ($attrExt->{"V8DisallowShadowing"}) { |
| $propAttr .= " | v8::DontDelete"; |
| } |
| |
| my $on_proto = "0 /* on instance */"; |
| my $data = "0 /* no data */"; |
| |
| # Constructor |
| if ($attribute->signature->type =~ /Constructor$/) { |
| my $constructorType = $codeGenerator->StripModule($attribute->signature->type); |
| $constructorType =~ s/Constructor$//; |
| $implIncludes{"V8${constructorType}.h"} = 1; |
| if ($customAccessor) { |
| $getter = "V8${customAccessor}AccessorGetter"; |
| } else { |
| $data = "&V8${constructorType}::info"; |
| $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; |
| } |
| $setter = "0"; |
| $propAttr = "v8::ReadOnly"; |
| |
| } else { |
| # Default Getter and Setter |
| $getter = "${interfaceName}Internal::${attrName}AttrGetter"; |
| $setter = "${interfaceName}Internal::${attrName}AttrSetter"; |
| |
| # Custom Setter |
| if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { |
| $hasCustomSetter = 1; |
| $setter = "V8${customAccessor}AccessorSetter"; |
| } |
| |
| # Custom Getter |
| if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { |
| $getter = "V8${customAccessor}AccessorGetter"; |
| } |
| } |
| |
| # Replaceable |
| if ($attrExt->{"Replaceable"} && !$hasCustomSetter) { |
| $setter = "0"; |
| # Handle the special case of window.top being marked as Replaceable. |
| # FIXME: Investigate whether we could treat window.top as replaceable |
| # and allow shadowing without it being a security hole. |
| if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) { |
| $propAttr .= " | v8::ReadOnly"; |
| } |
| } |
| |
| # Read only attributes |
| if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) { |
| $setter = "0"; |
| } |
| |
| # An accessor can be installed on the proto |
| if ($attrExt->{"v8OnProto"}) { |
| $on_proto = "1 /* on proto */"; |
| } |
| |
| my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type . |
| "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; |
| |
| push(@implContent, $indent . " \/\/ $commentInfo\n"); |
| push(@implContent, $indent . " {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n"); |
| } |
| |
| sub GenerateImplementationIndexer |
| { |
| my $dataNode = shift; |
| my $indexer = shift; |
| my $interfaceName = $dataNode->name; |
| |
| # FIXME: Figure out what HasNumericIndexGetter is really supposed to do. Right now, it's only set on WebGL-related files. |
| my $hasCustomSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"}; |
| my $hasGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; |
| |
| # FIXME: Find a way to not have to special-case HTMLOptionsCollection. |
| if ($interfaceName eq "HTMLOptionsCollection") { |
| $hasGetter = 1; |
| } |
| |
| # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled, |
| # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide |
| # simplistic, mirrored indexer handling in addition to named property handling. |
| my $isSpecialCase = exists $indexerSpecialCases{$interfaceName}; |
| if ($isSpecialCase) { |
| $hasGetter = 1; |
| if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) { |
| $hasCustomSetter = 1; |
| } |
| } |
| |
| if (!$hasGetter) { |
| return; |
| } |
| |
| $implIncludes{"V8Collection.h"} = 1; |
| |
| my $indexerType = $indexer ? $indexer->type : 0; |
| |
| # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563). |
| if ($interfaceName eq "WebKitCSSKeyframesRule") { |
| $indexerType = "WebKitCSSKeyframeRule"; |
| } |
| |
| # FIXME: The item() getter is not inherited from CSSValueList, seemingly due to the way |
| # the CodeGenerator->AddMethodsConstantsAndAttributesFromParentClasses() method works, |
| # so we need to set the indexerType manually in this case. |
| if ($interfaceName eq "WebKitCSSTransformValue") { |
| $indexerType = "CSSValue"; |
| } |
| |
| if ($indexerType && !$hasCustomSetter) { |
| if ($indexerType eq "DOMString") { |
| my $conversion = $indexer->extendedAttributes->{"ConvertNullStringTo"}; |
| if ($conversion && $conversion eq "Null") { |
| push(@implContent, <<END); |
| setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc); |
| END |
| } else { |
| push(@implContent, <<END); |
| setCollectionStringIndexedGetter<${interfaceName}>(desc); |
| END |
| } |
| } else { |
| push(@implContent, <<END); |
| setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc); |
| END |
| # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type. |
| $implIncludes{"V8${indexerType}.h"} = 1; |
| } |
| |
| return; |
| } |
| |
| my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; |
| my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode); |
| my $setOn = "Instance"; |
| |
| # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow |
| # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to |
| # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set |
| # on the object. |
| if ($interfaceName eq "DOMWindow") { |
| $setOn = "Prototype"; |
| $hasDeleter = 0; |
| } |
| |
| push(@implContent, " desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter"); |
| push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0"); |
| push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment. |
| push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0"); |
| push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator; |
| push(@implContent, ");\n"); |
| } |
| |
| sub GenerateImplementationNamedPropertyGetter |
| { |
| my $dataNode = shift; |
| my $namedPropertyGetter = shift; |
| my $interfaceName = $dataNode->name; |
| my $hasCustomGetter = $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; |
| |
| # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit |
| # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection). |
| if ($interfaceName eq "HTMLOptionsCollection") { |
| $interfaceName = "HTMLCollection"; |
| $hasCustomGetter = 1; |
| } |
| |
| if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") { |
| $hasCustomGetter = 1; |
| } |
| |
| if ($interfaceName eq "HTMLDocument") { |
| $hasCustomGetter = 0; |
| } |
| |
| my $hasGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $hasCustomGetter; |
| if (!$hasGetter) { |
| return; |
| } |
| |
| if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomGetter) { |
| $implIncludes{"V8Collection.h"} = 1; |
| my $type = $namedPropertyGetter->type; |
| push(@implContent, <<END); |
| setCollectionNamedGetter<${interfaceName}, ${type}>(desc); |
| END |
| return; |
| } |
| |
| my $hasSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"}; |
| my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; |
| my $hasEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"}; |
| my $setOn = "Instance"; |
| |
| # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow |
| # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to |
| # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set |
| # on the object. |
| if ($interfaceName eq "DOMWindow") { |
| $setOn = "Prototype"; |
| $hasDeleter = 0; |
| $hasEnumerator = 0; |
| } |
| |
| push(@implContent, " desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, "); |
| push(@implContent, $hasSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, "); |
| # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes. |
| push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, "); |
| push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, "); |
| push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0"); |
| push(@implContent, ");\n"); |
| } |
| |
| sub GenerateImplementationCustomCall |
| { |
| my $dataNode = shift; |
| my $interfaceName = $dataNode->name; |
| my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"}; |
| |
| # FIXME: Remove hard-coded HTMLOptionsCollection reference. |
| if ($interfaceName eq "HTMLOptionsCollection") { |
| $interfaceName = "HTMLCollection"; |
| $hasCustomCall = 1; |
| } |
| |
| if ($hasCustomCall) { |
| push(@implContent, " desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n"); |
| } |
| } |
| |
| sub GenerateImplementationMasqueradesAsUndefined |
| { |
| my $dataNode = shift; |
| if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"}) |
| { |
| push(@implContent, " desc->InstanceTemplate()->MarkAsUndetectable();\n"); |
| } |
| } |
| |
| sub GenerateImplementation |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| my $interfaceName = $dataNode->name; |
| my $visibleInterfaceName = GetVisibleInterfaceName($interfaceName); |
| my $className = "V8$interfaceName"; |
| my $implClassName = $interfaceName; |
| my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; |
| |
| # - Add default header template |
| push(@implFixedHeader, GenerateImplementationContentHeader($dataNode)); |
| |
| $implIncludes{"RuntimeEnabledFeatures.h"} = 1; |
| $implIncludes{"V8Proxy.h"} = 1; |
| $implIncludes{"V8Binding.h"} = 1; |
| $implIncludes{"V8BindingState.h"} = 1; |
| $implIncludes{"V8DOMWrapper.h"} = 1; |
| $implIncludes{"V8IsolatedContext.h"} = 1; |
| |
| AddIncludesForType($interfaceName); |
| |
| my $toActive = IsActiveDomType($interfaceName) ? "${className}::toActiveDOMObject" : "0"; |
| |
| push(@implContentDecls, "namespace WebCore {\n\n"); |
| push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive} };\n\n"); |
| push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n"); |
| push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n"); |
| |
| my $hasConstructors = 0; |
| my $serializedAttribute; |
| # Generate property accessors for attributes. |
| for ($index = 0; $index < @{$dataNode->attributes}; $index++) { |
| $attribute = @{$dataNode->attributes}[$index]; |
| $attrName = $attribute->signature->name; |
| $attrType = $attribute->signature->type; |
| |
| # Generate special code for the constructor attributes. |
| if ($attrType =~ /Constructor$/) { |
| if (!($attribute->signature->extendedAttributes->{"CustomGetter"} || |
| $attribute->signature->extendedAttributes->{"V8CustomGetter"})) { |
| $hasConstructors = 1; |
| } |
| next; |
| } |
| |
| if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") { |
| $attribute->signature->extendedAttributes->{"v8OnProto"} = 1; |
| } |
| |
| # Attributes of type SerializedScriptValue are set in the |
| # constructor and don't require callbacks. |
| if ($attrType eq "SerializedScriptValue") { |
| die "Only one attribute of type SerializedScriptValue supported" if $serializedAttribute; |
| $implIncludes{"SerializedScriptValue.h"} = 1; |
| $serializedAttribute = $attribute; |
| next; |
| } |
| |
| # Do not generate accessor if this is a custom attribute. The |
| # call will be forwarded to a hand-written accessor |
| # implementation. |
| if ($attribute->signature->extendedAttributes->{"Custom"} || |
| $attribute->signature->extendedAttributes->{"V8Custom"}) { |
| next; |
| } |
| |
| # Generate the accessor. |
| if (!($attribute->signature->extendedAttributes->{"CustomGetter"} || |
| $attribute->signature->extendedAttributes->{"V8CustomGetter"})) { |
| GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName); |
| } |
| if (!$attribute->signature->extendedAttributes->{"CustomSetter"} && |
| !$attribute->signature->extendedAttributes->{"V8CustomSetter"} && |
| !$attribute->signature->extendedAttributes->{"Replaceable"} && |
| $attribute->type !~ /^readonly/ && |
| !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) { |
| GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName); |
| } |
| } |
| |
| if ($hasConstructors) { |
| GenerateConstructorGetter($implClassName); |
| } |
| |
| $codeGenerator->LinkOverloadedFunctions($dataNode); |
| |
| my $indexer; |
| my $namedPropertyGetter; |
| # Generate methods for functions. |
| foreach my $function (@{$dataNode->functions}) { |
| if (!($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"})) { |
| GenerateFunctionCallback($function, $dataNode, $implClassName); |
| if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) { |
| GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName); |
| } |
| } |
| |
| if ($function->signature->name eq "item") { |
| $indexer = $function->signature; |
| } |
| |
| if ($function->signature->name eq "namedItem") { |
| $namedPropertyGetter = $function->signature; |
| } |
| |
| # If the function does not need domain security check, we need to |
| # generate an access getter that returns different function objects |
| # for different calling context. |
| if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { |
| GenerateDomainSafeFunctionGetter($function, $implClassName); |
| } |
| } |
| |
| # Attributes |
| my $attributes = $dataNode->attributes; |
| |
| # For the DOMWindow interface we partition the attributes into the |
| # ones that disallows shadowing and the rest. |
| my @disallowsShadowing; |
| # Also separate out attributes that are enabled at runtime so we can process them specially. |
| my @enabledAtRuntime; |
| my @normal; |
| foreach my $attribute (@$attributes) { |
| |
| if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) { |
| push(@disallowsShadowing, $attribute); |
| } elsif ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) { |
| push(@enabledAtRuntime, $attribute); |
| } else { |
| push(@normal, $attribute); |
| } |
| } |
| $attributes = \@normal; |
| # Put the attributes that disallow shadowing on the shadow object. |
| if (@disallowsShadowing) { |
| push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n"); |
| GenerateBatchedAttributeData($dataNode, \@disallowsShadowing); |
| push(@implContent, "};\n"); |
| } |
| |
| my $has_attributes = 0; |
| if (@$attributes) { |
| $has_attributes = 1; |
| push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n"); |
| GenerateBatchedAttributeData($dataNode, $attributes); |
| push(@implContent, "};\n"); |
| } |
| |
| # Setup table of standard callback functions |
| $num_callbacks = 0; |
| $has_callbacks = 0; |
| foreach my $function (@{$dataNode->functions}) { |
| # Only one table entry is needed for overloaded methods: |
| next if $function->{overloadIndex} > 1; |
| |
| my $attrExt = $function->signature->extendedAttributes; |
| # Don't put any nonstandard functions into this table: |
| if ($attrExt->{"V8OnInstance"}) { |
| next; |
| } |
| if ($attrExt->{"ClassMethod"}) { |
| next; |
| } |
| if ($attrExt->{"EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) { |
| next; |
| } |
| if ($attrExt->{"DoNotCheckDomainSecurity"} && |
| ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { |
| next; |
| } |
| if ($attrExt->{"DontEnum"} || $attrExt->{"V8ReadOnly"}) { |
| next; |
| } |
| if (!$has_callbacks) { |
| $has_callbacks = 1; |
| push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n"); |
| } |
| my $name = $function->signature->name; |
| my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); |
| push(@implContent, <<END); |
| {"$name", $callback}, |
| END |
| $num_callbacks++; |
| } |
| push(@implContent, "};\n") if $has_callbacks; |
| |
| # Setup constants |
| my $has_constants = 0; |
| if (@{$dataNode->constants}) { |
| $has_constants = 1; |
| push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n"); |
| } |
| foreach my $constant (@{$dataNode->constants}) { |
| my $name = $constant->name; |
| my $value = $constant->value; |
| # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl |
| # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF". It would be better if we |
| # handled this here, and converted it to a -1 constant in the c++ output. |
| push(@implContent, <<END); |
| {"${name}", static_cast<signed int>($value)}, |
| END |
| } |
| if ($has_constants) { |
| push(@implContent, "};\n"); |
| push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode)); |
| } |
| |
| push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n"); |
| |
| # In namespace WebCore, add generated implementation for 'CanBeConstructed'. |
| if ($dataNode->extendedAttributes->{"CanBeConstructed"} && !$dataNode->extendedAttributes->{"CustomConstructor"} && !$dataNode->extendedAttributes->{"V8CustomConstructor"}) { |
| my $v8ConstructFunction; |
| my $callWith = $dataNode->extendedAttributes->{"CallWith"}; |
| if ($callWith and $callWith eq "ScriptExecutionContext") { |
| $v8ConstructFunction = "constructDOMObjectWithScriptExecutionContext"; |
| } else { |
| $v8ConstructFunction = "constructDOMObject"; |
| } |
| push(@implContent, <<END); |
| v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args) |
| { |
| INC_STATS("DOM.${interfaceName}.Contructor"); |
| return V8Proxy::${v8ConstructFunction}<$interfaceName>(args, &info); |
| } |
| END |
| } |
| |
| my $access_check = ""; |
| if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) { |
| $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));"; |
| } |
| |
| # For the DOMWindow interface, generate the shadow object template |
| # configuration method. |
| if ($implClassName eq "DOMWindow") { |
| push(@implContent, <<END); |
| static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) |
| { |
| batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs)); |
| |
| // Install a security handler with V8. |
| templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info)); |
| templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount); |
| return templ; |
| } |
| END |
| } |
| |
| # find the super descriptor |
| my $parentClassTemplate = ""; |
| foreach (@{$dataNode->parents}) { |
| my $parent = $codeGenerator->StripModule($_); |
| if ($parent eq "EventTarget") { next; } |
| $implIncludes{"V8${parent}.h"} = 1; |
| $parentClassTemplate = "V8" . $parent . "::GetTemplate()"; |
| last; |
| } |
| if (!$parentClassTemplate) { |
| $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()"; |
| } |
| |
| # Generate the template configuration method |
| push(@implContent, <<END); |
| static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) |
| { |
| v8::Local<v8::Signature> defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, |
| END |
| # Set up our attributes if we have them |
| if ($has_attributes) { |
| push(@implContent, <<END); |
| ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs), |
| END |
| } else { |
| push(@implContent, <<END); |
| 0, 0, |
| END |
| } |
| |
| if ($has_callbacks) { |
| push(@implContent, <<END); |
| ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks)); |
| END |
| } else { |
| push(@implContent, <<END); |
| 0, 0); |
| END |
| } |
| |
| if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) { |
| push(@implContent, <<END); |
| desc->SetCallHandler(V8${interfaceName}::constructorCallback); |
| END |
| } |
| |
| if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) { |
| push(@implContent, <<END); |
| v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); |
| v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate(); |
| END |
| } |
| |
| push(@implContent, " $access_check\n"); |
| |
| # Setup the enable-at-runtime attrs if we have them |
| foreach my $runtime_attr (@enabledAtRuntime) { |
| my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature); |
| my $conditionalString = GenerateConditionalString($runtime_attr->signature); |
| push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString; |
| push(@implContent, " if (${enable_function}()) {\n"); |
| push(@implContent, " static const BatchedAttribute attrData =\\\n"); |
| GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", " "); |
| push(@implContent, <<END); |
| configureAttribute(instance, proto, attrData); |
| } |
| END |
| push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; |
| } |
| |
| GenerateImplementationIndexer($dataNode, $indexer); |
| GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter); |
| GenerateImplementationCustomCall($dataNode); |
| GenerateImplementationMasqueradesAsUndefined($dataNode); |
| |
| # Define our functions with Set() or SetAccessor() |
| $total_functions = 0; |
| foreach my $function (@{$dataNode->functions}) { |
| # Only one accessor is needed for overloaded methods: |
| next if $function->{overloadIndex} > 1; |
| |
| $total_functions++; |
| my $attrExt = $function->signature->extendedAttributes; |
| my $name = $function->signature->name; |
| |
| my $property_attributes = "v8::DontDelete"; |
| if ($attrExt->{"DontEnum"}) { |
| $property_attributes .= " | v8::DontEnum"; |
| } |
| if ($attrExt->{"V8ReadOnly"}) { |
| $property_attributes .= " | v8::ReadOnly"; |
| } |
| |
| my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; |
| |
| my $template = "proto"; |
| if ($attrExt->{"V8OnInstance"}) { |
| $template = "instance"; |
| } |
| if ($attrExt->{"ClassMethod"}) { |
| $template = "desc"; |
| } |
| |
| my $conditional = ""; |
| if ($attrExt->{"EnabledAtRuntime"}) { |
| # Only call Set()/SetAccessor() if this method should be enabled |
| $enable_function = GetRuntimeEnableFunctionName($function->signature); |
| $conditional = "if (${enable_function}())\n "; |
| } |
| |
| if ($attrExt->{"DoNotCheckDomainSecurity"} && |
| ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { |
| # Mark the accessor as ReadOnly and set it on the proto object so |
| # it can be shadowed. This is really a hack to make it work. |
| # There are several sceneria to call into the accessor: |
| # 1) from the same domain: "window.open": |
| # the accessor finds the DOM wrapper in the proto chain; |
| # 2) from the same domain: "window.__proto__.open": |
| # the accessor will NOT find a DOM wrapper in the prototype chain |
| # 3) from another domain: "window.open": |
| # the access find the DOM wrapper in the prototype chain |
| # "window.__proto__.open" from another domain will fail when |
| # accessing '__proto__' |
| # |
| # The solution is very hacky and fragile, it really needs to be replaced |
| # by a better solution. |
| $property_attributes .= " | v8::ReadOnly"; |
| push(@implContent, <<END); |
| |
| // $commentInfo |
| ${conditional}$template->SetAccessor(v8::String::New("$name"), ${interfaceName}Internal::${name}AttrGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes)); |
| END |
| $num_callbacks++; |
| next; |
| } |
| |
| my $signature = "defaultSignature"; |
| if ($attrExt->{"V8DoNotCheckSignature"} || $attrExt->{"ClassMethod"}) { |
| $signature = "v8::Local<v8::Signature>()"; |
| } |
| |
| if (RequiresCustomSignature($function)) { |
| $signature = "${name}Signature"; |
| push(@implContent, "\n // Custom Signature '$name'\n", CreateCustomSignature($function)); |
| } |
| |
| # Normal function call is a template |
| my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); |
| |
| if ($property_attributes eq "v8::DontDelete") { |
| $property_attributes = ""; |
| } else { |
| $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)"; |
| } |
| |
| if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") { |
| # Standard type of callback, already created in the batch, so skip it here. |
| next; |
| } |
| |
| push(@implContent, <<END); |
| ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes); |
| END |
| $num_callbacks++; |
| } |
| |
| die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions; |
| |
| if ($has_constants) { |
| push(@implContent, <<END); |
| batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts)); |
| END |
| } |
| |
| # Special cases |
| if ($interfaceName eq "DOMWindow") { |
| push(@implContent, <<END); |
| |
| proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount); |
| desc->SetHiddenPrototype(true); |
| instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount); |
| // Set access check callbacks, but turned off initially. |
| // When a context is detached from a frame, turn on the access check. |
| // Turning on checks also invalidates inline caches of the object. |
| instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false); |
| END |
| } |
| if ($interfaceName eq "HTMLDocument") { |
| push(@implContent, <<END); |
| desc->SetHiddenPrototype(true); |
| END |
| } |
| if ($interfaceName eq "Location") { |
| push(@implContent, <<END); |
| |
| // For security reasons, these functions are on the instance instead |
| // of on the prototype object to ensure that they cannot be overwritten. |
| instance->SetAccessor(v8::String::New("reload"), V8Location::reloadAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); |
| instance->SetAccessor(v8::String::New("replace"), V8Location::replaceAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); |
| instance->SetAccessor(v8::String::New("assign"), V8Location::assignAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); |
| END |
| } |
| |
| my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName); |
| push(@implContent, <<END); |
| |
| // Custom toString template |
| desc->Set(getToStringName(), getToStringTemplate()); |
| return desc; |
| } |
| |
| v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() |
| { |
| static v8::Persistent<v8::FunctionTemplate> ${className}RawCache = createRawTemplate(); |
| return ${className}RawCache; |
| } |
| |
| v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\ |
| { |
| static v8::Persistent<v8::FunctionTemplate> ${className}Cache = Configure${className}Template(GetRawTemplate()); |
| return ${className}Cache; |
| } |
| |
| bool ${className}::HasInstance(v8::Handle<v8::Value> value) |
| { |
| return GetRawTemplate()->HasInstance(value); |
| } |
| |
| END |
| |
| if (IsActiveDomType($interfaceName)) { |
| # MessagePort is handled like an active dom object even though it doesn't inherit |
| # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject. |
| my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)"; |
| push(@implContent, <<END); |
| ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object) |
| { |
| return ${returnValue}; |
| } |
| END |
| } |
| |
| if ($implClassName eq "DOMWindow") { |
| push(@implContent, <<END); |
| v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() |
| { |
| static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache; |
| if (V8DOMWindowShadowObjectCache.IsEmpty()) { |
| V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); |
| ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache); |
| } |
| return V8DOMWindowShadowObjectCache; |
| } |
| END |
| } |
| |
| GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute); |
| |
| push(@implContent, <<END); |
| |
| void ${className}::derefObject(void* object) |
| { |
| END |
| |
| if (IsRefPtrType($interfaceName)) { |
| push(@implContent, <<END); |
| static_cast<${nativeType}*>(object)->deref(); |
| END |
| } |
| |
| push(@implContent, <<END); |
| } |
| |
| } // namespace WebCore |
| END |
| |
| my $conditionalString = GenerateConditionalString($dataNode); |
| 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 GenerateHeaderContentHeader |
| { |
| my $dataNode = shift; |
| my $className = "V8" . $dataNode->name; |
| my $conditionalString = GenerateConditionalString($dataNode); |
| |
| my @headerContentHeader = split("\r", $headerTemplate); |
| |
| push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString; |
| push(@headerContentHeader, "\n#ifndef ${className}" . "_h"); |
| push(@headerContentHeader, "\n#define ${className}" . "_h\n\n"); |
| return @headerContentHeader; |
| } |
| |
| sub GenerateImplementationContentHeader |
| { |
| my $dataNode = shift; |
| my $className = "V8" . $dataNode->name; |
| my $conditionalString = GenerateConditionalString($dataNode); |
| |
| my @implContentHeader = split("\r", $headerTemplate); |
| |
| push(@implContentHeader, "\n#include \"config.h\"\n"); |
| push(@implContentHeader, "#include \"${className}.h\"\n\n"); |
| push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString; |
| return @implContentHeader; |
| } |
| |
| sub GenerateCallbackHeader |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| |
| my $interfaceName = $dataNode->name; |
| my $className = "V8$interfaceName"; |
| |
| |
| # - Add default header template |
| push(@headerContent, GenerateHeaderContentHeader($dataNode)); |
| |
| my @unsortedIncludes = (); |
| push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\""); |
| push(@unsortedIncludes, "#include \"$interfaceName.h\""); |
| push(@unsortedIncludes, "#include \"WorldContextHandle.h\""); |
| push(@unsortedIncludes, "#include <v8.h>"); |
| push(@unsortedIncludes, "#include <wtf/Forward.h>"); |
| push(@headerContent, join("\n", sort @unsortedIncludes)); |
| |
| push(@headerContent, "\n\nnamespace WebCore {\n\n"); |
| push(@headerContent, "class ScriptExecutionContext;\n\n"); |
| push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n"); |
| |
| push(@headerContent, <<END); |
| public: |
| static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context) |
| { |
| ASSERT(value->IsObject()); |
| ASSERT(context); |
| return adoptRef(new ${className}(value->ToObject(), context)); |
| } |
| |
| virtual ~${className}(); |
| |
| END |
| |
| # Functions |
| my $numFunctions = @{$dataNode->functions}; |
| if ($numFunctions > 0) { |
| push(@headerContent, " // Functions\n"); |
| foreach my $function (@{$dataNode->functions}) { |
| my @params = @{$function->parameters}; |
| if (!$function->signature->extendedAttributes->{"Custom"} && |
| !(GetNativeType($function->signature->type) eq "bool")) { |
| push(@headerContent, " COMPILE_ASSERT(false)"); |
| } |
| |
| push(@headerContent, " virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "("); |
| |
| my @args = (); |
| foreach my $param (@params) { |
| push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); |
| } |
| push(@headerContent, join(", ", @args)); |
| push(@headerContent, ");\n"); |
| } |
| } |
| |
| push(@headerContent, <<END); |
| |
| private: |
| ${className}(v8::Local<v8::Object>, ScriptExecutionContext*); |
| |
| v8::Persistent<v8::Object> m_callback; |
| WorldContextHandle m_worldContext; |
| }; |
| |
| END |
| |
| push(@headerContent, "}\n\n"); |
| push(@headerContent, "#endif // $className" . "_h\n\n"); |
| |
| my $conditionalString = GenerateConditionalString($dataNode); |
| push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString; |
| } |
| |
| sub GenerateCallbackImplementation |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| my $interfaceName = $dataNode->name; |
| my $className = "V8$interfaceName"; |
| |
| # - Add default header template |
| push(@implFixedHeader, GenerateImplementationContentHeader($dataNode)); |
| |
| $implIncludes{"ScriptExecutionContext.h"} = 1; |
| $implIncludes{"V8CustomVoidCallback.h"} = 1; |
| $implIncludes{"V8Proxy.h"} = 1; |
| |
| push(@implContent, "#include <wtf/Assertions.h>\n\n"); |
| push(@implContent, "namespace WebCore {\n\n"); |
| push(@implContent, <<END); |
| ${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context) |
| : ActiveDOMCallback(context) |
| , m_callback(v8::Persistent<v8::Object>::New(callback)) |
| , m_worldContext(UseCurrentWorld) |
| { |
| } |
| |
| ${className}::~${className}() |
| { |
| m_callback.Dispose(); |
| } |
| |
| END |
| |
| # Functions |
| my $numFunctions = @{$dataNode->functions}; |
| if ($numFunctions > 0) { |
| push(@implContent, "// Functions\n"); |
| foreach my $function (@{$dataNode->functions}) { |
| my @params = @{$function->parameters}; |
| if ($function->signature->extendedAttributes->{"Custom"} || |
| !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) { |
| next; |
| } |
| |
| AddIncludesForType($function->signature->type); |
| push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "("); |
| |
| my @args = (); |
| foreach my $param (@params) { |
| AddIncludesForType($param->type); |
| push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); |
| } |
| push(@implContent, join(", ", @args)); |
| |
| push(@implContent, ")\n"); |
| push(@implContent, "{\n"); |
| push(@implContent, " if (!canInvokeCallback())\n"); |
| push(@implContent, " return true;\n\n"); |
| push(@implContent, " v8::HandleScope handleScope;\n\n"); |
| push(@implContent, " v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n"); |
| push(@implContent, " if (v8Context.IsEmpty())\n"); |
| push(@implContent, " return true;\n\n"); |
| push(@implContent, " v8::Context::Scope scope(v8Context);\n\n"); |
| |
| @args = (); |
| foreach my $param (@params) { |
| my $paramName = $param->name; |
| push(@implContent, " v8::Handle<v8::Value> ${paramName}Handle = toV8(${paramName});\n"); |
| push(@implContent, " if (${paramName}Handle.IsEmpty()) {\n"); |
| push(@implContent, " CRASH();\n"); |
| push(@implContent, " return true;\n"); |
| push(@implContent, " }\n"); |
| push(@args, " ${paramName}Handle"); |
| } |
| |
| push(@implContent, "\n v8::Handle<v8::Value> argv[] = {\n"); |
| push(@implContent, join(",\n", @args)); |
| push(@implContent, "\n };\n\n"); |
| push(@implContent, " bool callbackReturnValue = false;\n"); |
| push(@implContent, " return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n"); |
| push(@implContent, "}\n"); |
| } |
| } |
| |
| push(@implContent, "\n} // namespace WebCore\n\n"); |
| |
| my $conditionalString = GenerateConditionalString($dataNode); |
| push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString; |
| } |
| |
| sub GenerateToV8Converters |
| { |
| my $dataNode = shift; |
| my $interfaceName = shift; |
| my $className = shift; |
| my $nativeType = shift; |
| my $serializedAttribute = shift; |
| |
| my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName); |
| my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : ""; |
| my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : ""; |
| |
| push(@implContent, <<END); |
| |
| v8::Handle<v8::Object> ${className}::wrapSlow(${nativeType}* impl) |
| { |
| v8::Handle<v8::Object> wrapper; |
| V8Proxy* proxy = 0; |
| END |
| |
| if (IsNodeSubType($dataNode)) { |
| push(@implContent, <<END); |
| if (impl->document()) { |
| proxy = V8Proxy::retrieve(impl->document()->frame()); |
| if (proxy && static_cast<Node*>(impl->document()) == static_cast<Node*>(impl)) { |
| if (proxy->windowShell()->initContextIfNeeded()) { |
| // initContextIfNeeded may have created a wrapper for the object, retry from the start. |
| return ${className}::wrap(impl); |
| } |
| } |
| } |
| |
| END |
| } |
| |
| if (IsNodeSubType($dataNode)) { |
| push(@implContent, <<END); |
| |
| v8::Handle<v8::Context> context; |
| if (proxy) |
| context = proxy->context(); |
| |
| // Enter the node's context and create the wrapper in that context. |
| if (!context.IsEmpty()) |
| context->Enter(); |
| END |
| } |
| |
| push(@implContent, <<END); |
| wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl); |
| END |
| if (IsNodeSubType($dataNode)) { |
| push(@implContent, <<END); |
| // Exit the node's context if it was entered. |
| if (!context.IsEmpty()) |
| context->Exit(); |
| END |
| } |
| |
| push(@implContent, <<END); |
| if (wrapper.IsEmpty()) |
| return wrapper; |
| END |
| push(@implContent, "\n impl->ref();\n") if IsRefPtrType($interfaceName); |
| |
| # Eagerly deserialize attributes of type SerializedScriptValue |
| # while we're in the right context. |
| if ($serializedAttribute) { |
| die "Attribute of type SerializedScriptValue expected" if $serializedAttribute->signature->type ne "SerializedScriptValue"; |
| my $attrName = $serializedAttribute->signature->name; |
| my $attrAttr = "v8::DontDelete"; |
| if ($serializedAttribute->type =~ /^readonly/) { |
| $attrAttr .= " | v8::ReadOnly"; |
| } |
| $attrAttr = "static_cast<v8::PropertyAttribute>($attrAttr)"; |
| my $getterFunc = $codeGenerator->WK_lcfirst($attrName); |
| push(@implContent, <<END); |
| SerializedScriptValue::deserializeAndSetProperty(wrapper, "${attrName}", ${attrAttr}, impl->${getterFunc}()); |
| END |
| } |
| |
| if ($domMapFunction) { |
| push(@implContent, <<END); |
| ${domMapFunction}.set(impl, v8::Persistent<v8::Object>::New(wrapper)); |
| END |
| } |
| |
| push(@implContent, <<END); |
| return wrapper; |
| } |
| END |
| } |
| |
| sub HasCustomToV8Implementation { |
| # FIXME: This subroutine is lame. Probably should be an .idl attribute (CustomToV8)? |
| $dataNode = shift; |
| $interfaceName = shift; |
| |
| # We generate a custom converter (but JSC doesn't) for the following: |
| return 1 if $interfaceName eq "CSSStyleSheet"; |
| return 1 if $interfaceName eq "CanvasPixelArray"; |
| return 1 if $interfaceName eq "DOMStringMap"; |
| return 1 if $interfaceName eq "DOMWindow"; |
| return 1 if $interfaceName eq "DOMTokenList"; |
| return 1 if $interfaceName eq "Element"; |
| return 1 if $interfaceName eq "HTMLDocument"; |
| return 1 if $interfaceName eq "HTMLElement"; |
| return 1 if $interfaceName eq "Location"; |
| return 1 if $interfaceName eq "NamedNodeMap"; |
| return 1 if $interfaceName eq "SVGDocument"; |
| return 1 if $interfaceName eq "SVGElement"; |
| return 1 if $interfaceName eq "ScriptProfile"; |
| return 1 if $interfaceName eq "ScriptProfileNode"; |
| return 1 if $interfaceName eq "WorkerContext"; |
| # We don't generate a custom converter (but JSC does) for the following: |
| return 0 if $interfaceName eq "AbstractWorker"; |
| return 0 if $interfaceName eq "CanvasRenderingContext"; |
| return 0 if $interfaceName eq "SVGElementInstance"; |
| |
| # For everything else, do what JSC does. |
| return $dataNode->extendedAttributes->{"CustomToJS"}; |
| } |
| |
| sub GetDomMapFunction |
| { |
| my $dataNode = shift; |
| my $type = shift; |
| return "getDOMSVGElementInstanceMap()" if $type eq "SVGElementInstance"; |
| return "getDOMNodeMap()" if ($dataNode && IsNodeSubType($dataNode)); |
| return "" if $type eq "DOMImplementation"; |
| return "getActiveDOMObjectMap()" if IsActiveDomType($type); |
| return "getDOMObjectMap()"; |
| } |
| |
| sub IsActiveDomType |
| { |
| # FIXME: Consider making this an .idl attribute. |
| my $type = shift; |
| return 1 if $type eq "EventSource"; |
| return 1 if $type eq "MessagePort"; |
| return 1 if $type eq "XMLHttpRequest"; |
| return 1 if $type eq "WebSocket"; |
| return 1 if $type eq "Worker"; |
| return 1 if $type eq "SharedWorker"; |
| return 1 if $type eq "IDBRequest"; |
| return 1 if $type eq "FileReader"; |
| return 1 if $type eq "FileWriter"; |
| return 0; |
| } |
| |
| sub GetNativeTypeForConversions |
| { |
| my $dataNode = shift; |
| my $type = shift; |
| |
| $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); |
| return $type; |
| } |
| |
| sub GenerateFunctionCallString() |
| { |
| my $function = shift; |
| my $numberOfParameters = shift; |
| my $indent = shift; |
| my $implClassName = shift; |
| |
| my $name = $function->signature->name; |
| my $returnType = GetTypeFromSignature($function->signature); |
| my $nativeReturnType = GetNativeType($returnType, 0); |
| my $result = ""; |
| |
| my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/); |
| $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType; |
| |
| if ($function->signature->extendedAttributes->{"v8implname"}) { |
| $name = $function->signature->extendedAttributes->{"v8implname"}; |
| } |
| |
| if ($function->signature->extendedAttributes->{"ImplementationFunction"}) { |
| $name = $function->signature->extendedAttributes->{"ImplementationFunction"}; |
| } |
| |
| my $functionString = "imp->${name}("; |
| if ($function->signature->extendedAttributes->{"ClassMethod"}) { |
| $functionString = "${implClassName}::${name}("; |
| } |
| |
| my $index = 0; |
| my $hasScriptState = 0; |
| |
| my $callWith = $function->signature->extendedAttributes->{"CallWith"}; |
| if ($callWith) { |
| my $callWithArg = "COMPILE_ASSERT(false)"; |
| if ($callWith eq "DynamicFrame") { |
| $result .= $indent . "Frame* enteredFrame = V8Proxy::retrieveFrameForEnteredContext();\n"; |
| $result .= $indent . "if (!enteredFrame)\n"; |
| $result .= $indent . " return v8::Undefined();\n"; |
| $callWithArg = "enteredFrame"; |
| } elsif ($callWith eq "ScriptState") { |
| $result .= $indent . "EmptyScriptState state;\n"; |
| $callWithArg = "&state"; |
| $hasScriptState = 1; |
| } elsif ($callWith eq "ScriptExecutionContext") { |
| $result .= $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n"; |
| $result .= $indent . "if (!scriptContext)\n"; |
| $result .= $indent . " return v8::Undefined();\n"; |
| $callWithArg = "scriptContext"; |
| } |
| $functionString .= ", " if $index; |
| $functionString .= $callWithArg; |
| $index++; |
| $numberOfParameters++ |
| } |
| |
| foreach my $parameter (@{$function->parameters}) { |
| if ($index eq $numberOfParameters) { |
| last; |
| } |
| $functionString .= ", " if $index; |
| my $paramName = $parameter->name; |
| my $paramType = $parameter->type; |
| |
| if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") { |
| $functionString .= "$paramName.get()"; |
| } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) { |
| $functionString .= "$paramName->propertyReference()"; |
| $result .= $indent . "if (!$paramName) {\n"; |
| $result .= $indent . " V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR);\n"; |
| $result .= $indent . " return v8::Handle<v8::Value>();\n"; |
| $result .= $indent . "}\n"; |
| } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") { |
| $functionString .= "$paramName.get()"; |
| } else { |
| $functionString .= $paramName; |
| } |
| $index++; |
| } |
| |
| if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { |
| $functionString .= ", " if $index; |
| $functionString .= "scriptArguments, callStack"; |
| $index += 2; |
| } |
| |
| if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) { |
| $functionString .= ", " if $index; |
| # FIXME: We need to pass DOMWrapperWorld as a parameter. |
| # See http://trac.webkit.org/changeset/54182 |
| $functionString .= "processingUserGesture()"; |
| $index++; |
| } |
| |
| if (@{$function->raisesExceptions}) { |
| $functionString .= ", " if $index; |
| $functionString .= "ec"; |
| $index++; |
| } |
| $functionString .= ")"; |
| |
| my $return = "result"; |
| my $returnIsRef = IsRefPtrType($returnType); |
| |
| if ($returnType eq "void") { |
| $result .= $indent . "$functionString;\n"; |
| } elsif ($hasScriptState or @{$function->raisesExceptions}) { |
| $result .= $indent . $nativeReturnType . " result = $functionString;\n"; |
| } else { |
| # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary |
| $return = $functionString; |
| $returnIsRef = 0; |
| |
| if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) { |
| $return = "WTF::getPtr(" . $return . ")"; |
| } |
| } |
| |
| if (@{$function->raisesExceptions}) { |
| $result .= $indent . "if (UNLIKELY(ec))\n"; |
| $result .= $indent . " goto fail;\n"; |
| } |
| |
| if ($hasScriptState) { |
| $result .= $indent . "if (state.hadException())\n"; |
| $result .= $indent . " return throwError(state.exception());\n" |
| } |
| |
| if ($isSVGTearOffType) { |
| $implIncludes{"V8$returnType.h"} = 1; |
| $implIncludes{"SVGPropertyTearOff.h"} = 1; |
| my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType); |
| $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)));\n"; |
| return $result; |
| } |
| |
| # If the implementing class is a POD type, commit changes |
| if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) { |
| $result .= $indent . "wrapper->commitChange();\n"; |
| } |
| |
| $return .= ".release()" if ($returnIsRef); |
| $result .= $indent . ReturnNativeToJSValue($function->signature, $return, $indent) . ";\n"; |
| |
| return $result; |
| } |
| |
| |
| sub GetTypeFromSignature |
| { |
| my $signature = shift; |
| |
| return $codeGenerator->StripModule($signature->type); |
| } |
| |
| |
| sub GetNativeTypeFromSignature |
| { |
| my $signature = shift; |
| my $parameterIndex = shift; |
| |
| my $type = GetTypeFromSignature($signature); |
| |
| if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) { |
| # Special-case index arguments because we need to check that they aren't < 0. |
| return "int"; |
| } |
| |
| $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0); |
| |
| if ($parameterIndex >= 0 && $type eq "V8Parameter") { |
| my $mode = ""; |
| if ($signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}) { |
| $mode = "WithUndefinedOrNullCheck"; |
| } elsif ($signature->extendedAttributes->{"ConvertNullToNullString"} || $signature->extendedAttributes->{"Reflect"}) { |
| $mode = "WithNullCheck"; |
| } |
| $type .= "<$mode>"; |
| } |
| |
| return $type; |
| } |
| |
| sub IsRefPtrType |
| { |
| my $type = shift; |
| |
| 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; |
| } |
| |
| sub GetNativeType |
| { |
| my $type = shift; |
| my $isParameter = shift; |
| |
| 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 "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter; |
| 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 "String" if $type eq "DOMString"; |
| return "Range::CompareHow" if $type eq "CompareHow"; |
| return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType"; |
| return "DOMTimeStamp" if $type eq "DOMTimeStamp"; |
| return "unsigned" if $type eq "unsigned int"; |
| 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"; |
| |
| return "String" if $type eq "DOMUserData"; # FIXME: Temporary hack? |
| |
| # 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 "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; |
| |
| return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener"; |
| |
| # Default, assume native type is a pointer with same type name as idl type |
| return "${type}*"; |
| } |
| |
| sub GetNativeTypeForCallbacks |
| { |
| my $type = shift; |
| return "const String&" if $type eq "DOMString"; |
| |
| # Callbacks use raw pointers, so pass isParameter = 1 |
| return GetNativeType($type, 1); |
| } |
| |
| sub TranslateParameter |
| { |
| my $signature = shift; |
| |
| # The IDL uses some pseudo-types which don't really exist. |
| if ($signature->type eq "TimeoutHandler") { |
| $signature->type("DOMString"); |
| } |
| } |
| |
| sub TypeCanFailConversion |
| { |
| my $signature = shift; |
| |
| my $type = GetTypeFromSignature($signature); |
| |
| $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr"; |
| return 1 if $type eq "Attr"; |
| return 1 if $type eq "VoidCallback"; |
| return 1 if $type eq "IDBKey"; |
| return 0; |
| } |
| |
| sub JSValueToNative |
| { |
| my $signature = shift; |
| my $value = shift; |
| |
| my $type = GetTypeFromSignature($signature); |
| |
| return "$value" if $type eq "JSObject"; |
| return "$value->BooleanValue()" if $type eq "boolean"; |
| return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double"; |
| |
| return "toInt32($value)" if $type eq "long" or $type eq "short"; |
| return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short"; |
| return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long"; |
| return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; |
| return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType"; |
| return "toWebCoreDate($value)" if $type eq "Date"; |
| |
| if ($type eq "DOMString" or $type eq "DOMUserData") { |
| return $value; |
| } |
| |
| die "Unexpected SerializedScriptValue" if $type eq "SerializedScriptValue"; |
| |
| if ($type eq "IDBKey") { |
| $implIncludes{"IDBBindingUtilities.h"} = 1; |
| $implIncludes{"IDBKey.h"} = 1; |
| return "createIDBKeyFromValue($value)"; |
| } |
| |
| if ($type eq "OptionsObject") { |
| $implIncludes{"OptionsObject.h"} = 1; |
| return $value; |
| } |
| |
| if ($type eq "DOMObject") { |
| $implIncludes{"ScriptValue.h"} = 1; |
| return "ScriptValue($value)"; |
| } |
| |
| if ($type eq "NodeFilter") { |
| return "V8DOMWrapper::wrapNativeNodeFilter($value)"; |
| } |
| |
| if ($type eq "MediaQueryListListener") { |
| $implIncludes{"MediaQueryListListener.h"} = 1; |
| return "MediaQueryListListener::create(" . $value . ")"; |
| } |
| |
| # Default, assume autogenerated type conversion routines |
| if ($type eq "EventTarget") { |
| $implIncludes{"V8Node.h"} = 1; |
| |
| # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget. |
| return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; |
| } |
| |
| if ($type eq "XPathNSResolver") { |
| return "V8DOMWrapper::getXPathNSResolver($value)"; |
| } |
| |
| AddIncludesForType($type); |
| |
| if (IsDOMNodeType($type)) { |
| $implIncludes{"V8${type}.h"} = 1; |
| |
| # Perform type checks on the parameter, if it is expected Node type, |
| # return NULL. |
| return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; |
| } else { |
| $implIncludes{"V8$type.h"} = 1; |
| |
| # Perform type checks on the parameter, if it is expected Node type, |
| # return NULL. |
| return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; |
| } |
| } |
| |
| sub GetV8HeaderName |
| { |
| my $type = shift; |
| return "V8Event.h" if $type eq "DOMTimeStamp"; |
| return "EventListener.h" if $type eq "EventListener"; |
| return "EventTarget.h" if $type eq "EventTarget"; |
| return "SerializedScriptValue.h" if $type eq "SerializedScriptValue"; |
| return "ScriptValue.h" if $type eq "DOMObject"; |
| return "V8${type}.h"; |
| } |
| |
| sub CreateCustomSignature |
| { |
| my $function = shift; |
| my $count = @{$function->parameters}; |
| my $name = $function->signature->name; |
| my $result = " const int ${name}Argc = ${count};\n" . |
| " v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { "; |
| my $first = 1; |
| foreach my $parameter (@{$function->parameters}) { |
| if ($first) { $first = 0; } |
| else { $result .= ", "; } |
| if (IsWrapperType($parameter->type)) { |
| if ($parameter->type eq "XPathNSResolver") { |
| # Special case for XPathNSResolver. All other browsers accepts a callable, |
| # so, even though it's against IDL, accept objects here. |
| $result .= "v8::Handle<v8::FunctionTemplate>()"; |
| } else { |
| my $type = $parameter->type; |
| my $header = GetV8HeaderName($type); |
| $implIncludes{$header} = 1; |
| $result .= "V8${type}::GetRawTemplate()"; |
| } |
| } else { |
| $result .= "v8::Handle<v8::FunctionTemplate>()"; |
| } |
| } |
| $result .= " };\n"; |
| $result .= " v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n"; |
| return $result; |
| } |
| |
| |
| sub RequiresCustomSignature |
| { |
| my $function = shift; |
| # No signature needed for Custom function |
| if ($function->signature->extendedAttributes->{"Custom"} || |
| $function->signature->extendedAttributes->{"V8Custom"}) { |
| return 0; |
| } |
| # No signature needed for overloaded function |
| if (@{$function->{overloads}} > 1) { |
| return 0; |
| } |
| # Type checking is performed in the generated code |
| if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) { |
| return 0; |
| } |
| foreach my $parameter (@{$function->parameters}) { |
| if ($parameter->extendedAttributes->{"Optional"} || $parameter->extendedAttributes->{"Callback"}) { |
| return 0; |
| } |
| } |
| |
| foreach my $parameter (@{$function->parameters}) { |
| if (IsWrapperType($parameter->type)) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| # FIXME: Sort this array. |
| my %non_wrapper_types = ( |
| 'float' => 1, |
| 'double' => 1, |
| 'int' => 1, |
| 'unsigned int' => 1, |
| 'short' => 1, |
| 'unsigned short' => 1, |
| 'long' => 1, |
| 'unsigned long' => 1, |
| 'boolean' => 1, |
| 'long long' => 1, |
| 'unsigned long long' => 1, |
| 'DOMString' => 1, |
| 'CompareHow' => 1, |
| 'SerializedScriptValue' => 1, |
| 'SVGPaintType' => 1, |
| 'DOMTimeStamp' => 1, |
| 'JSObject' => 1, |
| 'DOMObject' => 1, |
| 'EventTarget' => 1, |
| 'NodeFilter' => 1, |
| 'EventListener' => 1, |
| 'IDBKey' => 1, |
| 'OptionsObject' => 1, |
| 'Date' => 1, |
| 'MediaQueryListListener' => 1 |
| ); |
| |
| |
| sub IsWrapperType |
| { |
| my $type = $codeGenerator->StripModule(shift); |
| return !($non_wrapper_types{$type}); |
| } |
| |
| sub IsDOMNodeType |
| { |
| my $type = shift; |
| |
| return 1 if $type eq 'Attr'; |
| return 1 if $type eq 'CDATASection'; |
| return 1 if $type eq 'Comment'; |
| return 1 if $type eq 'Document'; |
| return 1 if $type eq 'DocumentFragment'; |
| return 1 if $type eq 'DocumentType'; |
| return 1 if $type eq 'Element'; |
| return 1 if $type eq 'EntityReference'; |
| return 1 if $type eq 'HTMLCanvasElement'; |
| return 1 if $type eq 'HTMLDocument'; |
| return 1 if $type eq 'HTMLElement'; |
| return 1 if $type eq 'HTMLFormElement'; |
| return 1 if $type eq 'HTMLTableCaptionElement'; |
| return 1 if $type eq 'HTMLTableSectionElement'; |
| return 1 if $type eq 'Node'; |
| return 1 if $type eq 'ProcessingInstruction'; |
| return 1 if $type eq 'SVGElement'; |
| return 1 if $type eq 'SVGDocument'; |
| return 1 if $type eq 'SVGSVGElement'; |
| return 1 if $type eq 'SVGUseElement'; |
| return 1 if $type eq 'Text'; |
| |
| return 0; |
| } |
| |
| |
| sub ReturnNativeToJSValue |
| { |
| my $signature = shift; |
| my $value = shift; |
| my $indent = shift; |
| my $type = GetTypeFromSignature($signature); |
| |
| return "return v8Boolean($value)" if $type eq "boolean"; |
| return "return v8::Handle<v8::Value>()" if $type eq "void"; # equivalent to v8::Undefined() |
| |
| # For all the types where we use 'int' as the representation type, |
| # we use Integer::New which has a fast Smi conversion check. |
| my $nativeType = GetNativeType($type); |
| return "return v8::Integer::New($value)" if $nativeType eq "int"; |
| return "return v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned"; |
| |
| return "return v8DateOrNull($value)" if $type eq "Date"; |
| # long long and unsigned long long are not representable in ECMAScript. |
| return "return v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp"; |
| return "return v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType"; |
| return "return $value.v8Value()" if $nativeType eq "ScriptValue"; |
| |
| if ($codeGenerator->IsStringType($type)) { |
| my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"}; |
| if (defined $conv) { |
| return "return v8StringOrNull($value)" if $conv eq "Null"; |
| return "return v8StringOrUndefined($value)" if $conv eq "Undefined"; |
| return "return v8StringOrFalse($value)" if $conv eq "False"; |
| |
| die "Unknown value for ConvertNullStringTo extended attribute"; |
| } |
| $conv = $signature->extendedAttributes->{"ConvertScriptString"}; |
| return "return v8StringOrNull($value)" if $conv; |
| return "return v8String($value)"; |
| } |
| |
| AddIncludesForType($type); |
| |
| # special case for non-DOM node interfaces |
| if (IsDOMNodeType($type)) { |
| return "return toV8(${value}" . ($signature->extendedAttributes->{"ReturnsNew"} ? ", true)" : ")"); |
| } |
| |
| if ($type eq "EventTarget") { |
| return "return V8DOMWrapper::convertEventTargetToV8Object($value)"; |
| } |
| |
| if ($type eq "EventListener") { |
| $implIncludes{"V8AbstractEventListener.h"} = 1; |
| return "return ${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null())"; |
| } |
| |
| if ($type eq "SerializedScriptValue") { |
| $implIncludes{"$type.h"} = 1; |
| return "return $value->deserialize()"; |
| } |
| |
| $implIncludes{"wtf/RefCounted.h"} = 1; |
| $implIncludes{"wtf/RefPtr.h"} = 1; |
| $implIncludes{"wtf/GetPtr.h"} = 1; |
| |
| return "return toV8($value)"; |
| } |
| |
| # Internal helper |
| sub WriteData |
| { |
| if (defined($IMPL)) { |
| # Write content to file. |
| print $IMPL @implContentHeader; |
| |
| print $IMPL @implFixedHeader; |
| |
| foreach my $implInclude (sort keys(%implIncludes)) { |
| my $checkType = $implInclude; |
| $checkType =~ s/\.h//; |
| |
| if ($implInclude =~ /wtf/) { |
| print $IMPL "#include \<$implInclude\>\n"; |
| } else { |
| print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType); |
| } |
| } |
| |
| print $IMPL "\n"; |
| print $IMPL @implContentDecls; |
| print $IMPL @implContent; |
| close($IMPL); |
| undef($IMPL); |
| |
| %implIncludes = (); |
| @implFixedHeader = (); |
| @implHeaderContent = (); |
| @implContentDecls = (); |
| @implContent = (); |
| } |
| |
| if (defined($HEADER)) { |
| # Write content to file. |
| print $HEADER @headerContent; |
| close($HEADER); |
| undef($HEADER); |
| |
| @headerContent = (); |
| } |
| } |
| |
| sub GetVisibleInterfaceName |
| { |
| my $interfaceName = shift; |
| |
| return "DOMException" if $interfaceName eq "DOMCoreException"; |
| return "FormData" if $interfaceName eq "DOMFormData"; |
| return $interfaceName; |
| } |
| |
| sub GetCallbackClassName |
| { |
| my $interfaceName = shift; |
| |
| return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback"; |
| return "V8$interfaceName"; |
| } |
| |
| sub ConvertToV8Parameter |
| { |
| my $signature = shift; |
| my $nativeType = shift; |
| my $variableName = shift; |
| my $value = shift; |
| my $suffix = shift; |
| |
| die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/; |
| if ($signature->type eq "DOMString") { |
| $implIncludes{"V8BindingMacros.h"} = 1; |
| my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK"; |
| $macro .= "_$suffix" if $suffix; |
| return "$macro($nativeType, $variableName, $value);" |
| } else { |
| # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData" |
| return "$nativeType $variableName($value, true);"; |
| } |
| } |
| |
| # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled. |
| sub GetRuntimeEnableFunctionName |
| { |
| my $signature = shift; |
| |
| # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method. |
| return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "1"); |
| |
| # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled(). |
| return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled"; |
| } |
| |
| sub DebugPrint |
| { |
| my $output = shift; |
| |
| print $output; |
| print "\n"; |
| } |