Home | History | Annotate | Download | only in scripts
      1 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann (at] kde.org>
      2 # Copyright (C) 2006 Anders Carlsson <andersca (at] mac.com>
      3 # Copyright (C) 2006 Samuel Weinig <sam.weinig (at] gmail.com>
      4 # Copyright (C) 2006 Alexey Proskuryakov <ap (at] webkit.org>
      5 # Copyright (C) 2006 Apple Computer, Inc.
      6 # Copyright (C) 2007, 2008, 2009 Google Inc.
      7 # Copyright (C) 2009 Cameron McCormack <cam (at] mcc.id.au>
      8 # Copyright (C) Research In Motion Limited 2010. All rights reserved.
      9 # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
     10 #
     11 # This library is free software; you can redistribute it and/or
     12 # modify it under the terms of the GNU Library General Public
     13 # License as published by the Free Software Foundation; either
     14 # version 2 of the License, or (at your option) any later version.
     15 #
     16 # This library is distributed in the hope that it will be useful,
     17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     19 # Library General Public License for more details.
     20 #
     21 # You should have received a copy of the GNU Library General Public License
     22 # along with this library; see the file COPYING.LIB.  If not, write to
     23 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     24 # Boston, MA 02111-1307, USA.
     25 #
     26 
     27 package CodeGeneratorV8;
     28 
     29 use Digest::MD5;
     30 
     31 my $module = "";
     32 my $outputDir = "";
     33 my $outputHeadersDir = "";
     34 
     35 my @headerContent = ();
     36 my @implContentHeader = ();
     37 my @implFixedHeader = ();
     38 my @implContent = ();
     39 my @implContentDecls = ();
     40 my %implIncludes = ();
     41 my %headerIncludes = ();
     42 
     43 my @allParents = ();
     44 
     45 # Default .h template
     46 my $headerTemplate = << "EOF";
     47 /*
     48     This file is part of the WebKit open source project.
     49     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
     50 
     51     This library is free software; you can redistribute it and/or
     52     modify it under the terms of the GNU Library General Public
     53     License as published by the Free Software Foundation; either
     54     version 2 of the License, or (at your option) any later version.
     55 
     56     This library is distributed in the hope that it will be useful,
     57     but WITHOUT ANY WARRANTY; without even the implied warranty of
     58     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     59     Library General Public License for more details.
     60 
     61     You should have received a copy of the GNU Library General Public License
     62     along with this library; see the file COPYING.LIB.  If not, write to
     63     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     64     Boston, MA 02111-1307, USA.
     65 */
     66 EOF
     67 
     68 # Default constructor
     69 sub new
     70 {
     71     my $object = shift;
     72     my $reference = { };
     73 
     74     $codeGenerator = shift;
     75     $outputDir = shift;
     76     $outputHeadersDir = shift;
     77 
     78     bless($reference, $object);
     79     return $reference;
     80 }
     81 
     82 sub finish
     83 {
     84     my $object = shift;
     85 
     86     # Commit changes!
     87     $object->WriteData();
     88 }
     89 
     90 # Params: 'domClass' struct
     91 sub GenerateInterface
     92 {
     93     my $object = shift;
     94     my $dataNode = shift;
     95     my $defines = shift;
     96 
     97     # Start actual generation
     98     if ($dataNode->extendedAttributes->{"Callback"}) {
     99         $object->GenerateCallbackHeader($dataNode);
    100         $object->GenerateCallbackImplementation($dataNode);
    101     } else {
    102         $object->GenerateHeader($dataNode);
    103         $object->GenerateImplementation($dataNode);
    104     }
    105 
    106     my $name = $dataNode->name;
    107 
    108     # Open files for writing
    109     my $headerFileName = "$outputHeadersDir/V8$name.h";
    110     my $implFileName = "$outputDir/V8$name.cpp";
    111 
    112     open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
    113     open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
    114 }
    115 
    116 # Params: 'idlDocument' struct
    117 sub GenerateModule
    118 {
    119     my $object = shift;
    120     my $dataNode = shift;
    121 
    122     $module = $dataNode->module;
    123 }
    124 
    125 sub AddIncludesForType
    126 {
    127     my $type = $codeGenerator->StripModule(shift);
    128 
    129     # When we're finished with the one-file-per-class
    130     # reorganization, we won't need these special cases.
    131     if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->AvoidInclusionOfType($type) and $type ne "Date") {
    132         # default, include the same named file
    133         $implIncludes{GetV8HeaderName(${type})} = 1;
    134 
    135         if ($type =~ /SVGPathSeg/) {
    136             $joinedName = $type;
    137             $joinedName =~ s/Abs|Rel//;
    138             $implIncludes{"${joinedName}.h"} = 1;
    139         }
    140     }
    141 
    142     # additional includes (things needed to compile the bindings but not the header)
    143 
    144     if ($type eq "CanvasRenderingContext2D") {
    145         $implIncludes{"CanvasGradient.h"} = 1;
    146         $implIncludes{"CanvasPattern.h"} = 1;
    147         $implIncludes{"CanvasStyle.h"} = 1;
    148     }
    149 
    150     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
    151         $implIncludes{"PlatformString.h"} = 1;
    152     }
    153 
    154     if ($type eq "CSSStyleDeclaration") {
    155         $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
    156     }
    157 
    158     if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
    159         # So we can get String -> AtomicString conversion for namedItem().
    160         $implIncludes{"wtf/text/AtomicString.h"} = 1;
    161     }
    162 }
    163 
    164 # If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if.
    165 sub GenerateConditionalString
    166 {
    167     my $node = shift;
    168     my $conditional = $node->extendedAttributes->{"Conditional"};
    169     if ($conditional) {
    170         if ($conditional =~ /&/) {
    171             return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
    172         } elsif ($conditional =~ /\|/) {
    173             return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")";
    174         } else {
    175             return "ENABLE(" . $conditional . ")";
    176         }
    177     } else {
    178         return "";
    179     }
    180 }
    181 
    182 sub GetSVGPropertyTypes
    183 {
    184     my $implType = shift;
    185 
    186     my $svgPropertyType;
    187     my $svgListPropertyType;
    188     my $svgNativeType;
    189 
    190     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
    191 
    192     $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
    193     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
    194 
    195     # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
    196     $svgNativeType = "$svgNativeType ";
    197 
    198     my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
    199     if ($svgNativeType =~ /SVGPropertyTearOff/) {
    200         $svgPropertyType = $svgWrappedNativeType;
    201         $implIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
    202     } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
    203         $svgListPropertyType = $svgWrappedNativeType;
    204         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
    205         $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1;
    206     } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
    207         $svgListPropertyType = $svgWrappedNativeType;
    208         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
    209         $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
    210     } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
    211         $svgListPropertyType = $svgWrappedNativeType;
    212         $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
    213     }
    214 
    215     if ($svgPropertyType) {
    216         $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint";
    217     }
    218 
    219     return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
    220 }
    221 
    222 sub GenerateHeader
    223 {
    224     my $object = shift;
    225     my $dataNode = shift;
    226 
    227     my $interfaceName = $dataNode->name;
    228     my $className = "V8$interfaceName";
    229     my $implClassName = $interfaceName;
    230 
    231     # Copy contents of parent classes except the first parent or if it is
    232     # EventTarget.
    233     $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);
    234 
    235     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
    236 
    237     # - Add default header template
    238     push(@headerContent, GenerateHeaderContentHeader($dataNode));
    239 
    240     $headerIncludes{"wtf/text/StringHash.h"} = 1;
    241     $headerIncludes{"WrapperTypeInfo.h"} = 1;
    242     $headerIncludes{"V8DOMWrapper.h"} = 1;
    243 
    244     my $headerClassInclude = GetHeaderClassInclude($implClassName);
    245     $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne "";
    246 
    247     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
    248 
    249     foreach my $headerInclude (sort keys(%headerIncludes)) {
    250         if ($headerInclude =~ /wtf/) {
    251             push(@headerContent, "#include \<${headerInclude}\>\n");
    252         } else {
    253             push(@headerContent, "#include \"${headerInclude}\"\n");
    254         }
    255     }
    256 
    257     push(@headerContent, "#include <v8.h>\n");
    258     push(@headerContent, "#include <wtf/HashMap.h>\n");
    259 
    260     push(@headerContent, "\nnamespace WebCore {\n");
    261     push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType;
    262     if ($svgNativeType) {
    263         if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) {
    264             push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n");
    265         } else {
    266             push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n");
    267         }
    268     }
    269     push(@headerContent, "\nclass FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect";
    270     push(@headerContent, "\nclass $className {\n");
    271 
    272     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
    273     my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
    274     my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : "";
    275     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
    276     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
    277 
    278     push(@headerContent, <<END);
    279 
    280 public:
    281     static bool HasInstance(v8::Handle<v8::Value> value);
    282     static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
    283     static v8::Persistent<v8::FunctionTemplate> GetTemplate();
    284     static ${nativeType}* toNative(v8::Handle<v8::Object> object)
    285     {
    286         return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex));
    287     }
    288     inline static v8::Handle<v8::Object> wrap(${nativeType}*${forceNewObjectParameter});
    289     static void derefObject(void*);
    290     static WrapperTypeInfo info;
    291 END
    292     if (IsActiveDomType($implClassName)) {
    293         push(@headerContent, "    static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n");
    294     }
    295 
    296     if ($implClassName eq "DOMWindow") {
    297         push(@headerContent, <<END);
    298     static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
    299 END
    300     }
    301 
    302     if ($implClassName eq "HTMLDocument") {
    303       push(@headerContent, <<END);
    304   static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl);
    305   static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key);
    306 END
    307     }
    308 
    309     my @enabledAtRuntime;
    310     foreach my $function (@{$dataNode->functions}) {
    311         my $name = $function->signature->name;
    312         my $attrExt = $function->signature->extendedAttributes;
    313 
    314         if ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
    315             push(@headerContent, <<END);
    316     static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&);
    317 END
    318         }
    319 
    320         if ($attrExt->{"EnabledAtRuntime"}) {
    321             push(@enabledAtRuntime, $function);
    322         }
    323     }
    324 
    325     if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) {
    326         push(@headerContent, <<END);
    327     static v8::Handle<v8::Value> constructorCallback(const v8::Arguments& args);
    328 END
    329     }
    330 
    331     foreach my $attribute (@{$dataNode->attributes}) {
    332         my $name = $attribute->signature->name;
    333         my $attrExt = $attribute->signature->extendedAttributes;
    334         if ($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"}
    335             || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) {
    336             push(@headerContent, <<END);
    337     static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);
    338 END
    339         }
    340         if ($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"}
    341             || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) {
    342             push(@headerContent, <<END);
    343     static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
    344 END
    345         }
    346         if ($attrExt->{"EnabledAtRuntime"}) {
    347             push(@enabledAtRuntime, $attribute);
    348         }
    349     }
    350 
    351     GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode);
    352     GenerateHeaderCustomCall($dataNode);
    353     GenerateHeaderCustomInternalFieldIndices($dataNode);
    354 
    355     if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
    356         push(@headerContent, <<END);
    357     static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data);
    358     static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data);
    359 END
    360     }
    361 
    362     push(@headerContent, <<END);
    363 private:
    364     static v8::Handle<v8::Object> wrapSlow(${nativeType}*);
    365 };
    366 
    367 END
    368 
    369     push(@headerContent, <<END);
    370 
    371 v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl${forceNewObjectInput})
    372 {
    373 END
    374     push(@headerContent, "    if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName);
    375     my $getWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getWrapper(impl)" : "${domMapFunction}.get(impl)";
    376     push(@headerContent, <<END);
    377         v8::Handle<v8::Object> wrapper = ${getWrapper};
    378         if (!wrapper.IsEmpty())
    379             return wrapper;
    380 END
    381     push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
    382     push(@headerContent, <<END);
    383     return ${className}::wrapSlow(impl);
    384 }
    385 END
    386 
    387     if (!HasCustomToV8Implementation($dataNode, $interfaceName)) {
    388         push(@headerContent, <<END);
    389 
    390 inline v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectParameter})
    391 {
    392     if (!impl)
    393         return v8::Null();
    394     return ${className}::wrap(impl${forceNewObjectCall});
    395 }
    396 END
    397     } elsif ($interfaceName ne 'Node') {
    398         push(@headerContent, <<END);
    399 
    400 v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter});
    401 END
    402     } else {
    403         push(@headerContent, <<END);
    404 
    405 v8::Handle<v8::Value> toV8Slow(Node*, bool);
    406 
    407 inline v8::Handle<v8::Value> toV8(Node* impl, bool forceNewObject = false)
    408 {
    409     if (!impl)
    410         return v8::Null();
    411     if (!forceNewObject) {
    412         v8::Handle<v8::Value> wrapper = V8DOMWrapper::getWrapper(impl);
    413         if (!wrapper.IsEmpty())
    414             return wrapper;
    415     }
    416     return toV8Slow(impl, forceNewObject);
    417 }
    418 END
    419     }
    420 
    421     if (IsRefPtrType($implClassName)) {
    422         push(@headerContent, <<END);
    423 inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl${forceNewObjectParameter})
    424 {
    425     return toV8(impl.get()${forceNewObjectCall});
    426 }
    427 END
    428     }
    429 
    430     push(@headerContent, "}\n\n");
    431     push(@headerContent, "#endif // $className" . "_h\n");
    432 
    433     my $conditionalString = GenerateConditionalString($dataNode);
    434     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
    435 }
    436 
    437 sub GetInternalFields
    438 {
    439     my $dataNode = shift;
    440     my $name = $dataNode->name;
    441     
    442     my @customInternalFields = ();
    443  
    444     # We can't ask whether a parent type has a given extendedAttribute, so special-case Node, AbstractWorker and WorkerContext to include all sub-types.
    445     # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
    446     if ($dataNode->extendedAttributes->{"EventTarget"} || IsNodeSubType($dataNode) || IsSubType($dataNode, "AbstractWorker") || IsSubType($dataNode, "WorkerContext")
    447         || $name eq "SVGElementInstance") {
    448         push(@customInternalFields, "eventListenerCacheIndex");
    449     }
    450 
    451     if ($name eq "DOMWindow") {
    452         push(@customInternalFields, "enteredIsolatedWorldIndex");
    453     }
    454     return @customInternalFields;
    455 }
    456 
    457 sub GetHeaderClassInclude
    458 {
    459     my $className = shift;
    460     if ($className =~ /SVGPathSeg/) {
    461         $className =~ s/Abs|Rel//;
    462     }
    463     return "" if ($codeGenerator->AvoidInclusionOfType($className));
    464     return "${className}.h";
    465 }
    466 
    467 sub GenerateHeaderCustomInternalFieldIndices
    468 {
    469     my $dataNode = shift;
    470     my @customInternalFields = GetInternalFields($dataNode);
    471     my $customFieldCounter = 0;
    472     foreach my $customInternalField (@customInternalFields) {
    473         push(@headerContent, <<END);
    474     static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
    475 END
    476         $customFieldCounter++;
    477     }
    478     push(@headerContent, <<END);
    479     static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
    480 END
    481 }
    482 
    483 my %indexerSpecialCases = (
    484     "Storage" => 1,
    485     "HTMLAppletElement" => 1,
    486     "HTMLEmbedElement" => 1,
    487     "HTMLObjectElement" => 1
    488 );
    489 
    490 sub GenerateHeaderNamedAndIndexedPropertyAccessors
    491 {
    492     my $dataNode = shift;
    493     my $interfaceName = $dataNode->name;
    494     my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
    495     my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"};
    496     my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
    497     my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"};
    498     my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
    499     my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
    500     if ($interfaceName eq "HTMLOptionsCollection") {
    501         $interfaceName = "HTMLCollection";
    502         $hasCustomIndexedGetter = 1;
    503         $hasCustomNamedGetter = 1;
    504     }
    505     if ($interfaceName eq "DOMWindow") {
    506         $hasCustomDeleterr = 0;
    507         $hasEnumerator = 0;
    508     }
    509     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
    510         $hasCustomNamedGetter = 1;
    511     }
    512     if ($interfaceName eq "HTMLDocument") {
    513         $hasCustomNamedGetter = 0;
    514         $hasCustomIndexedGetter = 0;
    515     }
    516     my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName};
    517 
    518     if ($hasCustomIndexedGetter || $isIndexerSpecialCase) {
    519         push(@headerContent, <<END);
    520     static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&);
    521 END
    522     }
    523 
    524     if ($isIndexerSpecialCase || $hasCustomIndexedSetter) {
    525         push(@headerContent, <<END);
    526     static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);
    527 END
    528     }
    529     if ($hasCustomDeleters) {
    530         push(@headerContent, <<END);
    531     static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
    532 END
    533     }
    534     if ($hasCustomNamedGetter) {
    535         push(@headerContent, <<END);
    536     static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
    537 END
    538     }
    539     if ($hasCustomNamedSetter) {
    540         push(@headerContent, <<END);
    541     static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&);
    542 END
    543     }
    544     if ($hasCustomDeleters) {
    545         push(@headerContent, <<END);
    546     static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
    547 END
    548     }
    549     if ($hasCustomEnumerator) {
    550         push(@headerContent, <<END);
    551     static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&);
    552     static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&);
    553 END
    554     }
    555 }
    556 
    557 sub GenerateHeaderCustomCall
    558 {
    559     my $dataNode = shift;
    560 
    561     if ($dataNode->extendedAttributes->{"CustomCall"}) {
    562         push(@headerContent, "    static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n");
    563     }
    564     if ($dataNode->name eq "Event") {
    565         push(@headerContent, "    static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
    566         push(@headerContent, "    static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);\n");
    567     }
    568     if ($dataNode->name eq "Location") {
    569         push(@headerContent, "    static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
    570         push(@headerContent, "    static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
    571         push(@headerContent, "    static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n");
    572     }
    573 }
    574 
    575 sub GenerateSetDOMException
    576 {
    577     my $indent = shift;
    578     my $result = "";
    579 
    580     $result .= $indent . "if (UNLIKELY(ec)) {\n";
    581     $result .= $indent . "    V8Proxy::setDOMException(ec);\n";
    582     $result .= $indent . "    return v8::Handle<v8::Value>();\n";
    583     $result .= $indent . "}\n";
    584 
    585     return $result;
    586 }
    587 
    588 sub IsSubType
    589 {
    590     my $dataNode = shift;
    591     my $parentType = shift;
    592     return 1 if ($dataNode->name eq $parentType);
    593     foreach (@allParents) {
    594         my $parent = $codeGenerator->StripModule($_);
    595         return 1 if $parent eq $parentType;
    596     }
    597     return 0;
    598 }
    599 
    600 sub IsNodeSubType
    601 {
    602     my $dataNode = shift;
    603     return IsSubType($dataNode, "Node");
    604 }
    605 
    606 sub GenerateDomainSafeFunctionGetter
    607 {
    608     my $function = shift;
    609     my $implClassName = shift;
    610 
    611     my $className = "V8" . $implClassName;
    612     my $funcName = $function->signature->name;
    613 
    614     my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
    615     if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
    616         $signature = "v8::Local<v8::Signature>()";
    617     }
    618 
    619     my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature);
    620 
    621     push(@implContentDecls, <<END);
    622 static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    623 {
    624     INC_STATS(\"DOM.$implClassName.$funcName._get\");
    625     static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
    626     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This());
    627     if (holder.IsEmpty()) {
    628         // can only reach here by 'object.__proto__.func', and it should passed
    629         // domain security check already
    630         return privateTemplate->GetFunction();
    631     }
    632     ${implClassName}* imp = ${className}::toNative(holder);
    633     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) {
    634         static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
    635         return sharedTemplate->GetFunction();
    636     }
    637     return privateTemplate->GetFunction();
    638 }
    639 
    640 END
    641 }
    642 
    643 sub GenerateConstructorGetter
    644 {
    645     my $implClassName = shift;
    646 
    647     push(@implContentDecls, <<END);
    648 static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    649 {
    650     INC_STATS(\"DOM.$implClassName.constructors._get\");
    651     v8::Handle<v8::Value> data = info.Data();
    652     ASSERT(data->IsExternal() || data->IsNumber());
    653     WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
    654 END
    655 
    656     if ($implClassName eq "DOMWindow") {
    657         push(@implContentDecls, <<END);
    658     // Get the proxy corresponding to the DOMWindow if possible to
    659     // make sure that the constructor function is constructed in the
    660     // context of the DOMWindow and not in the context of the caller.
    661     return V8DOMWrapper::getConstructor(type, V8DOMWindow::toNative(info.Holder()));
    662 END
    663     } elsif ($implClassName eq "DedicatedWorkerContext" or $implClassName eq "WorkerContext" or $implClassName eq "SharedWorkerContext") {
    664         push(@implContentDecls, <<END);
    665     return V8DOMWrapper::getConstructor(type, V8WorkerContext::toNative(info.Holder()));
    666 END
    667     } else {
    668         push(@implContentDecls, "    return v8::Handle<v8::Value>();");
    669     }
    670 
    671     push(@implContentDecls, <<END);
    672 }
    673 
    674 END
    675 }
    676 
    677 sub GenerateNormalAttrGetter
    678 {
    679     my $attribute = shift;
    680     my $dataNode = shift;
    681     my $implClassName = shift;
    682     my $interfaceName = shift;
    683 
    684     my $attrExt = $attribute->signature->extendedAttributes;
    685     my $attrName = $attribute->signature->name;
    686     my $attrType = GetTypeFromSignature($attribute->signature);
    687     my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1);
    688 
    689     my $getterStringUsesImp = $implClassName ne "SVGNumber";
    690     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
    691 
    692     # Getter
    693     my $conditionalString = GenerateConditionalString($attribute->signature);
    694     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
    695 
    696     push(@implContentDecls, <<END);
    697 static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
    698 {
    699     INC_STATS(\"DOM.$implClassName.$attrName._get\");
    700 END
    701 
    702     if ($svgNativeType) {
    703         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
    704         if ($svgWrappedNativeType =~ /List/) {
    705             push(@implContentDecls, <<END);
    706     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
    707 END
    708         } else {
    709             push(@implContentDecls, <<END);
    710     $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
    711     $svgWrappedNativeType& impInstance = wrapper->propertyReference();
    712 END
    713             if ($getterStringUsesImp) {
    714                 push(@implContentDecls, <<END);
    715     $svgWrappedNativeType* imp = &impInstance;
    716 END
    717             }
    718         }
    719     } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) {
    720         if ($interfaceName eq "DOMWindow") {
    721             push(@implContentDecls, <<END);
    722     v8::Handle<v8::Object> holder = info.Holder();
    723 END
    724         } else {
    725             # perform lookup first
    726             push(@implContentDecls, <<END);
    727     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
    728     if (holder.IsEmpty())
    729         return v8::Handle<v8::Value>();
    730 END
    731         }
    732         push(@implContentDecls, <<END);
    733     ${implClassName}* imp = V8${implClassName}::toNative(holder);
    734 END
    735     } else {
    736         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
    737         my $url = $attribute->signature->extendedAttributes->{"URL"};
    738         if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
    739             # Generate super-compact call for regular attribute getter:
    740             my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect;
    741             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
    742             $implIncludes{"${namespace}.h"} = 1;
    743             push(@implContentDecls, "    return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n");
    744             push(@implContentDecls, "}\n\n");
    745             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
    746             return;
    747             # Skip the rest of the function!
    748         }
    749         push(@implContentDecls, <<END);
    750     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
    751 END
    752     }
    753 
    754     # Generate security checks if necessary
    755     if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
    756         push(@implContentDecls, "    if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->$attrName()))\n    return v8::Handle<v8::Value>();\n\n");
    757     } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
    758         push(@implContentDecls, "    if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->contentDocument()))\n    return v8::Handle<v8::Value>();\n\n");
    759     }
    760 
    761     my $useExceptions = 1 if @{$attribute->getterExceptions};
    762     if ($useExceptions) {
    763         $implIncludes{"ExceptionCode.h"} = 1;
    764         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    765     }
    766 
    767     if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) {
    768         $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"};
    769     }
    770 
    771     my $returnType = GetTypeFromSignature($attribute->signature);
    772 
    773     my $getterString;
    774     if ($getterStringUsesImp) {
    775         $getterString = "imp->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
    776         $getterString .= "ec" if $useExceptions;
    777         $getterString .= ")";
    778     } else {
    779         $getterString = "impInstance";
    780     }
    781 
    782     my $result;
    783     my $wrapper;
    784 
    785         if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
    786         push(@implContentDecls, "    if (!imp->document())\n");
    787         push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
    788     }
    789 
    790     if ($useExceptions) {
    791         if ($nativeType =~ /^V8Parameter/) {
    792           push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n");
    793         } else {
    794           push(@implContentDecls, "    $nativeType v = $getterString;\n");
    795         }
    796         push(@implContentDecls, GenerateSetDOMException("    "));
    797         $result = "v";
    798         $result .= ".release()" if (IsRefPtrType($returnType));
    799     } else {
    800         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
    801         $result = $getterString;
    802     }
    803  
    804     # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get
    805     # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to
    806     # the newly created wrapper into an internal field of the holder object.
    807     if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"})
    808         && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" 
    809         && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) {
    810         AddIncludesForType($returnType);
    811         my $domMapFunction = GetDomMapFunction(0, $returnType);
    812         # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already
    813         # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference.
    814         push(@implContentDecls, "    RefPtr<$returnType> result = ${getterString};\n");
    815         push(@implContentDecls, "    v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Value>();\n");
    816         push(@implContentDecls, "    if (wrapper.IsEmpty()) {\n");
    817         push(@implContentDecls, "        wrapper = toV8(result.get());\n");
    818         push(@implContentDecls, "        if (!wrapper.IsEmpty())\n");
    819         if ($dataNode->name eq "DOMWindow") {
    820             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenWindowReference(imp->frame(), \"${attrName}\", wrapper);\n");
    821         } else {
    822             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenReference(info.Holder(), \"${attrName}\", wrapper);\n");
    823         }
    824         push(@implContentDecls, "    }\n");
    825         push(@implContentDecls, "    return wrapper;\n");
    826         push(@implContentDecls, "}\n\n");
    827         push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
    828         return;
    829     }
    830 
    831     if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) {
    832         $implIncludes{"V8$attrType.h"} = 1;
    833         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
    834         # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
    835         push(@implContentDecls, "    return toV8(static_cast<$svgNativeType*>($result));\n");
    836     } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) {
    837         $implIncludes{"V8$attrType.h"} = 1;
    838         $implIncludes{"SVGPropertyTearOff.h"} = 1;
    839         my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
    840         if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
    841             my $getter = $result;
    842             $getter =~ s/imp->//;
    843             $getter =~ s/\(\)//;
    844 
    845             my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);
    846 
    847             my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
    848             if ($selfIsTearOffType) {
    849                 $implIncludes{"SVGStaticPropertyWithParentTearOff.h"} = 1;
    850                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;
    851 
    852                 if ($result =~ /matrix/ and $implClassName eq "SVGTransform") {
    853                     # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
    854                     # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
    855                     $result =~ s/matrix/svgMatrix/;
    856                 }
    857 
    858                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)));\n");
    859             } else {
    860                 $implIncludes{"SVGStaticPropertyTearOff.h"} = 1;
    861                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;
    862 
    863                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)));\n");
    864             }
    865         } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
    866             my $extraImp = "GetOwnerElementForType<$implClassName, IsDerivedFromSVGElement<$implClassName>::value>::ownerElement(imp), ";
    867             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($extraImp$result)));\n");
    868         } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) {
    869             push(@implContentDecls, "    return toV8(WTF::getPtr($result));\n");
    870         } else {
    871             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($result)));\n");
    872         }
    873     } else {
    874         push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "    ").";\n");
    875     }
    876 
    877     push(@implContentDecls, "}\n\n");  # end of getter
    878     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
    879 }
    880 
    881 sub GenerateNormalAttrSetter
    882 {
    883     my $attribute = shift;
    884     my $dataNode = shift;
    885     my $implClassName = shift;
    886     my $interfaceName = shift;
    887 
    888     $implIncludes{"V8BindingMacros.h"} = 1;
    889 
    890     my $attrExt = $attribute->signature->extendedAttributes;
    891 
    892     my $conditionalString = GenerateConditionalString($attribute->signature);
    893     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
    894 
    895     push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n");
    896     push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
    897 
    898     # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
    899     # interface type, then if the incoming value does not implement that interface, a TypeError is
    900     # thrown rather than silently passing NULL to the C++ code.
    901     # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both
    902     # strings and numbers, so do not throw TypeError if the attribute is of these types.
    903     if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
    904         my $argType = GetTypeFromSignature($attribute->signature);
    905         if (IsWrapperType($argType)) {
    906             push(@implContentDecls, "    if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n");
    907             push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
    908             push(@implContentDecls, "        return;\n");
    909             push(@implContentDecls, "    }\n");
    910         }
    911     }
    912 
    913     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
    914     if ($svgNativeType) {
    915         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
    916         if ($svgWrappedNativeType =~ /List$/) {
    917             push(@implContentDecls, <<END);
    918     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
    919 END
    920         } else {
    921             push(@implContentDecls, "    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n");
    922             push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
    923             push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n");
    924             push(@implContentDecls, "        return;\n");
    925             push(@implContentDecls, "    }\n");
    926             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
    927             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
    928         }
    929     } elsif ($attrExt->{"v8OnProto"}) {
    930       if ($interfaceName eq "DOMWindow") {
    931         push(@implContentDecls, <<END);
    932     v8::Handle<v8::Object> holder = info.Holder();
    933 END
    934       } else {
    935         # perform lookup first
    936         push(@implContentDecls, <<END);
    937     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
    938     if (holder.IsEmpty())
    939         return;
    940 END
    941       }
    942     push(@implContentDecls, <<END);
    943     ${implClassName}* imp = V8${implClassName}::toNative(holder);
    944 END
    945     } else {
    946         my $attrType = GetTypeFromSignature($attribute->signature);
    947         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
    948         if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
    949             # Generate super-compact call for regular attribute setter:
    950             my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect;
    951             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
    952             $implIncludes{"${namespace}.h"} = 1;
    953             push(@implContentDecls, "    setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n");
    954             push(@implContentDecls, "}\n\n");
    955             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
    956             return;
    957             # Skip the rest of the function!
    958         }
    959 
    960         push(@implContentDecls, <<END);
    961     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
    962 END
    963     }
    964 
    965     my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
    966     if ($attribute->signature->type eq "EventListener") {
    967         if ($dataNode->name eq "DOMWindow") {
    968             push(@implContentDecls, "    if (!imp->document())\n");
    969             push(@implContentDecls, "        return;\n");
    970         }
    971     } else {
    972         my $value = JSValueToNative($attribute->signature, "value");
    973         if ($nativeType =~ /^V8Parameter/) {
    974           push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n");
    975         } else {
    976           push(@implContentDecls, "    $nativeType v = $value;\n");
    977         }
    978     }
    979 
    980     my $result = "v";
    981     my $returnType = GetTypeFromSignature($attribute->signature);
    982     if (IsRefPtrType($returnType)) {
    983         $result = "WTF::getPtr(" . $result . ")";
    984     }
    985 
    986     my $useExceptions = 1 if @{$attribute->setterExceptions};
    987 
    988     if ($useExceptions) {
    989         $implIncludes{"ExceptionCode.h"} = 1;
    990         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
    991     }
    992 
    993     if ($implClassName eq "SVGNumber") {
    994         push(@implContentDecls, "    *imp = $result;\n");
    995     } else {
    996         if ($attribute->signature->type eq "EventListener") {
    997             my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
    998             $implIncludes{"V8AbstractEventListener.h"} = 1;
    999             push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
   1000             if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
   1001                 $implIncludes{"V8EventListenerList.h"} = 1;
   1002                 $implIncludes{"V8WorkerContextErrorHandler.h"} = 1;
   1003                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)");
   1004             } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") {
   1005                 $implIncludes{"V8EventListenerList.h"} = 1;
   1006                 $implIncludes{"V8WindowErrorHandler.h"} = 1;
   1007                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)");
   1008             } else {
   1009                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)");
   1010             }
   1011         } else {
   1012             my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute);
   1013             push(@implContentDecls, "    imp->$setterExpressionPrefix$result");
   1014         }
   1015         push(@implContentDecls, ", ec") if $useExceptions;
   1016         push(@implContentDecls, ");\n");
   1017     }
   1018 
   1019     if ($useExceptions) {
   1020         push(@implContentDecls, "    if (UNLIKELY(ec))\n");
   1021         push(@implContentDecls, "        V8Proxy::setDOMException(ec);\n");
   1022     }
   1023 
   1024     if ($svgNativeType) {
   1025         if ($useExceptions) {
   1026             push(@implContentDecls, "    if (!ec)\n");
   1027             push(@implContentDecls, "        wrapper->commitChange();\n");
   1028         } else {
   1029             push(@implContentDecls, "    wrapper->commitChange();\n");
   1030         }
   1031     }
   1032 
   1033     push(@implContentDecls, "    return;\n");
   1034     push(@implContentDecls, "}\n\n");  # end of setter
   1035     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
   1036 }
   1037 
   1038 sub GetFunctionTemplateCallbackName
   1039 {
   1040     $function = shift;
   1041     $interfaceName = shift;
   1042 
   1043     my $name = $function->signature->name;
   1044 
   1045     if ($function->signature->extendedAttributes->{"Custom"} ||
   1046         $function->signature->extendedAttributes->{"V8Custom"}) {
   1047         if ($function->signature->extendedAttributes->{"Custom"} &&
   1048             $function->signature->extendedAttributes->{"V8Custom"}) {
   1049             die "Custom and V8Custom should be mutually exclusive!"
   1050         }
   1051         return "V8${interfaceName}::${name}Callback";
   1052     } else {
   1053         return "${interfaceName}Internal::${name}Callback";
   1054     }
   1055 }
   1056 
   1057 sub GenerateNewFunctionTemplate
   1058 {
   1059     $function = shift;
   1060     $interfaceName = shift;
   1061     $signature = shift;
   1062 
   1063     my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
   1064     return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)";
   1065 }
   1066 
   1067 sub GenerateEventListenerCallback
   1068 {
   1069     my $implClassName = shift;
   1070     my $functionName = shift;
   1071     my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
   1072     my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
   1073     my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove";
   1074  
   1075     push(@implContentDecls, <<END);
   1076 static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args)
   1077 {
   1078     INC_STATS("DOM.${implClassName}.${functionName}EventListener()");
   1079     RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType});
   1080     if (listener) {
   1081         V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
   1082         ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
   1083     }
   1084     return v8::Undefined();
   1085 }
   1086 
   1087 END
   1088 }
   1089 
   1090 sub GenerateParametersCheckExpression
   1091 {
   1092     my $numParameters = shift;
   1093     my $function = shift;
   1094 
   1095     my @andExpression = ();
   1096     push(@andExpression, "args.Length() == $numParameters");
   1097     my $parameterIndex = 0;
   1098     foreach $parameter (@{$function->parameters}) {
   1099         last if $parameterIndex >= $numParameters;
   1100         my $value = "args[$parameterIndex]";
   1101         my $type = GetTypeFromSignature($parameter);
   1102 
   1103         # Only DOMString or wrapper types are checked.
   1104         # For DOMString, Null, Undefined and any Object are accepted too, as
   1105         # these are acceptable values for a DOMString argument (any Object can
   1106         # be converted to a string via .toString).
   1107         if ($codeGenerator->IsStringType($type)) {
   1108             push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())");
   1109         } elsif ($parameter->extendedAttributes->{"Callback"}) {
   1110             # For Callbacks only checks if the value is null or object.
   1111             push(@andExpression, "(${value}->IsNull() || ${value}->IsObject())");
   1112         } elsif (IsWrapperType($type)) {
   1113             push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))");
   1114         }
   1115 
   1116         $parameterIndex++;
   1117     }
   1118     my $res = join(" && ", @andExpression);
   1119     $res = "($res)" if @andExpression > 1;
   1120     return $res;
   1121 }
   1122 
   1123 sub GenerateFunctionParametersCheck
   1124 {
   1125     my $function = shift;
   1126 
   1127     my @orExpression = ();
   1128     my $numParameters = 0;
   1129     foreach $parameter (@{$function->parameters}) {
   1130         if ($parameter->extendedAttributes->{"Optional"}) {
   1131             push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
   1132         }
   1133         $numParameters++;
   1134     }
   1135     push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
   1136     return join(" || ", @orExpression);
   1137 }
   1138 
   1139 sub GenerateOverloadedFunctionCallback
   1140 {
   1141     my $function = shift;
   1142     my $dataNode = shift;
   1143     my $implClassName = shift;
   1144 
   1145     # Generate code for choosing the correct overload to call. Overloads are
   1146     # chosen based on the total number of arguments passed and the type of
   1147     # values passed in non-primitive argument slots. When more than a single
   1148     # overload is applicable, precedence is given according to the order of
   1149     # declaration in the IDL.
   1150 
   1151     my $name = $function->signature->name;
   1152     push(@implContentDecls, <<END);
   1153 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
   1154 {
   1155     INC_STATS(\"DOM.$implClassName.$name\");
   1156 END
   1157 
   1158     foreach my $overload (@{$function->{overloads}}) {
   1159         my $parametersCheck = GenerateFunctionParametersCheck($overload);
   1160         push(@implContentDecls, "    if ($parametersCheck)\n");
   1161         push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
   1162     }
   1163     push(@implContentDecls, <<END);
   1164     V8Proxy::throwTypeError();
   1165     return notHandledByInterceptor();
   1166 END
   1167     push(@implContentDecls, "}\n\n");
   1168 }
   1169 
   1170 sub GenerateFunctionCallback
   1171 {
   1172     my $function = shift;
   1173     my $dataNode = shift;
   1174     my $implClassName = shift;
   1175 
   1176     my $interfaceName = $dataNode->name;
   1177     my $name = $function->signature->name;
   1178 
   1179     if (@{$function->{overloads}} > 1) {
   1180         # Append a number to an overloaded method's name to make it unique:
   1181         $name = $name . $function->{overloadIndex};
   1182     }
   1183 
   1184     # Adding and removing event listeners are not standard callback behavior,
   1185     # but they are extremely consistent across the various classes that take event listeners,
   1186     # so we can generate them as a "special case".
   1187     if ($name eq "addEventListener") {
   1188         GenerateEventListenerCallback($implClassName, "add");
   1189         return;
   1190     } elsif ($name eq "removeEventListener") {
   1191         GenerateEventListenerCallback($implClassName, "remove");
   1192         return;
   1193     }
   1194 
   1195     push(@implContentDecls, <<END);
   1196 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
   1197 {
   1198     INC_STATS(\"DOM.$implClassName.$name\");
   1199 END
   1200 
   1201     my $numParameters = @{$function->parameters};
   1202 
   1203     my $requiresAllArguments = $function->signature->extendedAttributes->{"RequiresAllArguments"};
   1204     if ($requiresAllArguments) {
   1205         my $numMandatoryParams = @{$function->parameters};
   1206         foreach my $param (reverse(@{$function->parameters})) {
   1207             if ($param->extendedAttributes->{"Optional"}) {
   1208                 $numMandatoryParams--;
   1209             } else {
   1210                 last;
   1211             }
   1212         }
   1213         push(@implContentDecls, "    if (args.Length() < $numMandatoryParams)\n");
   1214         if ($requiresAllArguments eq "Raise") {
   1215             push(@implContentDecls, "        return throwError(\"Not enough arguments\", V8Proxy::SyntaxError);\n");
   1216         } else {
   1217             push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
   1218         }
   1219     }
   1220 
   1221     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
   1222 
   1223     if ($svgNativeType) {
   1224         my $nativeClassName = GetNativeType($implClassName); 
   1225         if ($implClassName =~ /List$/) {
   1226             push(@implContentDecls, "    $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n");
   1227         } else {
   1228             push(@implContentDecls, "    $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n");
   1229             push(@implContentDecls, "    if (wrapper->role() == AnimValRole) {\n");
   1230             push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n");
   1231             push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
   1232             push(@implContentDecls, "    }\n");
   1233             my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
   1234             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
   1235             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
   1236         }
   1237     } elsif (!$function->signature->extendedAttributes->{"ClassMethod"}) {
   1238         push(@implContentDecls, <<END);
   1239     ${implClassName}* imp = V8${implClassName}::toNative(args.Holder());
   1240 END
   1241     }
   1242 
   1243     # Check domain security if needed
   1244     if (($dataNode->extendedAttributes->{"CheckDomainSecurity"}
   1245        || $interfaceName eq "DOMWindow")
   1246        && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
   1247     # We have not find real use cases yet.
   1248     push(@implContentDecls, <<END);
   1249     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
   1250         return v8::Handle<v8::Value>();
   1251 END
   1252     }
   1253 
   1254     my $raisesExceptions = @{$function->raisesExceptions};
   1255     if (!$raisesExceptions) {
   1256         foreach my $parameter (@{$function->parameters}) {
   1257             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
   1258                 $raisesExceptions = 1;
   1259             }
   1260         }
   1261     }
   1262 
   1263     if ($raisesExceptions) {
   1264         $implIncludes{"ExceptionCode.h"} = 1;
   1265         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
   1266         push(@implContentDecls, "    {\n");
   1267         # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors
   1268         # of objects (like Strings) declared later, causing compile errors. The block scope ends
   1269         # right before the label 'fail:'.
   1270     }
   1271 
   1272     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
   1273         push(@implContentDecls, <<END);
   1274     RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, $numParameters));
   1275     size_t maxStackSize = imp->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1;
   1276     RefPtr<ScriptCallStack> callStack(createScriptCallStack(maxStackSize));
   1277     if (!callStack)
   1278         return v8::Undefined();
   1279 END
   1280         $implIncludes{"ScriptArguments.h"} = 1;
   1281         $implIncludes{"ScriptCallStack.h"} = 1;
   1282         $implIncludes{"ScriptCallStackFactory.h"} = 1;
   1283     }
   1284     if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
   1285         push(@implContentDecls, <<END);
   1286     if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->getSVGDocument(ec)))
   1287         return v8::Handle<v8::Value>();
   1288 END
   1289     }
   1290 
   1291     my $paramIndex = 0;
   1292     foreach my $parameter (@{$function->parameters}) {
   1293         TranslateParameter($parameter);
   1294 
   1295         my $parameterName = $parameter->name;
   1296 
   1297         # Optional callbacks should be treated differently, because they always have a default value (0),
   1298         # and we can reduce the number of overloaded functions that take a different number of parameters.
   1299         if ($parameter->extendedAttributes->{"Optional"} && !$parameter->extendedAttributes->{"Callback"}) {
   1300             # Generate early call if there are not enough parameters.
   1301             push(@implContentDecls, "    if (args.Length() <= $paramIndex) {\n");
   1302             my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName);
   1303             push(@implContentDecls, $functionCall);
   1304             push(@implContentDecls, "    }\n");
   1305         }
   1306 
   1307         $implIncludes{"ExceptionCode.h"} = 1;
   1308         my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex);
   1309         if ($parameter->extendedAttributes->{"Callback"}) {
   1310             my $className = GetCallbackClassName($parameter->type);
   1311             $implIncludes{"$className.h"} = 1;
   1312             if ($parameter->extendedAttributes->{"Optional"}) {
   1313                 push(@implContentDecls, "    RefPtr<" . $parameter->type . "> $parameterName;\n");
   1314                 push(@implContentDecls, "    if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n");
   1315                 push(@implContentDecls, "        if (!args[$paramIndex]->IsObject())\n");
   1316                 push(@implContentDecls, "            return throwError(TYPE_MISMATCH_ERR);\n");
   1317                 push(@implContentDecls, "        $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n");
   1318                 push(@implContentDecls, "    }\n");
   1319             } else {
   1320                 push(@implContentDecls, "    if (args.Length() <= $paramIndex || !args[$paramIndex]->IsObject())\n");
   1321                 push(@implContentDecls, "        return throwError(TYPE_MISMATCH_ERR);\n");
   1322                 push(@implContentDecls, "    RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n");
   1323             }
   1324         } elsif ($parameter->type eq "SerializedScriptValue") {
   1325             $implIncludes{"SerializedScriptValue.h"} = 1;
   1326             push(@implContentDecls, "    bool ${parameterName}DidThrow = false;\n");
   1327             push(@implContentDecls, "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], ${parameterName}DidThrow);\n");
   1328             push(@implContentDecls, "    if (${parameterName}DidThrow)\n");
   1329             push(@implContentDecls, "        return v8::Undefined();\n");
   1330         } elsif (TypeCanFailConversion($parameter)) {
   1331             push(@implContentDecls, "    $nativeType $parameterName = " .
   1332                  JSValueToNative($parameter, "args[$paramIndex]") . ";\n");
   1333             push(@implContentDecls, "    if (UNLIKELY(!$parameterName)) {\n");
   1334             push(@implContentDecls, "        ec = TYPE_MISMATCH_ERR;\n");
   1335             push(@implContentDecls, "        goto fail;\n");
   1336             push(@implContentDecls, "    }\n");
   1337         } elsif ($nativeType =~ /^V8Parameter/) {
   1338             my $value = JSValueToNative($parameter, "args[$paramIndex]");
   1339             push(@implContentDecls, "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n");
   1340         } else {
   1341             $implIncludes{"V8BindingMacros.h"} = 1;
   1342             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
   1343             # interface type, then if the incoming value does not implement that interface, a TypeError
   1344             # is thrown rather than silently passing NULL to the C++ code.
   1345             # Per the Web IDL and ECMAScript specifications, incoming values can always be converted
   1346             # to both strings and numbers, so do not throw TypeError if the argument is of these
   1347             # types.
   1348             if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
   1349                 my $argValue = "args[$paramIndex]";
   1350                 my $argType = GetTypeFromSignature($parameter);
   1351                 if (IsWrapperType($argType)) {
   1352                     push(@implContentDecls, "    if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n");
   1353                     push(@implContentDecls, "        V8Proxy::throwTypeError();\n");
   1354                     push(@implContentDecls, "        return notHandledByInterceptor();\n");
   1355                     push(@implContentDecls, "    }\n");
   1356                 }
   1357             }
   1358             push(@implContentDecls, "    EXCEPTION_BLOCK($nativeType, $parameterName, " .
   1359                  JSValueToNative($parameter, "args[$paramIndex]") . ");\n");
   1360         }
   1361 
   1362         if ($parameter->extendedAttributes->{"IsIndex"}) {
   1363             push(@implContentDecls, "    if (UNLIKELY($parameterName < 0)) {\n");
   1364             push(@implContentDecls, "        ec = INDEX_SIZE_ERR;\n");
   1365             push(@implContentDecls, "        goto fail;\n");
   1366             push(@implContentDecls, "    }\n");
   1367         }
   1368 
   1369         $paramIndex++;
   1370     }
   1371 
   1372     # Build the function call string.
   1373     my $callString = GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName);
   1374     push(@implContentDecls, "$callString");
   1375 
   1376     if ($raisesExceptions) {
   1377         push(@implContentDecls, "    }\n");
   1378         push(@implContentDecls, "    fail:\n");
   1379         push(@implContentDecls, "    V8Proxy::setDOMException(ec);\n");
   1380         push(@implContentDecls, "    return v8::Handle<v8::Value>();\n");
   1381     }
   1382 
   1383     push(@implContentDecls, "}\n\n");
   1384 }
   1385 
   1386 sub GenerateBatchedAttributeData
   1387 {
   1388     my $dataNode = shift;
   1389     my $interfaceName = $dataNode->name;
   1390     my $attributes = shift;
   1391 
   1392     foreach my $attribute (@$attributes) {
   1393         my $conditionalString = GenerateConditionalString($attribute->signature);
   1394         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
   1395         GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
   1396         push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
   1397     }
   1398 }
   1399 
   1400 sub GenerateSingleBatchedAttribute
   1401 {
   1402     my $interfaceName = shift;
   1403     my $attribute = shift;
   1404     my $delimiter = shift;
   1405     my $indent = shift;
   1406     my $attrName = $attribute->signature->name;
   1407     my $attrExt = $attribute->signature->extendedAttributes;
   1408 
   1409     # Attributes of type SerializedScriptValue are set in the
   1410     # constructor and don't require callbacks.
   1411     return if ($attribute->signature->type eq "SerializedScriptValue");
   1412 
   1413     my $accessControl = "v8::DEFAULT";
   1414     if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) {
   1415         $accessControl = "v8::ALL_CAN_READ";
   1416     } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) {
   1417         $accessControl = "v8::ALL_CAN_WRITE";
   1418     } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) {
   1419         $accessControl = "v8::ALL_CAN_READ";
   1420         if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
   1421             $accessControl .= " | v8::ALL_CAN_WRITE";
   1422         }
   1423     }
   1424     if ($attrExt->{"V8DisallowShadowing"}) {
   1425         $accessControl .= " | v8::PROHIBITS_OVERWRITING";
   1426     }
   1427     $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";
   1428 
   1429     my $customAccessor =
   1430         $attrExt->{"Custom"} ||
   1431         $attrExt->{"CustomSetter"} ||
   1432         $attrExt->{"CustomGetter"} ||
   1433         $attrExt->{"V8Custom"} ||
   1434         $attrExt->{"V8CustomSetter"} ||
   1435         $attrExt->{"V8CustomGetter"} ||
   1436         "";
   1437     if ($customAccessor eq 1) {
   1438         # use the naming convension, interface + (capitalize) attr name
   1439         $customAccessor = $interfaceName . "::" . $attrName;
   1440     }
   1441 
   1442     my $getter;
   1443     my $setter;
   1444     my $propAttr = "v8::None";
   1445     my $hasCustomSetter = 0;
   1446 
   1447     # Check attributes.
   1448     if ($attrExt->{"DontEnum"}) {
   1449         $propAttr .= " | v8::DontEnum";
   1450     }
   1451     if ($attrExt->{"V8DisallowShadowing"}) {
   1452         $propAttr .= " | v8::DontDelete";
   1453     }
   1454 
   1455     my $on_proto = "0 /* on instance */";
   1456     my $data = "0 /* no data */";
   1457 
   1458     # Constructor
   1459     if ($attribute->signature->type =~ /Constructor$/) {
   1460         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
   1461         $constructorType =~ s/Constructor$//;
   1462         $implIncludes{"V8${constructorType}.h"} = 1;
   1463         if ($customAccessor) {
   1464             $getter = "V8${customAccessor}AccessorGetter";
   1465         } else {
   1466             $data = "&V8${constructorType}::info";
   1467             $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter";
   1468         }
   1469         $setter = "0";
   1470         $propAttr = "v8::ReadOnly";
   1471 
   1472     } else {
   1473         # Default Getter and Setter
   1474         $getter = "${interfaceName}Internal::${attrName}AttrGetter";
   1475         $setter = "${interfaceName}Internal::${attrName}AttrSetter";
   1476 
   1477         # Custom Setter
   1478         if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
   1479             $hasCustomSetter = 1;
   1480             $setter = "V8${customAccessor}AccessorSetter";
   1481         }
   1482 
   1483         # Custom Getter
   1484         if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
   1485             $getter = "V8${customAccessor}AccessorGetter";
   1486         }
   1487     }
   1488 
   1489     # Replaceable
   1490     if ($attrExt->{"Replaceable"} && !$hasCustomSetter) {
   1491         $setter = "0";
   1492         # Handle the special case of window.top being marked as Replaceable.
   1493         # FIXME: Investigate whether we could treat window.top as replaceable
   1494         # and allow shadowing without it being a security hole.
   1495         if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) {
   1496             $propAttr .= " | v8::ReadOnly";
   1497         }
   1498     }
   1499 
   1500     # Read only attributes
   1501     if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
   1502         $setter = "0";
   1503     }
   1504 
   1505     # An accessor can be installed on the proto
   1506     if ($attrExt->{"v8OnProto"}) {
   1507         $on_proto = "1 /* on proto */";
   1508     }
   1509 
   1510     my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
   1511                       "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
   1512 
   1513     push(@implContent, $indent . "    \/\/ $commentInfo\n");
   1514     push(@implContent, $indent . "    {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n");
   1515 }
   1516 
   1517 sub GenerateImplementationIndexer
   1518 {
   1519     my $dataNode = shift;
   1520     my $indexer = shift;
   1521     my $interfaceName = $dataNode->name;
   1522 
   1523     # FIXME: Figure out what HasNumericIndexGetter is really supposed to do. Right now, it's only set on WebGL-related files.
   1524     my $hasCustomSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"};
   1525     my $hasGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
   1526 
   1527     # FIXME: Find a way to not have to special-case HTMLOptionsCollection.
   1528     if ($interfaceName eq "HTMLOptionsCollection") {
   1529         $hasGetter = 1;
   1530     }
   1531 
   1532     # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled,
   1533     # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide
   1534     # simplistic, mirrored indexer handling in addition to named property handling.
   1535     my $isSpecialCase = exists $indexerSpecialCases{$interfaceName};
   1536     if ($isSpecialCase) {
   1537         $hasGetter = 1;
   1538         if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) {
   1539             $hasCustomSetter = 1;
   1540         }
   1541     }
   1542 
   1543     if (!$hasGetter) {
   1544         return;
   1545     }
   1546 
   1547     $implIncludes{"V8Collection.h"} = 1;
   1548 
   1549     my $indexerType = $indexer ? $indexer->type : 0;
   1550 
   1551     # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563).
   1552     if ($interfaceName eq "WebKitCSSKeyframesRule") {
   1553         $indexerType = "WebKitCSSKeyframeRule";
   1554     }
   1555 
   1556     # FIXME: The item() getter is not inherited from CSSValueList, seemingly due to the way
   1557     # the CodeGenerator->AddMethodsConstantsAndAttributesFromParentClasses() method works,
   1558     # so we need to set the indexerType manually in this case.
   1559     if ($interfaceName eq "WebKitCSSTransformValue") {
   1560         $indexerType = "CSSValue";
   1561     }
   1562 
   1563     if ($indexerType && !$hasCustomSetter) {
   1564         if ($indexerType eq "DOMString") {
   1565             my $conversion = $indexer->extendedAttributes->{"ConvertNullStringTo"};
   1566             if ($conversion && $conversion eq "Null") {
   1567                 push(@implContent, <<END);
   1568     setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc);
   1569 END
   1570             } else {
   1571                 push(@implContent, <<END);
   1572     setCollectionStringIndexedGetter<${interfaceName}>(desc);
   1573 END
   1574             }
   1575         } else {
   1576             push(@implContent, <<END);
   1577     setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
   1578 END
   1579             # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type.
   1580             $implIncludes{"V8${indexerType}.h"} = 1;
   1581         }
   1582 
   1583         return;
   1584     }
   1585 
   1586     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
   1587     my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode);
   1588     my $setOn = "Instance";
   1589 
   1590     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
   1591     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
   1592     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
   1593     # on the object.
   1594     if ($interfaceName eq "DOMWindow") {
   1595         $setOn = "Prototype";
   1596         $hasDeleter = 0;
   1597     }
   1598 
   1599     push(@implContent, "    desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter");
   1600     push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0");
   1601     push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment.
   1602     push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0");
   1603     push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator;
   1604     push(@implContent, ");\n");
   1605 }
   1606 
   1607 sub GenerateImplementationNamedPropertyGetter
   1608 {
   1609     my $dataNode = shift;
   1610     my $namedPropertyGetter = shift;
   1611     my $interfaceName = $dataNode->name;
   1612     my $hasCustomGetter = $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
   1613 
   1614     # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit
   1615     # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection).
   1616     if ($interfaceName eq "HTMLOptionsCollection") {
   1617         $interfaceName = "HTMLCollection";
   1618         $hasCustomGetter = 1;
   1619     }
   1620 
   1621     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
   1622         $hasCustomGetter = 1;
   1623     }
   1624 
   1625     if ($interfaceName eq "HTMLDocument") {
   1626         $hasCustomGetter = 0;
   1627     }
   1628 
   1629     my $hasGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $hasCustomGetter;
   1630     if (!$hasGetter) {
   1631         return;
   1632     }
   1633 
   1634     if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomGetter) {
   1635         $implIncludes{"V8Collection.h"} = 1;
   1636         my $type = $namedPropertyGetter->type;
   1637         push(@implContent, <<END);
   1638     setCollectionNamedGetter<${interfaceName}, ${type}>(desc);
   1639 END
   1640         return;
   1641     }
   1642 
   1643     my $hasSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"};
   1644     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
   1645     my $hasEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
   1646     my $setOn = "Instance";
   1647 
   1648     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
   1649     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
   1650     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
   1651     # on the object.
   1652     if ($interfaceName eq "DOMWindow") {
   1653         $setOn = "Prototype";
   1654         $hasDeleter = 0;
   1655         $hasEnumerator = 0;
   1656     }
   1657 
   1658     push(@implContent, "    desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, ");
   1659     push(@implContent, $hasSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, ");
   1660     # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes.
   1661     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, ");
   1662     push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, ");
   1663     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0");
   1664     push(@implContent, ");\n");
   1665 }
   1666 
   1667 sub GenerateImplementationCustomCall
   1668 {
   1669     my $dataNode = shift;
   1670     my $interfaceName = $dataNode->name;
   1671     my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"};
   1672 
   1673     # FIXME: Remove hard-coded HTMLOptionsCollection reference.
   1674     if ($interfaceName eq "HTMLOptionsCollection") {
   1675         $interfaceName = "HTMLCollection";
   1676         $hasCustomCall = 1;
   1677     }
   1678 
   1679     if ($hasCustomCall) {
   1680         push(@implContent, "    desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n");
   1681     }
   1682 }
   1683 
   1684 sub GenerateImplementationMasqueradesAsUndefined
   1685 {
   1686     my $dataNode = shift;
   1687     if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
   1688     {
   1689         push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
   1690     }
   1691 }
   1692 
   1693 sub GenerateImplementation
   1694 {
   1695     my $object = shift;
   1696     my $dataNode = shift;
   1697     my $interfaceName = $dataNode->name;
   1698     my $visibleInterfaceName = GetVisibleInterfaceName($interfaceName);
   1699     my $className = "V8$interfaceName";
   1700     my $implClassName = $interfaceName;
   1701     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
   1702 
   1703     # - Add default header template
   1704     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
   1705          
   1706     $implIncludes{"RuntimeEnabledFeatures.h"} = 1;
   1707     $implIncludes{"V8Proxy.h"} = 1;
   1708     $implIncludes{"V8Binding.h"} = 1;
   1709     $implIncludes{"V8BindingState.h"} = 1;
   1710     $implIncludes{"V8DOMWrapper.h"} = 1;
   1711     $implIncludes{"V8IsolatedContext.h"} = 1;
   1712 
   1713     AddIncludesForType($interfaceName);
   1714 
   1715     my $toActive = IsActiveDomType($interfaceName) ? "${className}::toActiveDOMObject" : "0";
   1716 
   1717     # Find the super descriptor.
   1718     my $parentClass = "";
   1719     my $parentClassTemplate = "";
   1720     foreach (@{$dataNode->parents}) {
   1721         my $parent = $codeGenerator->StripModule($_);
   1722         if ($parent eq "EventTarget") {
   1723             next;
   1724         }
   1725         $implIncludes{"V8${parent}.h"} = 1;
   1726         $parentClass = "V8" . $parent;
   1727         $parentClassTemplate = $parentClass . "::GetTemplate()";
   1728         last;
   1729     }
   1730     push(@implContentDecls, "namespace WebCore {\n\n");
   1731     my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
   1732     push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n");   
   1733     push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n");
   1734     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
   1735 
   1736     my $hasConstructors = 0;
   1737     my $serializedAttribute;
   1738     # Generate property accessors for attributes.
   1739     for ($index = 0; $index < @{$dataNode->attributes}; $index++) {
   1740         $attribute = @{$dataNode->attributes}[$index];
   1741         $attrName = $attribute->signature->name;
   1742         $attrType = $attribute->signature->type;
   1743 
   1744         # Generate special code for the constructor attributes.
   1745         if ($attrType =~ /Constructor$/) {
   1746             if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
   1747                 $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
   1748                 $hasConstructors = 1;
   1749             }
   1750             next;
   1751         }
   1752 
   1753         if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
   1754             $attribute->signature->extendedAttributes->{"v8OnProto"} = 1;
   1755         }
   1756 
   1757         # Attributes of type SerializedScriptValue are set in the
   1758         # constructor and don't require callbacks.
   1759         if ($attrType eq "SerializedScriptValue") {
   1760             die "Only one attribute of type SerializedScriptValue supported" if $serializedAttribute;
   1761             $implIncludes{"SerializedScriptValue.h"} = 1;
   1762             $serializedAttribute = $attribute;
   1763             next;
   1764         }
   1765 
   1766         # Do not generate accessor if this is a custom attribute.  The
   1767         # call will be forwarded to a hand-written accessor
   1768         # implementation.
   1769         if ($attribute->signature->extendedAttributes->{"Custom"} ||
   1770             $attribute->signature->extendedAttributes->{"V8Custom"}) {
   1771             next;
   1772         }
   1773 
   1774         # Generate the accessor.
   1775         if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
   1776             $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
   1777             GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName);
   1778         }
   1779         if (!$attribute->signature->extendedAttributes->{"CustomSetter"} &&
   1780             !$attribute->signature->extendedAttributes->{"V8CustomSetter"} &&
   1781             !$attribute->signature->extendedAttributes->{"Replaceable"} &&
   1782             $attribute->type !~ /^readonly/ &&
   1783             !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
   1784             GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName);
   1785         }
   1786     }
   1787 
   1788     if ($hasConstructors) {
   1789         GenerateConstructorGetter($implClassName);
   1790     }
   1791 
   1792     $codeGenerator->LinkOverloadedFunctions($dataNode);
   1793 
   1794     my $indexer;
   1795     my $namedPropertyGetter;
   1796     # Generate methods for functions.
   1797     foreach my $function (@{$dataNode->functions}) {
   1798         if (!($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"})) {
   1799             GenerateFunctionCallback($function, $dataNode, $implClassName);
   1800             if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
   1801                 GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
   1802             }
   1803         }
   1804 
   1805         if ($function->signature->name eq "item") {
   1806             $indexer = $function->signature;
   1807         }
   1808 
   1809         if ($function->signature->name eq "namedItem") {
   1810             $namedPropertyGetter = $function->signature;
   1811         }
   1812 
   1813         # If the function does not need domain security check, we need to
   1814         # generate an access getter that returns different function objects
   1815         # for different calling context.
   1816         if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
   1817             GenerateDomainSafeFunctionGetter($function, $implClassName);
   1818         }
   1819     }
   1820 
   1821     # Attributes
   1822     my $attributes = $dataNode->attributes;
   1823 
   1824     # For the DOMWindow interface we partition the attributes into the
   1825     # ones that disallows shadowing and the rest.
   1826     my @disallowsShadowing;
   1827     # Also separate out attributes that are enabled at runtime so we can process them specially.
   1828     my @enabledAtRuntime;
   1829     my @normal;
   1830     foreach my $attribute (@$attributes) {
   1831 
   1832         if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) {
   1833             push(@disallowsShadowing, $attribute);
   1834         } elsif ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) {
   1835             push(@enabledAtRuntime, $attribute);
   1836         } else {
   1837             push(@normal, $attribute);
   1838         }
   1839     }
   1840     $attributes = \@normal;
   1841     # Put the attributes that disallow shadowing on the shadow object.
   1842     if (@disallowsShadowing) {
   1843         push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n");
   1844         GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
   1845         push(@implContent, "};\n");
   1846     }
   1847 
   1848     my $has_attributes = 0;
   1849     if (@$attributes && (@$attributes > 1 || $$attributes[0]->signature->type ne "SerializedScriptValue")) {
   1850         $has_attributes = 1;
   1851         push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n");
   1852         GenerateBatchedAttributeData($dataNode, $attributes);
   1853         push(@implContent, "};\n");
   1854     }
   1855 
   1856     # Setup table of standard callback functions
   1857     $num_callbacks = 0;
   1858     $has_callbacks = 0;
   1859     foreach my $function (@{$dataNode->functions}) {
   1860         # Only one table entry is needed for overloaded methods:
   1861         next if $function->{overloadIndex} > 1;
   1862 
   1863         my $attrExt = $function->signature->extendedAttributes;
   1864         # Don't put any nonstandard functions into this table:
   1865         if ($attrExt->{"V8OnInstance"}) {
   1866             next;
   1867         }
   1868         if ($attrExt->{"ClassMethod"}) {
   1869             next;
   1870         }
   1871         if ($attrExt->{"EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) {
   1872             next;
   1873         }
   1874         if ($attrExt->{"DoNotCheckDomainSecurity"} &&
   1875             ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
   1876             next;
   1877         }
   1878         if ($attrExt->{"DontEnum"} || $attrExt->{"V8ReadOnly"}) {
   1879             next;
   1880         }
   1881         if (!$has_callbacks) {
   1882             $has_callbacks = 1;
   1883             push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n");
   1884         }
   1885         my $name = $function->signature->name;
   1886         my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
   1887         push(@implContent, <<END);
   1888     {"$name", $callback},
   1889 END
   1890         $num_callbacks++;
   1891     }
   1892     push(@implContent, "};\n")  if $has_callbacks;
   1893 
   1894     # Setup constants
   1895     my $has_constants = 0;
   1896     if (@{$dataNode->constants}) {
   1897         $has_constants = 1;
   1898         push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n");
   1899     }
   1900     foreach my $constant (@{$dataNode->constants}) {
   1901         my $name = $constant->name;
   1902         my $value = $constant->value;
   1903         # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
   1904         # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
   1905         # handled this here, and converted it to a -1 constant in the c++ output.
   1906         push(@implContent, <<END);
   1907     {"${name}", static_cast<signed int>($value)},
   1908 END
   1909     }
   1910     if ($has_constants) {
   1911         push(@implContent, "};\n");
   1912         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
   1913     }
   1914 
   1915     push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n");
   1916 
   1917     # In namespace WebCore, add generated implementation for 'CanBeConstructed'.
   1918     if ($dataNode->extendedAttributes->{"CanBeConstructed"} && !$dataNode->extendedAttributes->{"CustomConstructor"} && !$dataNode->extendedAttributes->{"V8CustomConstructor"}) {
   1919         my $v8ConstructFunction;
   1920         my $callWith = $dataNode->extendedAttributes->{"CallWith"};
   1921         if ($callWith and $callWith eq "ScriptExecutionContext") {
   1922             $v8ConstructFunction = "constructDOMObjectWithScriptExecutionContext";
   1923         } else {
   1924             $v8ConstructFunction = "constructDOMObject";
   1925         }
   1926         push(@implContent, <<END);
   1927 v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args)
   1928 {
   1929     INC_STATS("DOM.${interfaceName}.Contructor");
   1930     return V8Proxy::${v8ConstructFunction}<$interfaceName>(args, &info);
   1931 }
   1932 END
   1933    }
   1934 
   1935     my $access_check = "";
   1936     if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) {
   1937         $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
   1938     }
   1939 
   1940     # For the DOMWindow interface, generate the shadow object template
   1941     # configuration method.
   1942     if ($implClassName eq "DOMWindow") {
   1943         push(@implContent, <<END);
   1944 static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ)
   1945 {
   1946     batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));
   1947 
   1948     // Install a security handler with V8.
   1949     templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
   1950     templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
   1951     return templ;
   1952 }
   1953 END
   1954     }
   1955 
   1956     if (!$parentClassTemplate) {
   1957         $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
   1958     }
   1959 
   1960     # Generate the template configuration method
   1961     push(@implContent,  <<END);
   1962 static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc)
   1963 {
   1964     v8::Local<v8::Signature> defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount,
   1965 END
   1966     # Set up our attributes if we have them
   1967     if ($has_attributes) {
   1968         push(@implContent, <<END);
   1969         ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs),
   1970 END
   1971     } else {
   1972         push(@implContent, <<END);
   1973         0, 0,
   1974 END
   1975     }
   1976 
   1977     if ($has_callbacks) {
   1978         push(@implContent, <<END);
   1979         ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
   1980 END
   1981     } else {
   1982         push(@implContent, <<END);
   1983         0, 0);
   1984     UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
   1985 END
   1986         $implIncludes{"wtf/UnusedParam.h"} = 1;
   1987     }
   1988 
   1989     if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) {
   1990         push(@implContent, <<END);
   1991         desc->SetCallHandler(V8${interfaceName}::constructorCallback);
   1992 END
   1993     }
   1994 
   1995     if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) {
   1996         push(@implContent,  <<END);
   1997     v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
   1998     v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
   1999 END
   2000     }
   2001 
   2002     push(@implContent,  "    $access_check\n");
   2003 
   2004     # Setup the enable-at-runtime attrs if we have them
   2005     foreach my $runtime_attr (@enabledAtRuntime) {
   2006         my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature);
   2007         my $conditionalString = GenerateConditionalString($runtime_attr->signature);
   2008         push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
   2009         push(@implContent, "    if (${enable_function}()) {\n");
   2010         push(@implContent, "        static const BatchedAttribute attrData =\\\n");
   2011         GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
   2012         push(@implContent, <<END);
   2013         configureAttribute(instance, proto, attrData);
   2014     }
   2015 END
   2016         push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
   2017     }
   2018 
   2019     GenerateImplementationIndexer($dataNode, $indexer);
   2020     GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter);
   2021     GenerateImplementationCustomCall($dataNode);
   2022     GenerateImplementationMasqueradesAsUndefined($dataNode);
   2023 
   2024     # Define our functions with Set() or SetAccessor()
   2025     $total_functions = 0;
   2026     foreach my $function (@{$dataNode->functions}) {
   2027         # Only one accessor is needed for overloaded methods:
   2028         next if $function->{overloadIndex} > 1;
   2029 
   2030         $total_functions++;
   2031         my $attrExt = $function->signature->extendedAttributes;
   2032         my $name = $function->signature->name;
   2033 
   2034         my $property_attributes = "v8::DontDelete";
   2035         if ($attrExt->{"DontEnum"}) {
   2036             $property_attributes .= " | v8::DontEnum";
   2037         }
   2038         if ($attrExt->{"V8ReadOnly"}) {
   2039             $property_attributes .= " | v8::ReadOnly";
   2040         }
   2041 
   2042         my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
   2043 
   2044         my $template = "proto";
   2045         if ($attrExt->{"V8OnInstance"}) {
   2046             $template = "instance";
   2047         }
   2048         if ($attrExt->{"ClassMethod"}) {
   2049             $template = "desc";
   2050         }
   2051 
   2052         my $conditional = "";
   2053         if ($attrExt->{"EnabledAtRuntime"}) {
   2054             # Only call Set()/SetAccessor() if this method should be enabled
   2055             $enable_function = GetRuntimeEnableFunctionName($function->signature);
   2056             $conditional = "if (${enable_function}())\n        ";
   2057         }
   2058 
   2059         if ($attrExt->{"DoNotCheckDomainSecurity"} &&
   2060             ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) {
   2061             # Mark the accessor as ReadOnly and set it on the proto object so
   2062             # it can be shadowed. This is really a hack to make it work.
   2063             # There are several sceneria to call into the accessor:
   2064             #   1) from the same domain: "window.open":
   2065             #      the accessor finds the DOM wrapper in the proto chain;
   2066             #   2) from the same domain: "window.__proto__.open":
   2067             #      the accessor will NOT find a DOM wrapper in the prototype chain
   2068             #   3) from another domain: "window.open":
   2069             #      the access find the DOM wrapper in the prototype chain
   2070             #   "window.__proto__.open" from another domain will fail when
   2071             #   accessing '__proto__'
   2072             #
   2073             # The solution is very hacky and fragile, it really needs to be replaced
   2074             # by a better solution.
   2075             $property_attributes .= " | v8::ReadOnly";
   2076             push(@implContent, <<END);
   2077 
   2078     // $commentInfo
   2079     ${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));
   2080 END
   2081           $num_callbacks++;
   2082           next;
   2083       }
   2084 
   2085       my $signature = "defaultSignature";
   2086       if ($attrExt->{"V8DoNotCheckSignature"} || $attrExt->{"ClassMethod"}) {
   2087           $signature = "v8::Local<v8::Signature>()";
   2088       }
   2089 
   2090       if (RequiresCustomSignature($function)) {
   2091           $signature = "${name}Signature";
   2092           push(@implContent, "\n    // Custom Signature '$name'\n", CreateCustomSignature($function));
   2093       }
   2094 
   2095       # Normal function call is a template
   2096       my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
   2097 
   2098       if ($property_attributes eq "v8::DontDelete") {
   2099           $property_attributes = "";
   2100       } else {
   2101           $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)";
   2102       }
   2103 
   2104       if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") {
   2105           # Standard type of callback, already created in the batch, so skip it here.
   2106           next;
   2107       }
   2108 
   2109       push(@implContent, <<END);
   2110     ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes);
   2111 END
   2112       $num_callbacks++;
   2113     }
   2114 
   2115     die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions;
   2116 
   2117     if ($has_constants) {
   2118         push(@implContent, <<END);
   2119     batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts));
   2120 END
   2121     }
   2122 
   2123     # Special cases
   2124     if ($interfaceName eq "DOMWindow") {
   2125         push(@implContent, <<END);
   2126 
   2127     proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
   2128     desc->SetHiddenPrototype(true);
   2129     instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
   2130     // Set access check callbacks, but turned off initially.
   2131     // When a context is detached from a frame, turn on the access check.
   2132     // Turning on checks also invalidates inline caches of the object.
   2133     instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
   2134 END
   2135     }
   2136     if ($interfaceName eq "HTMLDocument") {
   2137         push(@implContent, <<END);
   2138     desc->SetHiddenPrototype(true);
   2139 END
   2140     }
   2141     if ($interfaceName eq "Location") {
   2142         push(@implContent, <<END);
   2143 
   2144     // For security reasons, these functions are on the instance instead
   2145     // of on the prototype object to ensure that they cannot be overwritten.
   2146     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));
   2147     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));
   2148     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));
   2149 END
   2150     }
   2151 
   2152     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
   2153     push(@implContent, <<END);
   2154 
   2155     // Custom toString template
   2156     desc->Set(getToStringName(), getToStringTemplate());
   2157     return desc;
   2158 }
   2159 
   2160 v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
   2161 {
   2162     static v8::Persistent<v8::FunctionTemplate> ${className}RawCache = createRawTemplate();
   2163     return ${className}RawCache;
   2164 }
   2165 
   2166 v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\
   2167 {
   2168     static v8::Persistent<v8::FunctionTemplate> ${className}Cache = Configure${className}Template(GetRawTemplate());
   2169     return ${className}Cache;
   2170 }
   2171 
   2172 bool ${className}::HasInstance(v8::Handle<v8::Value> value)
   2173 {
   2174     return GetRawTemplate()->HasInstance(value);
   2175 }
   2176 
   2177 END
   2178 
   2179     if (IsActiveDomType($interfaceName)) {
   2180         # MessagePort is handled like an active dom object even though it doesn't inherit
   2181         # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject.
   2182         my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)";
   2183         push(@implContent, <<END);
   2184 ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
   2185 {
   2186     return ${returnValue};
   2187 }      
   2188 END
   2189     }
   2190 
   2191     if ($implClassName eq "DOMWindow") {
   2192         push(@implContent, <<END);
   2193 v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate()
   2194 {
   2195     static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache;
   2196     if (V8DOMWindowShadowObjectCache.IsEmpty()) {
   2197         V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
   2198         ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache);
   2199     }
   2200     return V8DOMWindowShadowObjectCache;
   2201 }
   2202 END
   2203     }
   2204 
   2205     GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute);
   2206 
   2207     push(@implContent, <<END);
   2208 
   2209 void ${className}::derefObject(void* object)
   2210 {
   2211 END
   2212 
   2213     if (IsRefPtrType($interfaceName)) {
   2214         push(@implContent, <<END);
   2215     static_cast<${nativeType}*>(object)->deref();
   2216 END
   2217     }
   2218 
   2219     push(@implContent, <<END);
   2220 }
   2221 
   2222 } // namespace WebCore
   2223 END
   2224 
   2225     my $conditionalString = GenerateConditionalString($dataNode);
   2226     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
   2227     
   2228     # We've already added the header for this file in implFixedHeader, so remove
   2229     # it from implIncludes to ensure we don't #include it twice.
   2230     delete $implIncludes{"${className}.h"};
   2231 }
   2232 
   2233 sub GenerateHeaderContentHeader
   2234 {
   2235     my $dataNode = shift;
   2236     my $className = "V8" . $dataNode->name;
   2237     my $conditionalString = GenerateConditionalString($dataNode);
   2238 
   2239     my @headerContentHeader = split("\r", $headerTemplate);
   2240 
   2241     push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString;
   2242     push(@headerContentHeader, "\n#ifndef ${className}" . "_h");
   2243     push(@headerContentHeader, "\n#define ${className}" . "_h\n\n");
   2244     return @headerContentHeader;
   2245 }
   2246 
   2247 sub GenerateImplementationContentHeader
   2248 {
   2249     my $dataNode = shift;
   2250     my $className = "V8" . $dataNode->name;
   2251     my $conditionalString = GenerateConditionalString($dataNode);
   2252 
   2253     my @implContentHeader = split("\r", $headerTemplate);
   2254 
   2255     push(@implContentHeader, "\n#include \"config.h\"\n");
   2256     push(@implContentHeader, "#include \"${className}.h\"\n\n");
   2257     push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
   2258     return @implContentHeader;
   2259 }
   2260 
   2261 sub GenerateCallbackHeader
   2262 {
   2263     my $object = shift;
   2264     my $dataNode = shift;
   2265 
   2266     my $interfaceName = $dataNode->name;
   2267     my $className = "V8$interfaceName";
   2268 
   2269 
   2270     # - Add default header template
   2271     push(@headerContent, GenerateHeaderContentHeader($dataNode));
   2272 
   2273     my @unsortedIncludes = ();
   2274     push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\"");
   2275     push(@unsortedIncludes, "#include \"$interfaceName.h\"");
   2276     push(@unsortedIncludes, "#include \"WorldContextHandle.h\"");
   2277     push(@unsortedIncludes, "#include <v8.h>");
   2278     push(@unsortedIncludes, "#include <wtf/Forward.h>");
   2279     push(@headerContent, join("\n", sort @unsortedIncludes));
   2280     
   2281     push(@headerContent, "\n\nnamespace WebCore {\n\n");
   2282     push(@headerContent, "class ScriptExecutionContext;\n\n");
   2283     push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
   2284 
   2285     push(@headerContent, <<END);
   2286 public:
   2287     static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context)
   2288     {
   2289         ASSERT(value->IsObject());
   2290         ASSERT(context);
   2291         return adoptRef(new ${className}(value->ToObject(), context));
   2292     }
   2293 
   2294     virtual ~${className}();
   2295 
   2296 END
   2297 
   2298     # Functions
   2299     my $numFunctions = @{$dataNode->functions};
   2300     if ($numFunctions > 0) {
   2301         push(@headerContent, "    // Functions\n");
   2302         foreach my $function (@{$dataNode->functions}) {
   2303             my @params = @{$function->parameters};
   2304             if (!$function->signature->extendedAttributes->{"Custom"} &&
   2305                 !(GetNativeType($function->signature->type) eq "bool")) {
   2306                     push(@headerContent, "    COMPILE_ASSERT(false)");
   2307             }
   2308 
   2309             push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
   2310 
   2311             my @args = ();
   2312             foreach my $param (@params) {
   2313                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
   2314             }
   2315             push(@headerContent, join(", ", @args));
   2316             push(@headerContent, ");\n");
   2317         }
   2318     }
   2319 
   2320     push(@headerContent, <<END);
   2321 
   2322 private:
   2323     ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);
   2324 
   2325     v8::Persistent<v8::Object> m_callback;
   2326     WorldContextHandle m_worldContext;
   2327 };
   2328 
   2329 END
   2330 
   2331     push(@headerContent, "}\n\n");
   2332     push(@headerContent, "#endif // $className" . "_h\n\n");
   2333 
   2334     my $conditionalString = GenerateConditionalString($dataNode);
   2335     push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
   2336 }
   2337 
   2338 sub GenerateCallbackImplementation
   2339 {
   2340     my $object = shift;
   2341     my $dataNode = shift;
   2342     my $interfaceName = $dataNode->name;
   2343     my $className = "V8$interfaceName";
   2344 
   2345     # - Add default header template
   2346     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
   2347          
   2348     $implIncludes{"ScriptExecutionContext.h"} = 1;
   2349     $implIncludes{"V8Binding.h"} = 1;
   2350     $implIncludes{"V8CustomVoidCallback.h"} = 1;
   2351     $implIncludes{"V8Proxy.h"} = 1;
   2352 
   2353     push(@implContent, "#include <wtf/Assertions.h>\n\n");
   2354     push(@implContent, "namespace WebCore {\n\n");
   2355     push(@implContent, <<END);
   2356 ${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context)
   2357     : ActiveDOMCallback(context)
   2358     , m_callback(v8::Persistent<v8::Object>::New(callback))
   2359     , m_worldContext(UseCurrentWorld)
   2360 {
   2361 }
   2362 
   2363 ${className}::~${className}()
   2364 {
   2365     m_callback.Dispose();
   2366 }
   2367 
   2368 END
   2369 
   2370     # Functions
   2371     my $numFunctions = @{$dataNode->functions};
   2372     if ($numFunctions > 0) {
   2373         push(@implContent, "// Functions\n");
   2374         foreach my $function (@{$dataNode->functions}) {
   2375             my @params = @{$function->parameters};
   2376             if ($function->signature->extendedAttributes->{"Custom"} ||
   2377                 !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) {
   2378                 next;
   2379             }
   2380 
   2381             AddIncludesForType($function->signature->type);
   2382             push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
   2383 
   2384             my @args = ();
   2385             foreach my $param (@params) {
   2386                 AddIncludesForType($param->type);
   2387                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
   2388             }
   2389             push(@implContent, join(", ", @args));
   2390 
   2391             push(@implContent, ")\n");
   2392             push(@implContent, "{\n");
   2393             push(@implContent, "    if (!canInvokeCallback())\n");
   2394             push(@implContent, "        return true;\n\n");
   2395             push(@implContent, "    v8::HandleScope handleScope;\n\n");
   2396             push(@implContent, "    v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n");
   2397             push(@implContent, "    if (v8Context.IsEmpty())\n");
   2398             push(@implContent, "        return true;\n\n");
   2399             push(@implContent, "    v8::Context::Scope scope(v8Context);\n\n");
   2400 
   2401             @args = ();
   2402             foreach my $param (@params) {
   2403                 my $paramName = $param->name;
   2404                 push(@implContent, "    v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName) . ";\n");
   2405                 push(@implContent, "    if (${paramName}Handle.IsEmpty()) {\n");
   2406                 push(@implContent, "        CRASH();\n");
   2407                 push(@implContent, "        return true;\n");
   2408                 push(@implContent, "    }\n");
   2409                 push(@args, "        ${paramName}Handle");
   2410             }
   2411 
   2412             if (scalar(@args) > 0) {
   2413                 push(@implContent, "\n    v8::Handle<v8::Value> argv[] = {\n");
   2414                 push(@implContent, join(",\n", @args));
   2415                 push(@implContent, "\n    };\n\n");
   2416             } else {
   2417                 push(@implContent, "\n    v8::Handle<v8::Value> *argv = 0;\n\n");
   2418             }
   2419             push(@implContent, "    bool callbackReturnValue = false;\n");
   2420             push(@implContent, "    return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
   2421             push(@implContent, "}\n");
   2422         }
   2423     }
   2424 
   2425     push(@implContent, "\n} // namespace WebCore\n\n");
   2426 
   2427     my $conditionalString = GenerateConditionalString($dataNode);
   2428     push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
   2429 }
   2430 
   2431 sub GenerateToV8Converters
   2432 {
   2433     my $dataNode = shift;
   2434     my $interfaceName = shift;
   2435     my $className = shift;
   2436     my $nativeType = shift;
   2437     my $serializedAttribute = shift;
   2438 
   2439     my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName);
   2440     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
   2441     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
   2442 
   2443     push(@implContent, <<END);
   2444 
   2445 v8::Handle<v8::Object> ${className}::wrapSlow(${nativeType}* impl)
   2446 {
   2447     v8::Handle<v8::Object> wrapper;
   2448     V8Proxy* proxy = 0;
   2449 END
   2450 
   2451     if (IsNodeSubType($dataNode)) {
   2452         push(@implContent, <<END);
   2453     if (impl->document()) {
   2454         proxy = V8Proxy::retrieve(impl->document()->frame());
   2455         if (proxy && static_cast<Node*>(impl->document()) == static_cast<Node*>(impl)) {
   2456             if (proxy->windowShell()->initContextIfNeeded()) {
   2457                 // initContextIfNeeded may have created a wrapper for the object, retry from the start.
   2458                 return ${className}::wrap(impl);
   2459             }
   2460         }
   2461     }
   2462 
   2463 END
   2464     }
   2465 
   2466     if (IsNodeSubType($dataNode)) {
   2467         push(@implContent, <<END);
   2468 
   2469     v8::Handle<v8::Context> context;
   2470     if (proxy)
   2471         context = proxy->context();
   2472 
   2473     // Enter the node's context and create the wrapper in that context.
   2474     if (!context.IsEmpty())
   2475         context->Enter();
   2476 END
   2477     }
   2478 
   2479     push(@implContent, <<END);
   2480     wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl);
   2481 END
   2482     if (IsNodeSubType($dataNode)) {
   2483         push(@implContent, <<END);
   2484     // Exit the node's context if it was entered.
   2485     if (!context.IsEmpty())
   2486         context->Exit();
   2487 END
   2488     }
   2489 
   2490     push(@implContent, <<END);
   2491     if (wrapper.IsEmpty())
   2492         return wrapper;
   2493 END
   2494     push(@implContent, "\n    impl->ref();\n") if IsRefPtrType($interfaceName);
   2495 
   2496     # Eagerly deserialize attributes of type SerializedScriptValue
   2497     # while we're in the right context.
   2498     if ($serializedAttribute) {
   2499         die "Attribute of type SerializedScriptValue expected" if $serializedAttribute->signature->type ne "SerializedScriptValue";
   2500         my $attrName = $serializedAttribute->signature->name;
   2501         my $attrAttr = "v8::DontDelete";
   2502         if ($serializedAttribute->type =~ /^readonly/) {
   2503             $attrAttr .= " | v8::ReadOnly";
   2504         }
   2505         $attrAttr = "static_cast<v8::PropertyAttribute>($attrAttr)";
   2506         my $getterFunc = $codeGenerator->WK_lcfirst($attrName);
   2507         push(@implContent, <<END);
   2508     SerializedScriptValue::deserializeAndSetProperty(wrapper, "${attrName}", ${attrAttr}, impl->${getterFunc}());
   2509 END
   2510     }
   2511 
   2512     push(@implContent, <<END);
   2513     v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);
   2514 END
   2515     if (IsNodeSubType($dataNode)) {
   2516         push(@implContent, <<END);
   2517     wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
   2518 END
   2519     }    
   2520     push(@implContent, <<END);
   2521     ${domMapFunction}.set(impl, wrapperHandle);
   2522 END
   2523 
   2524     push(@implContent, <<END);
   2525     return wrapper;
   2526 }
   2527 END
   2528 }
   2529 
   2530 sub HasCustomToV8Implementation {
   2531     # FIXME: This subroutine is lame. Probably should be an .idl attribute (CustomToV8)?
   2532     $dataNode = shift;
   2533     $interfaceName = shift;
   2534 
   2535     # We generate a custom converter (but JSC doesn't) for the following:
   2536     return 1 if $interfaceName eq "CSSStyleSheet";
   2537     return 1 if $interfaceName eq "CanvasPixelArray";
   2538     return 1 if $interfaceName eq "DOMStringMap";
   2539     return 1 if $interfaceName eq "DOMWindow";
   2540     return 1 if $interfaceName eq "DOMTokenList";
   2541     return 1 if $interfaceName eq "Element";
   2542     return 1 if $interfaceName eq "HTMLDocument";
   2543     return 1 if $interfaceName eq "HTMLElement";
   2544     return 1 if $interfaceName eq "Location";
   2545     return 1 if $interfaceName eq "NamedNodeMap";
   2546     return 1 if $interfaceName eq "SVGDocument";
   2547     return 1 if $interfaceName eq "SVGElement";
   2548     return 1 if $interfaceName eq "ScriptProfile";
   2549     return 1 if $interfaceName eq "ScriptProfileNode";
   2550     return 1 if $interfaceName eq "WorkerContext";
   2551     # We don't generate a custom converter (but JSC does) for the following:
   2552     return 0 if $interfaceName eq "AbstractWorker";
   2553     return 0 if $interfaceName eq "CanvasRenderingContext";
   2554     return 0 if $interfaceName eq "SVGElementInstance";
   2555     return 0 if $interfaceName eq "NodeList";
   2556 
   2557     # For everything else, do what JSC does.
   2558     return $dataNode->extendedAttributes->{"CustomToJS"};
   2559 }
   2560 
   2561 sub GetDomMapFunction
   2562 {
   2563     my $dataNode = shift;
   2564     my $type = shift;
   2565     return "getDOMSVGElementInstanceMap()" if $type eq "SVGElementInstance";
   2566     return "getDOMNodeMap()" if ($dataNode && IsNodeSubType($dataNode));
   2567     return "getActiveDOMObjectMap()" if IsActiveDomType($type);
   2568     return "getDOMObjectMap()";
   2569 }
   2570 
   2571 sub IsActiveDomType
   2572 {
   2573     # FIXME: Consider making this an .idl attribute.
   2574     my $type = shift;
   2575     return 1 if $type eq "EventSource";
   2576     return 1 if $type eq "MessagePort";
   2577     return 1 if $type eq "XMLHttpRequest";
   2578     return 1 if $type eq "WebSocket";
   2579     return 1 if $type eq "Worker";
   2580     return 1 if $type eq "SharedWorker";
   2581     return 1 if $type eq "IDBRequest";
   2582     return 1 if $type eq "IDBTransaction";
   2583     return 1 if $type eq "FileReader";
   2584     return 1 if $type eq "FileWriter";
   2585     return 0;
   2586 }
   2587 
   2588 sub GetNativeTypeForConversions
   2589 {
   2590     my $dataNode = shift;
   2591     my $type = shift;
   2592 
   2593     $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); 
   2594     return $type;
   2595 }
   2596 
   2597 sub GenerateFunctionCallString()
   2598 {
   2599     my $function = shift;
   2600     my $numberOfParameters = shift;
   2601     my $indent = shift;
   2602     my $implClassName = shift;
   2603 
   2604     my $name = $function->signature->name;
   2605     my $returnType = GetTypeFromSignature($function->signature);
   2606     my $nativeReturnType = GetNativeType($returnType, 0);
   2607     my $result = "";
   2608 
   2609     my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/);
   2610     $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType;
   2611 
   2612     if ($function->signature->extendedAttributes->{"v8implname"}) {
   2613         $name = $function->signature->extendedAttributes->{"v8implname"};
   2614     }
   2615 
   2616     if ($function->signature->extendedAttributes->{"ImplementationFunction"}) {
   2617         $name = $function->signature->extendedAttributes->{"ImplementationFunction"};
   2618     }
   2619 
   2620     my $functionString = "imp->${name}(";
   2621     if ($function->signature->extendedAttributes->{"ClassMethod"}) {
   2622         $functionString = "${implClassName}::${name}(";
   2623     }
   2624 
   2625     my $index = 0;
   2626     my $hasScriptState = 0;
   2627 
   2628     my $callWith = $function->signature->extendedAttributes->{"CallWith"};
   2629     if ($callWith) {
   2630         my $callWithArg = "COMPILE_ASSERT(false)";
   2631         if ($callWith eq "DynamicFrame") {
   2632             $result .= $indent . "Frame* enteredFrame = V8Proxy::retrieveFrameForEnteredContext();\n";
   2633             $result .= $indent . "if (!enteredFrame)\n";
   2634             $result .= $indent . "    return v8::Undefined();\n";
   2635             $callWithArg = "enteredFrame";
   2636         } elsif ($callWith eq "ScriptState") {
   2637             $result .= $indent . "EmptyScriptState state;\n";
   2638             $callWithArg = "&state";
   2639             $hasScriptState = 1;
   2640         } elsif ($callWith eq "ScriptExecutionContext") {
   2641             $result .= $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n";
   2642             $result .= $indent . "if (!scriptContext)\n";
   2643             $result .= $indent . "    return v8::Undefined();\n";
   2644             $callWithArg = "scriptContext";
   2645         }
   2646         $functionString .= ", " if $index;
   2647         $functionString .= $callWithArg;
   2648         $index++;
   2649         $numberOfParameters++
   2650     }
   2651 
   2652     foreach my $parameter (@{$function->parameters}) {
   2653         if ($index eq $numberOfParameters) {
   2654             last;
   2655         }
   2656         $functionString .= ", " if $index;
   2657         my $paramName = $parameter->name;
   2658         my $paramType = $parameter->type;
   2659 
   2660         if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
   2661             $functionString .= "$paramName.get()";
   2662         } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) {
   2663             $functionString .= "$paramName->propertyReference()";
   2664             $result .= $indent . "if (!$paramName) {\n";
   2665             $result .= $indent . "    V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR);\n";
   2666             $result .= $indent . "    return v8::Handle<v8::Value>();\n";
   2667             $result .= $indent . "}\n";
   2668         } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") {
   2669             $functionString .= "$paramName.get()";
   2670         } else {
   2671             $functionString .= $paramName;
   2672         }
   2673         $index++;
   2674     }
   2675 
   2676     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
   2677         $functionString .= ", " if $index;
   2678         $functionString .= "scriptArguments, callStack";
   2679         $index += 2;
   2680     }
   2681 
   2682     if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) {
   2683         $functionString .= ", " if $index;
   2684         # FIXME: We need to pass DOMWrapperWorld as a parameter.
   2685         # See http://trac.webkit.org/changeset/54182
   2686         $functionString .= "processingUserGesture()";
   2687         $index++;
   2688     }
   2689 
   2690     if (@{$function->raisesExceptions}) {
   2691         $functionString .= ", " if $index;
   2692         $functionString .= "ec";
   2693         $index++;
   2694     }
   2695     $functionString .= ")";
   2696 
   2697     my $return = "result";
   2698     my $returnIsRef = IsRefPtrType($returnType);
   2699 
   2700     if ($returnType eq "void") {
   2701         $result .= $indent . "$functionString;\n";
   2702     } elsif ($hasScriptState or @{$function->raisesExceptions}) {
   2703         $result .= $indent . $nativeReturnType . " result = $functionString;\n";
   2704     } else {
   2705         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
   2706         $return = $functionString;
   2707         $returnIsRef = 0;
   2708     
   2709         if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) {
   2710             $return = "WTF::getPtr(" . $return . ")";
   2711         }
   2712     }
   2713 
   2714     if (@{$function->raisesExceptions}) {
   2715         $result .= $indent . "if (UNLIKELY(ec))\n";
   2716         $result .= $indent . "    goto fail;\n";
   2717     }
   2718 
   2719     if ($hasScriptState) {
   2720         $result .= $indent . "if (state.hadException())\n";
   2721         $result .= $indent . "    return throwError(state.exception());\n"
   2722     }
   2723 
   2724     if ($isSVGTearOffType) {
   2725         $implIncludes{"V8$returnType.h"} = 1;
   2726         $implIncludes{"SVGPropertyTearOff.h"} = 1;
   2727         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
   2728         $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)));\n";
   2729         return $result;
   2730     }
   2731 
   2732     # If the implementing class is a POD type, commit changes
   2733     if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) {
   2734         $result .= $indent . "wrapper->commitChange();\n";
   2735     }
   2736 
   2737     $return .= ".release()" if ($returnIsRef);
   2738     $result .= $indent . ReturnNativeToJSValue($function->signature, $return, $indent) . ";\n";
   2739 
   2740     return $result;
   2741 }
   2742 
   2743 
   2744 sub GetTypeFromSignature
   2745 {
   2746     my $signature = shift;
   2747 
   2748     return $codeGenerator->StripModule($signature->type);
   2749 }
   2750 
   2751 
   2752 sub GetNativeTypeFromSignature
   2753 {
   2754     my $signature = shift;
   2755     my $parameterIndex = shift;
   2756 
   2757     my $type = GetTypeFromSignature($signature);
   2758 
   2759     if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
   2760         # Special-case index arguments because we need to check that they aren't < 0.
   2761         return "int";
   2762     }
   2763 
   2764     $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0);
   2765 
   2766     if ($parameterIndex >= 0 && $type eq "V8Parameter") {
   2767         my $mode = "";
   2768         if ($signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}) {
   2769             $mode = "WithUndefinedOrNullCheck";
   2770         } elsif ($signature->extendedAttributes->{"ConvertNullToNullString"} || $signature->extendedAttributes->{"Reflect"}) {
   2771             $mode = "WithNullCheck";
   2772         }
   2773         $type .= "<$mode>";
   2774     }
   2775 
   2776     return $type;
   2777 }
   2778 
   2779 sub IsRefPtrType
   2780 {
   2781     my $type = shift;
   2782 
   2783     return 0 if $type eq "boolean";
   2784     return 0 if $type eq "float";
   2785     return 0 if $type eq "int";
   2786     return 0 if $type eq "Date";
   2787     return 0 if $type eq "DOMString";
   2788     return 0 if $type eq "double";
   2789     return 0 if $type eq "short";
   2790     return 0 if $type eq "long";
   2791     return 0 if $type eq "unsigned";
   2792     return 0 if $type eq "unsigned long";
   2793     return 0 if $type eq "unsigned short";
   2794 
   2795     return 1;
   2796 }
   2797 
   2798 sub GetNativeType
   2799 {
   2800     my $type = shift;
   2801     my $isParameter = shift;
   2802 
   2803     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
   2804     if ($svgNativeType) {
   2805         if ($svgNativeType =~ /List$/) {
   2806             return "${svgNativeType}*";
   2807         } else {
   2808             return "RefPtr<${svgNativeType} >";
   2809         }
   2810     }
   2811 
   2812     if ($type eq "float" or $type eq "double") {
   2813         return $type;
   2814     }
   2815 
   2816     return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter;
   2817     return "int" if $type eq "int";
   2818     return "int" if $type eq "short" or $type eq "unsigned short";
   2819     return "unsigned" if $type eq "unsigned long";
   2820     return "int" if $type eq "long";
   2821     return "long long" if $type eq "long long";
   2822     return "unsigned long long" if $type eq "unsigned long long";
   2823     return "bool" if $type eq "boolean";
   2824     return "String" if $type eq "DOMString";
   2825     return "Range::CompareHow" if $type eq "CompareHow";
   2826     return "DOMTimeStamp" if $type eq "DOMTimeStamp";
   2827     return "unsigned" if $type eq "unsigned int";
   2828     return "Node*" if $type eq "EventTarget" and $isParameter;
   2829     return "double" if $type eq "Date";
   2830     return "ScriptValue" if $type eq "DOMObject";
   2831     return "OptionsObject" if $type eq "OptionsObject";
   2832 
   2833     return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?
   2834 
   2835     # temporary hack
   2836     return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
   2837 
   2838     return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
   2839 
   2840     return "RefPtr<IDBKey>" if $type eq "IDBKey";
   2841 
   2842     # necessary as resolvers could be constructed on fly.
   2843     return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";
   2844 
   2845     return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;
   2846 
   2847     return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";
   2848 
   2849     return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList" and $isParameter;
   2850     return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
   2851 
   2852     # Default, assume native type is a pointer with same type name as idl type
   2853     return "${type}*";
   2854 }
   2855 
   2856 sub GetNativeTypeForCallbacks
   2857 {
   2858     my $type = shift;
   2859     return "const String&" if $type eq "DOMString";
   2860 
   2861     # Callbacks use raw pointers, so pass isParameter = 1
   2862     return GetNativeType($type, 1);
   2863 }
   2864 
   2865 sub TranslateParameter
   2866 {
   2867     my $signature = shift;
   2868 
   2869     # The IDL uses some pseudo-types which don't really exist.
   2870     if ($signature->type eq "TimeoutHandler") {
   2871       $signature->type("DOMString");
   2872     }
   2873 }
   2874 
   2875 sub TypeCanFailConversion
   2876 {
   2877     my $signature = shift;
   2878 
   2879     my $type = GetTypeFromSignature($signature);
   2880 
   2881     $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr";
   2882     return 1 if $type eq "Attr";
   2883     return 1 if $type eq "VoidCallback";
   2884     return 1 if $type eq "IDBKey";
   2885     return 0;
   2886 }
   2887 
   2888 sub JSValueToNative
   2889 {
   2890     my $signature = shift;
   2891     my $value = shift;
   2892 
   2893     my $type = GetTypeFromSignature($signature);
   2894 
   2895     return "$value" if $type eq "JSObject";
   2896     return "$value->BooleanValue()" if $type eq "boolean";
   2897     return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
   2898 
   2899     return "toInt32($value)" if $type eq "long" or $type eq "short";
   2900     return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short";
   2901     return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long";
   2902     return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
   2903     return "toWebCoreDate($value)" if $type eq "Date";
   2904     return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList";
   2905 
   2906     if ($type eq "DOMString" or $type eq "DOMUserData") {
   2907         return $value;
   2908     }
   2909 
   2910     die "Unexpected SerializedScriptValue" if $type eq "SerializedScriptValue";
   2911 
   2912     if ($type eq "IDBKey") {
   2913         $implIncludes{"IDBBindingUtilities.h"} = 1;
   2914         $implIncludes{"IDBKey.h"} = 1;
   2915         return "createIDBKeyFromValue($value)";
   2916     }
   2917 
   2918     if ($type eq "OptionsObject") {
   2919         $implIncludes{"OptionsObject.h"} = 1;
   2920         return $value;
   2921     }
   2922 
   2923     if ($type eq "DOMObject") {
   2924         $implIncludes{"ScriptValue.h"} = 1;
   2925         return "ScriptValue($value)";
   2926     }
   2927 
   2928     if ($type eq "NodeFilter") {
   2929         return "V8DOMWrapper::wrapNativeNodeFilter($value)";
   2930     }
   2931 
   2932     if ($type eq "MediaQueryListListener") {
   2933         $implIncludes{"MediaQueryListListener.h"} = 1;
   2934         return "MediaQueryListListener::create(" . $value . ")";
   2935     }
   2936 
   2937     # Default, assume autogenerated type conversion routines
   2938     if ($type eq "EventTarget") {
   2939         $implIncludes{"V8Node.h"} = 1;
   2940 
   2941         # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
   2942         return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
   2943     }
   2944 
   2945     if ($type eq "XPathNSResolver") {
   2946         return "V8DOMWrapper::getXPathNSResolver($value)";
   2947     }
   2948 
   2949     AddIncludesForType($type);
   2950 
   2951     if (IsDOMNodeType($type)) {
   2952         $implIncludes{"V8${type}.h"} = 1;
   2953 
   2954         # Perform type checks on the parameter, if it is expected Node type,
   2955         # return NULL.
   2956         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
   2957     } else {
   2958         $implIncludes{"V8$type.h"} = 1;
   2959 
   2960         # Perform type checks on the parameter, if it is expected Node type,
   2961         # return NULL.
   2962         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
   2963     }
   2964 }
   2965 
   2966 sub GetV8HeaderName
   2967 {
   2968     my $type = shift;
   2969     return "V8Event.h" if $type eq "DOMTimeStamp";
   2970     return "EventListener.h" if $type eq "EventListener";
   2971     return "EventTarget.h" if $type eq "EventTarget";
   2972     return "SerializedScriptValue.h" if $type eq "SerializedScriptValue";
   2973     return "ScriptValue.h" if $type eq "DOMObject";
   2974     return "V8${type}.h";
   2975 }
   2976 
   2977 sub CreateCustomSignature
   2978 {
   2979     my $function = shift;
   2980     my $count = @{$function->parameters};
   2981     my $name = $function->signature->name;
   2982     my $result = "    const int ${name}Argc = ${count};\n" .
   2983       "    v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { ";
   2984     my $first = 1;
   2985     foreach my $parameter (@{$function->parameters}) {
   2986         if ($first) { $first = 0; }
   2987         else { $result .= ", "; }
   2988         if (IsWrapperType($parameter->type)) {
   2989             if ($parameter->type eq "XPathNSResolver") {
   2990                 # Special case for XPathNSResolver.  All other browsers accepts a callable,
   2991                 # so, even though it's against IDL, accept objects here.
   2992                 $result .= "v8::Handle<v8::FunctionTemplate>()";
   2993             } else {
   2994                 my $type = $parameter->type;
   2995                 my $header = GetV8HeaderName($type);
   2996                 $implIncludes{$header} = 1;
   2997                 $result .= "V8${type}::GetRawTemplate()";
   2998             }
   2999         } else {
   3000             $result .= "v8::Handle<v8::FunctionTemplate>()";
   3001         }
   3002     }
   3003     $result .= " };\n";
   3004     $result .= "    v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n";
   3005     return $result;
   3006 }
   3007 
   3008 
   3009 sub RequiresCustomSignature
   3010 {
   3011     my $function = shift;
   3012     # No signature needed for Custom function
   3013     if ($function->signature->extendedAttributes->{"Custom"} ||
   3014         $function->signature->extendedAttributes->{"V8Custom"}) {
   3015         return 0;
   3016     }
   3017     # No signature needed for overloaded function
   3018     if (@{$function->{overloads}} > 1) {
   3019         return 0;
   3020     }
   3021     # Type checking is performed in the generated code
   3022     if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
   3023       return 0;
   3024     }
   3025     foreach my $parameter (@{$function->parameters}) {
   3026         if ($parameter->extendedAttributes->{"Optional"} || $parameter->extendedAttributes->{"Callback"}) {
   3027             return 0;
   3028         }
   3029     }
   3030 
   3031     foreach my $parameter (@{$function->parameters}) {
   3032         if (IsWrapperType($parameter->type)) {
   3033             return 1;
   3034         }
   3035     }
   3036     return 0;
   3037 }
   3038 
   3039 
   3040 # FIXME: Sort this array.
   3041 my %non_wrapper_types = (
   3042     'float' => 1,
   3043     'double' => 1,
   3044     'int' => 1,
   3045     'unsigned int' => 1,
   3046     'short' => 1,
   3047     'unsigned short' => 1,
   3048     'long' => 1,
   3049     'unsigned long' => 1,
   3050     'boolean' => 1,
   3051     'long long' => 1,
   3052     'unsigned long long' => 1,
   3053     'DOMString' => 1,
   3054     'CompareHow' => 1,
   3055     'SerializedScriptValue' => 1,
   3056     'DOMTimeStamp' => 1,
   3057     'JSObject' => 1,
   3058     'DOMObject' => 1,
   3059     'EventTarget' => 1,
   3060     'NodeFilter' => 1,
   3061     'EventListener' => 1,
   3062     'IDBKey' => 1,
   3063     'OptionsObject' => 1,
   3064     'Date' => 1,
   3065     'MediaQueryListListener' => 1
   3066 );
   3067 
   3068 
   3069 sub IsWrapperType
   3070 {
   3071     my $type = $codeGenerator->StripModule(shift);
   3072     return !($non_wrapper_types{$type});
   3073 }
   3074 
   3075 sub IsDOMNodeType
   3076 {
   3077     my $type = shift;
   3078 
   3079     return 1 if $type eq 'Attr';
   3080     return 1 if $type eq 'CDATASection';
   3081     return 1 if $type eq 'Comment';
   3082     return 1 if $type eq 'Document';
   3083     return 1 if $type eq 'DocumentFragment';
   3084     return 1 if $type eq 'DocumentType';
   3085     return 1 if $type eq 'Element';
   3086     return 1 if $type eq 'EntityReference';
   3087     return 1 if $type eq 'HTMLCanvasElement';
   3088     return 1 if $type eq 'HTMLDocument';
   3089     return 1 if $type eq 'HTMLElement';
   3090     return 1 if $type eq 'HTMLFormElement';
   3091     return 1 if $type eq 'HTMLTableCaptionElement';
   3092     return 1 if $type eq 'HTMLTableSectionElement';
   3093     return 1 if $type eq 'Node';
   3094     return 1 if $type eq 'ProcessingInstruction';
   3095     return 1 if $type eq 'SVGElement';
   3096     return 1 if $type eq 'SVGDocument';
   3097     return 1 if $type eq 'SVGSVGElement';
   3098     return 1 if $type eq 'SVGUseElement';
   3099     return 1 if $type eq 'Text';
   3100 
   3101     return 0;
   3102 }
   3103 
   3104 
   3105 sub NativeToJSValue
   3106 {
   3107     my $signature = shift;
   3108     my $value = shift;
   3109     my $indent = shift;
   3110     my $type = GetTypeFromSignature($signature);
   3111 
   3112     return "v8Boolean($value)" if $type eq "boolean";
   3113     return "v8::Handle<v8::Value>()" if $type eq "void";     # equivalent to v8::Undefined()
   3114 
   3115     # HTML5 says that unsigned reflected attributes should be in the range
   3116     # [0, 2^31). When a value isn't in this range, a default value (or 0)
   3117     # should be returned instead.
   3118     if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
   3119         $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
   3120         return "v8::Integer::NewFromUnsigned(std::max(0, " . $value . "))";
   3121     }
   3122 
   3123     # For all the types where we use 'int' as the representation type,
   3124     # we use Integer::New which has a fast Smi conversion check.
   3125     my $nativeType = GetNativeType($type);
   3126     return "v8::Integer::New($value)" if $nativeType eq "int";
   3127     return "v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned";
   3128 
   3129     return "v8DateOrNull($value)" if $type eq "Date";
   3130     # long long and unsigned long long are not representable in ECMAScript.
   3131     return "v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp";
   3132     return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type);
   3133     return "$value.v8Value()" if $nativeType eq "ScriptValue";
   3134 
   3135     if ($codeGenerator->IsStringType($type)) {
   3136         my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
   3137         if (defined $conv) {
   3138             return "v8StringOrNull($value)" if $conv eq "Null";
   3139             return "v8StringOrUndefined($value)" if $conv eq "Undefined";
   3140             return "v8StringOrFalse($value)" if $conv eq "False";
   3141 
   3142             die "Unknown value for ConvertNullStringTo extended attribute";
   3143         }
   3144         $conv = $signature->extendedAttributes->{"ConvertScriptString"};
   3145         return "v8StringOrNull($value)" if $conv;
   3146         return "v8String($value)";
   3147     }
   3148 
   3149     AddIncludesForType($type);
   3150 
   3151     # special case for non-DOM node interfaces
   3152     if (IsDOMNodeType($type)) {
   3153         return "toV8(${value}" . ($signature->extendedAttributes->{"ReturnsNew"} ? ", true)" : ")");
   3154     }
   3155 
   3156     if ($type eq "EventTarget") {
   3157         return "V8DOMWrapper::convertEventTargetToV8Object($value)";
   3158     }
   3159 
   3160     if ($type eq "EventListener") {
   3161         $implIncludes{"V8AbstractEventListener.h"} = 1;
   3162         return "${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null())";
   3163     }
   3164 
   3165     if ($type eq "SerializedScriptValue") {
   3166         $implIncludes{"$type.h"} = 1;
   3167         return "$value->deserialize()";
   3168     }
   3169 
   3170     $implIncludes{"wtf/RefCounted.h"} = 1;
   3171     $implIncludes{"wtf/RefPtr.h"} = 1;
   3172     $implIncludes{"wtf/GetPtr.h"} = 1;
   3173 
   3174     return "toV8($value)";
   3175 }
   3176 
   3177 sub ReturnNativeToJSValue
   3178 {
   3179     return "return " . NativeToJSValue(@_);
   3180 }
   3181 
   3182 # Internal helper
   3183 sub WriteData
   3184 {
   3185     if (defined($IMPL)) {
   3186         # Write content to file.
   3187         print $IMPL @implContentHeader;
   3188 
   3189         print $IMPL @implFixedHeader;
   3190 
   3191         foreach my $implInclude (sort keys(%implIncludes)) {
   3192             my $checkType = $implInclude;
   3193             $checkType =~ s/\.h//;
   3194 
   3195             if ($implInclude =~ /wtf/) {
   3196                 print $IMPL "#include \<$implInclude\>\n";
   3197             } else {
   3198                 print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
   3199             }
   3200         }
   3201 
   3202         print $IMPL "\n";
   3203         print $IMPL @implContentDecls;
   3204         print $IMPL @implContent;
   3205         close($IMPL);
   3206         undef($IMPL);
   3207 
   3208         %implIncludes = ();
   3209         @implFixedHeader = ();
   3210         @implHeaderContent = ();
   3211         @implContentDecls = ();
   3212         @implContent = ();
   3213     }
   3214 
   3215     if (defined($HEADER)) {
   3216         # Write content to file.
   3217         print $HEADER @headerContent;
   3218         close($HEADER);
   3219         undef($HEADER);
   3220 
   3221         @headerContent = ();
   3222     }
   3223 }
   3224 
   3225 sub GetVisibleInterfaceName
   3226 {
   3227     my $interfaceName = shift;
   3228 
   3229     return "DOMException" if $interfaceName eq "DOMCoreException";
   3230     return "FormData" if $interfaceName eq "DOMFormData";
   3231     return $interfaceName;
   3232 }
   3233 
   3234 sub GetCallbackClassName
   3235 {
   3236     my $interfaceName = shift;
   3237 
   3238     return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback";
   3239     return "V8$interfaceName";
   3240 }
   3241 
   3242 sub ConvertToV8Parameter
   3243 {
   3244     my $signature = shift;
   3245     my $nativeType = shift;
   3246     my $variableName = shift;
   3247     my $value = shift;
   3248     my $suffix = shift;
   3249 
   3250     die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/;
   3251     if ($signature->type eq "DOMString") {
   3252         $implIncludes{"V8BindingMacros.h"} = 1;
   3253         my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK";
   3254         $macro .= "_$suffix" if $suffix;
   3255         return "$macro($nativeType, $variableName, $value);"
   3256     } else {
   3257         # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData"
   3258         return "$nativeType $variableName($value, true);";
   3259     }
   3260 }
   3261 
   3262 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
   3263 sub GetRuntimeEnableFunctionName
   3264 {
   3265     my $signature = shift;
   3266 
   3267     # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
   3268     return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "1");
   3269 
   3270     # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
   3271     return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled";
   3272 }
   3273 
   3274 sub DebugPrint
   3275 {
   3276     my $output = shift;
   3277 
   3278     print $output;
   3279     print "\n";
   3280 }
   3281