| |
| # 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> |
| # |
| # 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 File::stat; |
| use Digest::MD5; |
| |
| my $module = ""; |
| my $outputDir = ""; |
| |
| my @headerContent = (); |
| my @implContentHeader = (); |
| my @implFixedHeader = (); |
| my @implContent = (); |
| my @implContentDecls = (); |
| my %implIncludes = (); |
| |
| 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; |
| |
| bless($reference, $object); |
| return $reference; |
| } |
| |
| sub finish |
| { |
| my $object = shift; |
| |
| # Commit changes! |
| $object->WriteData(); |
| } |
| |
| # Workaround for V8 bindings difference where RGBColor is not a POD type. |
| sub IsPodType |
| { |
| my $type = shift; |
| return $codeGenerator->IsPodType($type); |
| } |
| |
| # Params: 'domClass' struct |
| sub GenerateInterface |
| { |
| my $object = shift; |
| my $dataNode = shift; |
| my $defines = shift; |
| |
| # Start actual generation |
| $object->GenerateHeader($dataNode); |
| $object->GenerateImplementation($dataNode); |
| |
| my $name = $dataNode->name; |
| |
| # Open files for writing |
| my $headerFileName = "$outputDir/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 AvoidInclusionOfType |
| { |
| my $type = shift; |
| |
| # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist. |
| return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix"; |
| return 0; |
| } |
| |
| 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 !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{"AtomicString.h"} = 1; |
| } |
| } |
| |
| sub AddIncludesForSVGAnimatedType |
| { |
| my $type = shift; |
| $type =~ s/SVGAnimated//; |
| |
| if ($type eq "Point" or $type eq "Rect") { |
| $implIncludes{"Float$type.h"} = 1; |
| } elsif ($type eq "String") { |
| $implIncludes{"PlatformString.h"} = 1; |
| } |
| |
| $implIncludes{"SVGAnimatedTemplate.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) { |
| return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; |
| } else { |
| return ""; |
| } |
| } |
| |
| 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"}; |
| my $conditionalString = GenerateConditionalString($dataNode); |
| |
| # - Add default header template |
| @headerContent = split("\r", $headerTemplate); |
| |
| push(@headerContent, "\n#if ${conditionalString}\n\n") if $conditionalString; |
| push(@headerContent, "\n#ifndef $className" . "_H"); |
| push(@headerContent, "\n#define $className" . "_H\n\n"); |
| |
| # Get correct pass/store types respecting PODType flag |
| my $podType = $dataNode->extendedAttributes->{"PODType"}; |
| |
| push(@headerContent, "#include \"$podType.h\"\n") if $podType and ($podType ne "double" and $podType ne "float" and $podType ne "RGBA32"); |
| |
| push(@headerContent, "#include <v8.h>\n"); |
| push(@headerContent, "#include <wtf/HashMap.h>\n"); |
| push(@headerContent, "#include \"StringHash.h\"\n"); |
| push(@headerContent, "#include \"WrapperTypeInfo.h\"\n"); |
| push(@headerContent, GetHeaderClassInclude($implClassName)); |
| push(@headerContent, "\nnamespace WebCore {\n"); |
| if ($podType) { |
| push(@headerContent, "\ntemplate<typename PODType> class V8SVGPODTypeWrapper;\n"); |
| } |
| push(@headerContent, "\nclass $className {\n"); |
| |
| my $nativeType = GetNativeTypeForConversions($interfaceName); |
| if ($podType) { |
| $nativeType = "V8SVGPODTypeWrapper<${nativeType} >"; |
| } |
| my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : ""; |
| 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>); |
| 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 |
| } |
| |
| 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->{"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); |
| }; |
| |
| v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter}); |
| END |
| if (IsRefPtrType($implClassName)) { |
| push(@headerContent, <<END); |
| v8::Handle<v8::Value> toV8(PassRefPtr<${nativeType} >${forceNewObjectParameter}); |
| END |
| } |
| |
| push(@headerContent, "}\n\n"); |
| push(@headerContent, "#endif // $className" . "_H\n"); |
| |
| 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"); |
| if ($name eq "HTMLDocument") { |
| push(@customInternalFields, ("markerIndex", "shadowIndex")); |
| } |
| } elsif (IsSubType($dataNode, "StyleSheet") || $name eq "NamedNodeMap") { |
| push(@customInternalFields, "ownerNodeIndex"); |
| } elsif ($name eq "MessageChannel") { |
| push(@customInternalFields, ("port1Index", "port2Index")); |
| } elsif ($name eq "DOMWindow") { |
| push(@customInternalFields, ("consoleIndex", "historyIndex", "locationbarIndex", "menubarIndex", "navigatorIndex", |
| "personalbarIndex", "screenIndex", "scrollbarsIndex", "selectionIndex", "statusbarIndex", "toolbarIndex", "locationIndex", |
| "domSelectionIndex", "enteredIsolatedWorldIndex")); |
| } |
| return @customInternalFields; |
| } |
| |
| sub GetHeaderClassInclude |
| { |
| my $className = shift; |
| if ($className =~ /SVGPathSeg/) { |
| $className =~ s/Abs|Rel//; |
| } |
| return "" if (AvoidInclusionOfType($className)); |
| return "#include \"SVGAnimatedTemplate.h\"\n" if ($codeGenerator->IsSVGAnimatedType($className)); |
| return "#include \"${className}.h\"\n"; |
| } |
| |
| 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, |
| "HTMLDocument" => 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 "HTMLSelectElement" || $interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") { |
| $hasCustomNamedGetter = 1; |
| } |
| my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName}; |
| |
| if ($hasCustomIndexedGetter || $isIndexerSpecialCase) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t index, const v8::AccessorInfo& info); |
| END |
| } |
| |
| if ($isIndexerSpecialCase || $hasCustomIndexedSetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> indexedPropertySetter(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info); |
| END |
| } |
| if ($hasCustomDeleters) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t index, const v8::AccessorInfo& info); |
| END |
| } |
| if ($hasCustomNamedGetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info); |
| END |
| } |
| if ($hasCustomNamedSetter) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info); |
| END |
| } |
| if ($hasCustomDeleters || $interfaceName eq "HTMLDocument") { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String> name, const v8::AccessorInfo& info); |
| END |
| } |
| if ($hasCustomEnumerator) { |
| push(@headerContent, <<END); |
| static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo& info); |
| 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> private_template = 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 private_template->GetFunction(); |
| } |
| ${implClassName}* imp = ${className}::toNative(holder); |
| if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { |
| static v8::Persistent<v8::FunctionTemplate> shared_template = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); |
| return shared_template->GetFunction(); |
| } |
| return private_template->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 $attrIsPodType = IsPodType($attrType); |
| |
| my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1); |
| my $isPodType = IsPodType($implClassName); |
| my $skipContext = 0; |
| |
| if ($isPodType) { |
| $implClassName = GetNativeType($implClassName); |
| $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; |
| } |
| |
| # Special case: SVGZoomEvent's attributes are all read-only |
| if ($implClassName eq "SVGZoomEvent") { |
| $attrIsPodType = 0; |
| $skipContext = 1; |
| } |
| |
| # Special case: SVGSVGEelement::viewport is read-only |
| if (($implClassName eq "SVGSVGElement") and ($attrName eq "viewport")) { |
| $attrIsPodType = 0; |
| $skipContext = 1; |
| } |
| |
| # Special case for SVGColor |
| if (($implClassName eq "SVGColor") and ($attrName eq "rgbColor")) { |
| $attrIsPodType = 0; |
| } |
| |
| my $getterStringUsesImp = $implClassName ne "float"; |
| |
| # Getter |
| 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 ($isPodType) { |
| push(@implContentDecls, <<END); |
| V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8SVGPODTypeWrapper<$implClassName>::toNative(info.Holder()); |
| $implClassName imp_instance = *imp_wrapper; |
| END |
| if ($getterStringUsesImp) { |
| push(@implContentDecls, <<END); |
| $implClassName* imp = &imp_instance; |
| 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"}; |
| if ($getterStringUsesImp && $reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { |
| # Generate super-compact call for regular attribute getter: |
| my $contentAttributeName = $reflect eq "1" ? $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"); |
| 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())) return v8::Handle<v8::Value>();\n\n"); |
| } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) { |
| push(@implContentDecls, " if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->contentDocument())) return v8::Handle<v8::Value>();\n\n"); |
| } |
| |
| my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType); |
| if ($useExceptions) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, " ExceptionCode ec = 0;\n"); |
| } |
| |
| if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) { |
| $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; |
| } |
| |
| my $getterFunc = $codeGenerator->WK_lcfirst($attrName); |
| |
| if ($codeGenerator->IsSVGAnimatedType($attribute->signature->type)) { |
| # Some SVGFE*Element.idl use 'operator' as attribute name; rewrite as '_operator' to avoid clashes with C/C++ |
| $getterFunc = "_" . $getterFunc if ($attrName =~ /operator/); |
| $getterFunc .= "Animated"; |
| } |
| |
| my $returnType = GetTypeFromSignature($attribute->signature); |
| |
| my $getterString; |
| if ($getterStringUsesImp) { |
| my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; |
| my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"}; |
| if ($reflect || $reflectURL) { |
| my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL); |
| my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); |
| $implIncludes{"${namespace}.h"} = 1; |
| my $getAttributeFunctionName = $reflectURL ? "getURLAttribute" : "getAttribute"; |
| $getterString = "imp->$getAttributeFunctionName(${namespace}::${contentAttributeName}Attr"; |
| } else { |
| $getterString = "imp->$getterFunc("; |
| } |
| $getterString .= "ec" if $useExceptions; |
| $getterString .= ")"; |
| if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { |
| $getterString .= ".toInt()"; |
| } |
| } else { |
| $getterString = "imp_instance"; |
| } |
| |
| my $result; |
| my $wrapper; |
| |
| if ($attrIsPodType) { |
| $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; |
| |
| my $getter = $getterString; |
| $getter =~ s/imp->//; |
| $getter =~ s/\(\)//; |
| my $setter = "set" . $codeGenerator->WK_ucfirst($getter); |
| |
| my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName); |
| if (not $implClassIsAnimatedType and $codeGenerator->IsPodTypeWithWriteableProperties($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { |
| if (IsPodType($implClassName)) { |
| my $wrapper = "V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>::create($getterString, imp_wrapper)"; |
| push(@implContentDecls, " RefPtr<V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName> > wrapper = $wrapper;\n"); |
| } else { |
| my $wrapper = "V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>::create(imp, &${implClassName}::$getter, &${implClassName}::$setter)"; |
| push(@implContentDecls, " RefPtr<V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName> > wrapper = $wrapper;\n"); |
| } |
| } else { |
| if ($implClassIsAnimatedType) { |
| # We can't hash member function pointers, so instead generate |
| # some hashing material based on the names of the methods. |
| my $hashhex = substr(Digest::MD5::md5_hex("${implClassName}::$getter ${implClassName}::$setter)"), 0, 8); |
| my $wrapper = "V8SVGDynamicPODTypeWrapperCache<$nativeType, $implClassName>::lookupOrCreateWrapper(imp, &${implClassName}::$getter, &${implClassName}::$setter, 0x$hashhex)"; |
| push(@implContentDecls, " RefPtr<V8SVGPODTypeWrapper<" . $nativeType . "> > wrapper = $wrapper;\n"); |
| } else { |
| my $wrapper = GenerateSVGStaticPodTypeWrapper($returnType, $getterString); |
| push(@implContentDecls, " RefPtr<V8SVGStaticPODTypeWrapper<" . $nativeType . "> > wrapper = $wrapper;\n"); |
| } |
| } |
| |
| } else { |
| 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) { |
| push(@implContentDecls, " $nativeType v = "); |
| push(@implContentDecls, "$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; |
| } |
| } |
| |
| if (IsSVGTypeNeedingContextParameter($attrType) && !$skipContext) { |
| if ($attrIsPodType) { |
| push(@implContentDecls, GenerateSVGContextAssignment($implClassName, "wrapper.get()", " ")); |
| } else { |
| push(@implContentDecls, GenerateSVGContextRetrieval($implClassName, " ")); |
| # The templating associated with passing withSVGContext()'s return value directly into toV8 can get compilers confused, |
| # so just manually set the return value to a PassRefPtr of the expected type. |
| push(@implContentDecls, " PassRefPtr<$attrType> resultAsPassRefPtr = V8Proxy::withSVGContext($result, context);\n"); |
| $result = "resultAsPassRefPtr"; |
| } |
| } |
| |
| if ($attrIsPodType) { |
| $implIncludes{"V8${attrType}.h"} = 1; |
| push(@implContentDecls, " return toV8(wrapper.release().get());\n"); |
| } else { |
| push(@implContentDecls, " " . ReturnNativeToJSValue($attribute->signature, $result, " ").";\n"); |
| } |
| |
| push(@implContentDecls, "}\n\n"); # end of getter |
| } |
| |
| sub GenerateNormalAttrSetter |
| { |
| my $attribute = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| my $interfaceName = shift; |
| |
| my $attrExt = $attribute->signature->extendedAttributes; |
| |
| 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"); |
| |
| my $isPodType = IsPodType($implClassName); |
| |
| if ($isPodType) { |
| $implClassName = GetNativeType($implClassName); |
| $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; |
| push(@implContentDecls, " V8SVGPODTypeWrapper<$implClassName>* wrapper = V8SVGPODTypeWrapper<$implClassName>::toNative(info.Holder());\n"); |
| push(@implContentDecls, " $implClassName imp_instance = *wrapper;\n"); |
| push(@implContentDecls, " $implClassName* imp = &imp_instance;\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"}; |
| my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"}; |
| if (($reflect || $reflectURL) && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { |
| # Generate super-compact call for regular attribute setter: |
| my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL); |
| my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); |
| $implIncludes{"${namespace}.h"} = 1; |
| push(@implContentDecls, " setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n"); |
| push(@implContentDecls, "}\n\n"); |
| 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 { |
| push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n"); |
| } |
| |
| my $result = ""; |
| if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { |
| $result .= "WebCore::String::number("; |
| } |
| $result .= "v"; |
| if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { |
| $result .= ")"; |
| } |
| my $returnType = GetTypeFromSignature($attribute->signature); |
| if (IsRefPtrType($returnType)) { |
| $result = "WTF::getPtr(" . $result . ")"; |
| } |
| |
| my $useExceptions = 1 if @{$attribute->setterExceptions} and !($isPodType); |
| |
| if ($useExceptions) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, " ExceptionCode ec = 0;\n"); |
| } |
| |
| if ($implClassName eq "float") { |
| push(@implContentDecls, " *imp = $result;\n"); |
| } else { |
| my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName); |
| my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; |
| my $reflectURL = $attribute->signature->extendedAttributes->{"ReflectURL"}; |
| if ($reflect || $reflectURL) { |
| my $contentAttributeName = ($reflect || $reflectURL) eq "1" ? $attrName : ($reflect || $reflectURL); |
| my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); |
| $implIncludes{"${namespace}.h"} = 1; |
| push(@implContentDecls, " imp->setAttribute(${namespace}::${contentAttributeName}Attr, $result"); |
| } elsif ($attribute->signature->type eq "EventListener") { |
| $implIncludes{"V8AbstractEventListener.h"} = 1; |
| push(@implContentDecls, " transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n"); |
| push(@implContentDecls, " imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)"); |
| } else { |
| push(@implContentDecls, " imp->set$implSetterFunctionName($result"); |
| } |
| push(@implContentDecls, ", ec") if $useExceptions; |
| push(@implContentDecls, ");\n"); |
| } |
| |
| if ($useExceptions) { |
| push(@implContentDecls, " if (UNLIKELY(ec))\n"); |
| push(@implContentDecls, " V8Proxy::setDOMException(ec);\n"); |
| } |
| |
| if ($isPodType) { |
| push(@implContentDecls, " wrapper->commitChange(*imp, V8Proxy::svgContext(wrapper));\n"); |
| } elsif (IsSVGTypeNeedingContextParameter($implClassName)) { |
| $implIncludes{"SVGElement.h"} = 1; |
| |
| my $currentObject = "imp"; |
| if ($isPodType) { |
| $currentObject = "wrapper"; |
| } |
| |
| push(@implContentDecls, " if (SVGElement* context = V8Proxy::svgContext($currentObject)) {\n"); |
| push(@implContentDecls, " context->svgAttributeChanged(imp->associatedAttributeName());\n"); |
| push(@implContentDecls, " }\n"); |
| } |
| |
| push(@implContentDecls, " return;\n"); |
| push(@implContentDecls, "}\n\n"); # end of setter |
| } |
| |
| 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 GenerateFunctionCallback |
| { |
| my $function = shift; |
| my $dataNode = shift; |
| my $implClassName = shift; |
| |
| my $interfaceName = $dataNode->name; |
| my $name = $function->signature->name; |
| |
| # 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}; |
| |
| if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) { |
| push(@implContentDecls, " if (args.Length() < $numParameters) return v8::Handle<v8::Value>();\n"); |
| } |
| |
| if (IsPodType($implClassName)) { |
| my $nativeClassName = GetNativeType($implClassName); |
| push(@implContentDecls, " V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8SVGPODTypeWrapper<$nativeClassName>::toNative(args.Holder());\n"); |
| push(@implContentDecls, " $nativeClassName imp_instance = *imp_wrapper;\n"); |
| push(@implContentDecls, " $nativeClassName* imp = &imp_instance;\n"); |
| } else { |
| 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 (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); |
| OwnPtr<ScriptCallStack> callStack(ScriptCallStack::create(args, $numParameters)); |
| if (!callStack) |
| return v8::Undefined(); |
| END |
| $implIncludes{"ScriptCallStack.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; |
| |
| if ($parameter->extendedAttributes->{"Optional"}) { |
| # 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"); |
| } |
| |
| if (BasicTypeCanFailConversion($parameter)) { |
| push(@implContentDecls, " bool ${parameterName}Ok;\n"); |
| } |
| |
| push(@implContentDecls, " " . GetNativeTypeFromSignature($parameter, $paramIndex) . " $parameterName = "); |
| push(@implContentDecls, JSValueToNative($parameter, "args[$paramIndex]", |
| BasicTypeCanFailConversion($parameter) ? "${parameterName}Ok" : undef) . ";\n"); |
| |
| if (TypeCanFailConversion($parameter)) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, |
| " if (UNLIKELY(!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ")) {\n" . |
| " ec = TYPE_MISMATCH_ERR;\n" . |
| " goto fail;\n" . |
| " }\n"); |
| } |
| |
| if ($parameter->extendedAttributes->{"IsIndex"}) { |
| $implIncludes{"ExceptionCode.h"} = 1; |
| push(@implContentDecls, |
| " if (UNLIKELY($parameterName < 0)) {\n" . |
| " ec = INDEX_SIZE_ERR;\n" . |
| " goto fail;\n" . |
| " }\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, "\n#if ${conditionalString}\n") if $conditionalString; |
| GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", ""); |
| push(@implContent, "\n#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; |
| |
| 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 . " {\n"); |
| push(@implContent, $indent . " \/\/ $commentInfo\n"); |
| push(@implContent, $indent . " \"$attrName\",\n"); |
| push(@implContent, $indent . " $getter,\n"); |
| push(@implContent, $indent . " $setter,\n"); |
| push(@implContent, $indent . " $data,\n"); |
| push(@implContent, $indent . " $accessControl,\n"); |
| push(@implContent, $indent . " static_cast<v8::PropertyAttribute>($propAttr),\n"); |
| push(@implContent, $indent . " $on_proto\n"); |
| push(@implContent, $indent . " }" . $delimiter . "\n"); |
| END |
| } |
| |
| 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: If the parent interface of $dataNode already has |
| # HasIndexGetter, we don't need to handle the getter here. |
| if ($interfaceName eq "WebKitCSSTransformValue") { |
| $hasGetter = 0; |
| } |
| |
| # 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"; |
| } |
| |
| 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; |
| } |
| |
| my $hasGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $hasCustomGetter || $namedPropertyGetter; |
| 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"}; |
| # FIXME: Try to remove hard-coded HTMLDocument reference by aligning handling of document.all with JSC bindings. |
| my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"} || $interfaceName eq "HTMLDocument"; |
| 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, "); |
| push(@implContent, "0, "); # NamedPropertyQuery -- not being used at the moment. |
| 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"}; |
| my $conditionalString = GenerateConditionalString($dataNode); |
| |
| # - Add default header template |
| @implContentHeader = split("\r", $headerTemplate); |
| |
| push(@implFixedHeader, |
| "#include \"config.h\"\n" . |
| "#include \"RuntimeEnabledFeatures.h\"\n" . |
| "#include \"V8Proxy.h\"\n" . |
| "#include \"V8Binding.h\"\n" . |
| "#include \"V8BindingState.h\"\n" . |
| "#include \"V8DOMWrapper.h\"\n" . |
| "#include \"V8IsolatedContext.h\"\n\n" . |
| "#undef LOG\n\n"); |
| |
| push(@implFixedHeader, "\n#if ${conditionalString}\n\n") if $conditionalString; |
| |
| if ($className =~ /^V8SVGAnimated/) { |
| AddIncludesForSVGAnimatedType($interfaceName); |
| } |
| |
| $implIncludes{"${className}.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; |
| # 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; |
| } |
| |
| # 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); |
| } |
| |
| 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->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 shadow_attrs[] = {\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}) { |
| my $attrExt = $function->signature->extendedAttributes; |
| # Don't put any nonstandard functions into this table: |
| if ($attrExt->{"V8OnInstance"}) { |
| 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(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n"); |
| |
| # In namespace WebCore, add generated implementation for 'CanBeConstructed'. |
| if ($dataNode->extendedAttributes->{"CanBeConstructed"} && !$dataNode->extendedAttributes->{"CustomConstructor"}) { |
| push(@implContent, <<END); |
| v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args) |
| { |
| INC_STATS("DOM.${interfaceName}.Contructor"); |
| return V8Proxy::constructDOMObject<$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>(), shadow_attrs, sizeof(shadow_attrs)/sizeof(*shadow_attrs)); |
| |
| // 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> default_signature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, |
| END |
| # Set up our attributes if we have them |
| if ($has_attributes) { |
| push(@implContent, <<END); |
| ${interfaceName}_attrs, sizeof(${interfaceName}_attrs)/sizeof(*${interfaceName}_attrs), |
| END |
| } else { |
| push(@implContent, <<END); |
| NULL, 0, |
| END |
| } |
| |
| if ($has_callbacks) { |
| push(@implContent, <<END); |
| ${interfaceName}_callbacks, sizeof(${interfaceName}_callbacks)/sizeof(*${interfaceName}_callbacks)); |
| END |
| } else { |
| push(@implContent, <<END); |
| NULL, 0); |
| END |
| } |
| |
| if ($dataNode->extendedAttributes->{"CustomConstructor"} || $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) { |
| # A function named RuntimeEnabledFeatures::{methodName}Enabled() need to be written by hand. |
| $enable_function = "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($runtime_attr->signature->name) . "Enabled"; |
| 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}) { |
| $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"; |
| } |
| |
| my $conditional = ""; |
| if ($attrExt->{"EnabledAtRuntime"}) { |
| # Only call Set()/SetAccessor() if this method should be enabled |
| $enable_function = "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($function->signature->name) . "Enabled"; |
| $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 = "default_signature"; |
| if ($attrExt->{"V8DoNotCheckSignature"}) { |
| $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 "default_signature" && $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, sizeof(${interfaceName}_consts)/sizeof(*${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 "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($interfaceName); |
| if ($dataNode->extendedAttributes->{"PODType"}) { |
| $nativeType = "V8SVGPODTypeWrapper<${nativeType}>"; |
| } |
| push(@implContent, <<END); |
| |
| // Custom toString template |
| desc->Set(getToStringName(), getToStringTemplate()); |
| return desc; |
| } |
| |
| v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() |
| { |
| static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_ = createRawTemplate(); |
| return ${className}_raw_cache_; |
| } |
| |
| v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\ |
| { |
| static v8::Persistent<v8::FunctionTemplate> ${className}_cache_ = Configure${className}Template(GetRawTemplate()); |
| return ${className}_cache_; |
| } |
| |
| ${nativeType}* ${className}::toNative(v8::Handle<v8::Object> object) |
| { |
| return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex)); |
| } |
| |
| 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> V8DOMWindowShadowObject_cache_; |
| if (V8DOMWindowShadowObject_cache_.IsEmpty()) { |
| V8DOMWindowShadowObject_cache_ = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); |
| ConfigureShadowObjectTemplate(V8DOMWindowShadowObject_cache_); |
| } |
| return V8DOMWindowShadowObject_cache_; |
| } |
| END |
| } |
| |
| GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType); |
| |
| 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 |
| |
| push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; |
| } |
| |
| sub GenerateToV8Converters |
| { |
| my $dataNode = shift; |
| my $interfaceName = shift; |
| my $className = shift; |
| my $nativeType = 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}::wrap(${nativeType}* impl${forceNewObjectInput}) |
| { |
| 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)) |
| proxy->windowShell()->initContextIfNeeded(); |
| } |
| |
| END |
| } |
| |
| if ($domMapFunction) { |
| push(@implContent, " if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName); |
| if (IsNodeSubType($dataNode)) { |
| push(@implContent, " wrapper = V8DOMWrapper::getWrapper(impl);\n"); |
| } else { |
| push(@implContent, " wrapper = ${domMapFunction}.get(impl);\n"); |
| } |
| push(@implContent, <<END); |
| if (!wrapper.IsEmpty()) |
| return wrapper; |
| END |
| push(@implContent, " }\n") if IsDOMNodeType($interfaceName); |
| } |
| 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); |
| |
| if ($domMapFunction) { |
| push(@implContent, <<END); |
| ${domMapFunction}.set(impl, v8::Persistent<v8::Object>::New(wrapper)); |
| END |
| } |
| |
| push(@implContent, <<END); |
| return wrapper; |
| } |
| END |
| |
| if (IsRefPtrType($interfaceName)) { |
| push(@implContent, <<END); |
| |
| v8::Handle<v8::Value> toV8(PassRefPtr<${nativeType} > impl${forceNewObjectInput}) |
| { |
| return toV8(impl.get()${forceNewObjectCall}); |
| } |
| END |
| } |
| |
| if (!HasCustomToV8Implementation($dataNode, $interfaceName)) { |
| push(@implContent, <<END); |
| |
| v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectInput}) |
| { |
| if (!impl) |
| return v8::Null(); |
| return ${className}::wrap(impl${forceNewObjectCall}); |
| } |
| 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 "BarInfo"; |
| return 1 if $interfaceName eq "CSSStyleSheet"; |
| return 1 if $interfaceName eq "CanvasPixelArray"; |
| return 1 if $interfaceName eq "DOMSelection"; |
| return 1 if $interfaceName eq "DOMWindow"; |
| return 1 if $interfaceName eq "Element"; |
| return 1 if $interfaceName eq "Location"; |
| return 1 if $interfaceName eq "HTMLDocument"; |
| return 1 if $interfaceName eq "HTMLElement"; |
| return 1 if $interfaceName eq "History"; |
| return 1 if $interfaceName eq "NamedNodeMap"; |
| return 1 if $interfaceName eq "Navigator"; |
| return 1 if $interfaceName eq "SVGDocument"; |
| return 1 if $interfaceName eq "SVGElement"; |
| return 1 if $interfaceName eq "Screen"; |
| 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 "ImageData"; |
| 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 IsNodeSubType($dataNode); |
| # Only use getDOMSVGObjectWithContextMap() for non-node svg objects |
| return "getDOMSVGObjectWithContextMap()" if $type =~ /SVG/; |
| 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 "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 0; |
| } |
| |
| sub GetNativeTypeForConversions |
| { |
| my $type = shift; |
| return "FloatRect" if $type eq "SVGRect"; |
| return "FloatPoint" if $type eq "SVGPoint"; |
| return "AffineTransform" if $type eq "SVGMatrix"; |
| return "float" if $type eq "SVGNumber"; |
| return $type; |
| } |
| |
| sub GenerateFunctionCallString() |
| { |
| my $function = shift; |
| my $numberOfParameters = shift; |
| my $indent = shift; |
| my $implClassName = shift; |
| |
| my $name = $function->signature->name; |
| my $isPodType = IsPodType($implClassName); |
| my $returnType = GetTypeFromSignature($function->signature); |
| my $returnsPodType = IsPodType($returnType); |
| my $nativeReturnType = GetNativeType($returnType, 0); |
| my $result = ""; |
| |
| # Special case: SVG matrix transform methods should not mutate |
| # the matrix but return a copy |
| my $copyFirst = 0; |
| if ($implClassName eq "SVGMatrix" && $function->signature->type eq "SVGMatrix") { |
| $copyFirst = 1; |
| } |
| |
| 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 ($copyFirst) { |
| $functionString = "result.${name}("; |
| } |
| |
| my $returnsListItemPodType = 0; |
| # SVG lists functions that return POD types require special handling |
| if (IsSVGListTypeNeedingSpecialHandling($implClassName) && IsSVGListMethod($name) && $returnsPodType) { |
| $returnsListItemPodType = 1; |
| $result .= $indent . "SVGList<RefPtr<SVGPODListItem<$nativeReturnType> > >* listImp = imp;\n"; |
| $functionString = "listImp->${name}("; |
| } |
| |
| my $first = 1; |
| my $index = 0; |
| |
| foreach my $parameter (@{$function->parameters}) { |
| if ($index eq $numberOfParameters) { |
| last; |
| } |
| if ($first) { $first = 0; } |
| else { $functionString .= ", "; } |
| my $paramName = $parameter->name; |
| my $paramType = $parameter->type; |
| |
| # This is a bit of a hack... we need to convert parameters to methods on SVG lists |
| # of POD types which are items in the list to appropriate SVGList<> instances |
| if ($returnsListItemPodType && $paramType . "List" eq $implClassName) { |
| $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)"; |
| } |
| |
| if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") { |
| $functionString .= "$paramName.get()"; |
| } else { |
| $functionString .= $paramName; |
| } |
| $index++; |
| } |
| |
| if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { |
| $functionString .= ", " if not $first; |
| $functionString .= "callStack.get()"; |
| if ($first) { $first = 0; } |
| } |
| |
| if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) { |
| $functionString .= ", " if not $first; |
| # FIXME: We need to pass DOMWrapperWorld as a parameter. |
| # See http://trac.webkit.org/changeset/54182 |
| $functionString .= "processingUserGesture()"; |
| if ($first) { $first = 0; } |
| } |
| |
| if (@{$function->raisesExceptions}) { |
| $functionString .= ", " if not $first; |
| $functionString .= "ec"; |
| } |
| $functionString .= ")"; |
| |
| my $return = "result"; |
| my $returnIsRef = IsRefPtrType($returnType); |
| |
| if ($returnType eq "void") { |
| $result .= $indent . "$functionString;\n"; |
| } elsif ($copyFirst) { |
| $result .= $indent . GetNativeType($returnType, 0) . " result = *imp;\n" . $indent . "$functionString;\n"; |
| } elsif ($returnsListItemPodType) { |
| $result .= $indent . "RefPtr<SVGPODListItem<$nativeReturnType> > result = $functionString;\n"; |
| } elsif (@{$function->raisesExceptions} or $returnsPodType or $isPodType or IsSVGTypeNeedingContextParameter($returnType)) { |
| $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 (@{$function->raisesExceptions}) { |
| $result .= $indent . "if (UNLIKELY(ec)) goto fail;\n"; |
| } |
| |
| # If the return type is a POD type, separate out the wrapper generation |
| if ($returnsListItemPodType) { |
| $result .= $indent . "RefPtr<V8SVGPODTypeWrapper<" . $nativeReturnType . "> > wrapper = "; |
| $result .= "V8SVGPODTypeWrapperCreatorForList<" . $nativeReturnType . ">::create($return, imp->associatedAttributeName());\n"; |
| $return = "wrapper"; |
| } elsif ($returnsPodType) { |
| $result .= $indent . "RefPtr<V8SVGPODTypeWrapper<" . $nativeReturnType . "> > wrapper = "; |
| $result .= GenerateSVGStaticPodTypeWrapper($returnType, $return) . ";\n"; |
| $return = "wrapper"; |
| } |
| |
| my $generatedSVGContextRetrieval = 0; |
| # If the return type needs an SVG context, output it |
| if (IsSVGTypeNeedingContextParameter($returnType)) { |
| $result .= GenerateSVGContextAssignment($implClassName, $return . ".get()", $indent); |
| $generatedSVGContextRetrieval = 1; |
| } |
| |
| if (IsSVGTypeNeedingContextParameter($implClassName) && $implClassName =~ /List$/ && IsSVGListMutator($name)) { |
| if (!$generatedSVGContextRetrieval) { |
| $result .= GenerateSVGContextRetrieval($implClassName, $indent); |
| $generatedSVGContextRetrieval = 1; |
| } |
| |
| $result .= $indent . "context->svgAttributeChanged(imp->associatedAttributeName());\n"; |
| $implIncludes{"SVGElement.h"} = 1; |
| } |
| |
| # If the implementing class is a POD type, commit changes |
| if ($isPodType) { |
| if (!$generatedSVGContextRetrieval) { |
| $result .= GenerateSVGContextRetrieval($implClassName, $indent); |
| $generatedSVGContextRetrieval = 1; |
| } |
| |
| $result .= $indent . "imp_wrapper->commitChange(imp_instance, context);\n"; |
| } |
| |
| if ($returnsPodType) { |
| $implIncludes{"V8${returnType}.h"} = 1; |
| $result .= $indent . "return toV8(wrapper.release());\n"; |
| } else { |
| $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"}) { |
| $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 0 if $type eq "SVGAnimatedPoints"; |
| |
| return 1; |
| } |
| |
| sub GetNativeType |
| { |
| my $type = shift; |
| my $isParameter = shift; |
| |
| 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 "FloatRect" if $type eq "SVGRect"; |
| return "FloatPoint" if $type eq "SVGPoint"; |
| return "AffineTransform" if $type eq "SVGMatrix"; |
| return "SVGTransform" if $type eq "SVGTransform"; |
| return "SVGLength" if $type eq "SVGLength"; |
| return "SVGAngle" if $type eq "SVGAngle"; |
| return "float" if $type eq "SVGNumber"; |
| return "SVGPreserveAspectRatio" if $type eq "SVGPreserveAspectRatio"; |
| 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 "String" if $type eq "DOMUserData"; # FIXME: Temporary hack? |
| |
| # temporary hack |
| return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; |
| |
| # necessary as resolvers could be constructed on fly. |
| return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver"; |
| |
| return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; |
| |
| # Default, assume native type is a pointer with same type name as idl type |
| return "${type}*"; |
| } |
| |
| 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 BasicTypeCanFailConversion |
| { |
| my $signature = shift; |
| my $type = GetTypeFromSignature($signature); |
| |
| return 1 if $type eq "SVGAngle"; |
| return 1 if $type eq "SVGLength"; |
| return 1 if $type eq "SVGMatrix"; |
| return 1 if $type eq "SVGPoint"; |
| return 1 if $type eq "SVGPreserveAspectRatio"; |
| return 1 if $type eq "SVGRect"; |
| return 1 if $type eq "SVGTransform"; |
| return 0; |
| } |
| |
| 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 BasicTypeCanFailConversion($signature); |
| } |
| |
| sub JSValueToNative |
| { |
| my $signature = shift; |
| my $value = shift; |
| my $okParam = shift; |
| my $maybeOkParam = $okParam ? ", ${okParam}" : ""; |
| |
| 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 "$value->NumberValue()" if $type eq "SVGNumber"; |
| |
| return "toInt32($value${maybeOkParam})" if $type eq "unsigned long" or $type eq "unsigned short" or $type eq "long"; |
| 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; |
| } |
| |
| if ($type eq "SerializedScriptValue") { |
| $implIncludes{"SerializedScriptValue.h"} = 1; |
| return "SerializedScriptValue::create($value)"; |
| } |
| |
| if ($type eq "DOMObject") { |
| $implIncludes{"ScriptValue.h"} = 1; |
| return "ScriptValue($value)"; |
| } |
| |
| if ($type eq "NodeFilter") { |
| return "V8DOMWrapper::wrapNativeNodeFilter($value)"; |
| } |
| |
| if ($type eq "SVGRect") { |
| $implIncludes{"FloatRect.h"} = 1; |
| } |
| |
| if ($type eq "SVGPoint") { |
| $implIncludes{"FloatPoint.h"} = 1; |
| } |
| |
| # 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; |
| |
| if (IsPodType($type)) { |
| my $nativeType = GetNativeType($type); |
| $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; |
| |
| return "V8SVGPODTypeUtil::toSVGPODType<${nativeType}>(&V8${type}::info, $value${maybeOkParam})" |
| } |
| |
| $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; |
| } |
| |
| foreach my $parameter (@{$function->parameters}) { |
| if (IsWrapperType($parameter->type)) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| my %non_wrapper_types = ( |
| 'float' => 1, |
| 'double' => 1, |
| 'short' => 1, |
| 'unsigned short' => 1, |
| 'long' => 1, |
| 'unsigned long' => 1, |
| 'boolean' => 1, |
| 'long long' => 1, |
| 'unsigned long long' => 1, |
| 'DOMString' => 1, |
| 'CompareHow' => 1, |
| 'SVGAngle' => 1, |
| 'SVGRect' => 1, |
| 'SVGPoint' => 1, |
| 'SVGPreserveAspectRatio' => 1, |
| 'SVGMatrix' => 1, |
| 'SVGTransform' => 1, |
| 'SVGLength' => 1, |
| 'SVGNumber' => 1, |
| 'SVGPaintType' => 1, |
| 'DOMTimeStamp' => 1, |
| 'JSObject' => 1, |
| 'DOMObject' => 1, |
| 'EventTarget' => 1, |
| 'NodeFilter' => 1, |
| 'EventListener' => 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 v8::Date::New(static_cast<double>($value))" if $type eq "DOMTimeStamp"; |
| 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"; |
| 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"; |
| } |
| 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; |
| |
| if (IsPodType($type)) { |
| $value = GenerateSVGStaticPodTypeWrapper($type, $value) . ".get()"; |
| } |
| |
| return "return toV8($value)"; |
| } |
| |
| sub GenerateSVGStaticPodTypeWrapper { |
| my $type = shift; |
| my $value = shift; |
| |
| $implIncludes{"V8$type.h"}=1; |
| $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; |
| |
| my $nativeType = GetNativeType($type); |
| return "V8SVGStaticPODTypeWrapper<$nativeType>::create($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//; |
| |
| 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 IsSVGTypeNeedingContextParameter |
| { |
| my $implClassName = shift; |
| |
| if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) { |
| return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/; |
| } |
| |
| return 0; |
| } |
| |
| sub GenerateSVGContextAssignment |
| { |
| my $srcType = shift; |
| my $value = shift; |
| my $indent = shift; |
| |
| $result = GenerateSVGContextRetrieval($srcType, $indent); |
| $result .= $indent . "V8Proxy::setSVGContext($value, context);\n"; |
| |
| return $result; |
| } |
| |
| sub GenerateSVGContextRetrieval |
| { |
| my $srcType = shift; |
| my $indent = shift; |
| |
| my $srcIsPodType = IsPodType($srcType); |
| |
| my $srcObject = "imp"; |
| if ($srcIsPodType) { |
| $srcObject = "imp_wrapper"; |
| } |
| |
| my $contextDecl; |
| |
| if (IsSVGTypeNeedingContextParameter($srcType)) { |
| $contextDecl = "V8Proxy::svgContext($srcObject)"; |
| } else { |
| $contextDecl = $srcObject; |
| } |
| |
| return $indent . "SVGElement* context = $contextDecl;\n"; |
| } |
| |
| sub IsSVGListMutator |
| { |
| my $functionName = shift; |
| |
| return 1 if $functionName eq "clear"; |
| return 1 if $functionName eq "initialize"; |
| return 1 if $functionName eq "insertItemBefore"; |
| return 1 if $functionName eq "replaceItem"; |
| return 1 if $functionName eq "removeItem"; |
| return 1 if $functionName eq "appendItem"; |
| |
| return 0; |
| } |
| |
| sub IsSVGListMethod |
| { |
| my $functionName = shift; |
| |
| return 1 if $functionName eq "getFirst"; |
| return 1 if $functionName eq "getLast"; |
| return 1 if $functionName eq "getItem"; |
| |
| return IsSVGListMutator($functionName); |
| } |
| |
| sub IsSVGListTypeNeedingSpecialHandling |
| { |
| my $className = shift; |
| |
| return 1 if $className eq "SVGPointList"; |
| return 1 if $className eq "SVGTransformList"; |
| |
| return 0; |
| } |
| |
| sub GetVisibleInterfaceName |
| { |
| my $interfaceName = shift; |
| |
| return "DOMException" if $interfaceName eq "DOMCoreException"; |
| return "FormData" if $interfaceName eq "DOMFormData"; |
| return $interfaceName; |
| } |
| |
| sub DebugPrint |
| { |
| my $output = shift; |
| |
| print $output; |
| print "\n"; |
| } |