1# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
2# Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
3# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
4# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
5# Copyright (C) 2006 Apple Computer, Inc.
6# Copyright (C) 2007, 2008, 2009 Google Inc.
7# Copyright (C) 2009 Cameron McCormack <cam@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
27package CodeGeneratorV8;
28
29use Digest::MD5;
30
31my $module = "";
32my $outputDir = "";
33my $outputHeadersDir = "";
34
35my @headerContent = ();
36my @implContentHeader = ();
37my @implFixedHeader = ();
38my @implContent = ();
39my @implContentDecls = ();
40my %implIncludes = ();
41my %headerIncludes = ();
42
43my @allParents = ();
44
45# Default .h template
46my $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*/
66EOF
67
68# Default constructor
69sub 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
82sub finish
83{
84    my $object = shift;
85
86    # Commit changes!
87    $object->WriteData();
88}
89
90# Params: 'domClass' struct
91sub 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
117sub GenerateModule
118{
119    my $object = shift;
120    my $dataNode = shift;
121
122    $module = $dataNode->module;
123}
124
125sub 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.
165sub 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
182sub 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
222sub 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
280public:
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;
291END
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();
299END
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);
306END
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&);
317END
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);
328END
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);
338END
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);
344END
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);
359END
360    }
361
362    push(@headerContent, <<END);
363private:
364    static v8::Handle<v8::Object> wrapSlow(${nativeType}*);
365};
366
367END
368
369    push(@headerContent, <<END);
370
371v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl${forceNewObjectInput})
372{
373END
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;
380END
381    push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
382    push(@headerContent, <<END);
383    return ${className}::wrapSlow(impl);
384}
385END
386
387    if (!HasCustomToV8Implementation($dataNode, $interfaceName)) {
388        push(@headerContent, <<END);
389
390inline v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectParameter})
391{
392    if (!impl)
393        return v8::Null();
394    return ${className}::wrap(impl${forceNewObjectCall});
395}
396END
397    } elsif ($interfaceName ne 'Node') {
398        push(@headerContent, <<END);
399
400v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter});
401END
402    } else {
403        push(@headerContent, <<END);
404
405v8::Handle<v8::Value> toV8Slow(Node*, bool);
406
407inline 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}
418END
419    }
420
421    if (IsRefPtrType($implClassName)) {
422        push(@headerContent, <<END);
423inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl${forceNewObjectParameter})
424{
425    return toV8(impl.get()${forceNewObjectCall});
426}
427END
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
437sub 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
457sub 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
467sub 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};
475END
476        $customFieldCounter++;
477    }
478    push(@headerContent, <<END);
479    static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
480END
481}
482
483my %indexerSpecialCases = (
484    "Storage" => 1,
485    "HTMLAppletElement" => 1,
486    "HTMLEmbedElement" => 1,
487    "HTMLObjectElement" => 1
488);
489
490sub 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&);
521END
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&);
527END
528    }
529    if ($hasCustomDeleters) {
530        push(@headerContent, <<END);
531    static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
532END
533    }
534    if ($hasCustomNamedGetter) {
535        push(@headerContent, <<END);
536    static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
537END
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&);
542END
543    }
544    if ($hasCustomDeleters) {
545        push(@headerContent, <<END);
546    static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
547END
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&);
553END
554    }
555}
556
557sub 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
575sub 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
588sub 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
600sub IsNodeSubType
601{
602    my $dataNode = shift;
603    return IsSubType($dataNode, "Node");
604}
605
606sub 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);
622static 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
640END
641}
642
643sub GenerateConstructorGetter
644{
645    my $implClassName = shift;
646
647    push(@implContentDecls, <<END);
648static 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);
654END
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()));
662END
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()));
666END
667    } else {
668        push(@implContentDecls, "    return v8::Handle<v8::Value>();");
669    }
670
671    push(@implContentDecls, <<END);
672}
673
674END
675}
676
677sub 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);
697static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
698{
699    INC_STATS(\"DOM.$implClassName.$attrName._get\");
700END
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());
707END
708        } else {
709            push(@implContentDecls, <<END);
710    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
711    $svgWrappedNativeType& impInstance = wrapper->propertyReference();
712END
713            if ($getterStringUsesImp) {
714                push(@implContentDecls, <<END);
715    $svgWrappedNativeType* imp = &impInstance;
716END
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();
723END
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>();
730END
731        }
732        push(@implContentDecls, <<END);
733    ${implClassName}* imp = V8${implClassName}::toNative(holder);
734END
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());
751END
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
881sub 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());
919END
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();
933END
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;
940END
941      }
942    push(@implContentDecls, <<END);
943    ${implClassName}* imp = V8${implClassName}::toNative(holder);
944END
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());
962END
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
1038sub 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
1057sub 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
1067sub 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);
1076static 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
1087END
1088}
1089
1090sub 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
1123sub 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
1139sub 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);
1153static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1154{
1155    INC_STATS(\"DOM.$implClassName.$name\");
1156END
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();
1166END
1167    push(@implContentDecls, "}\n\n");
1168}
1169
1170sub 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);
1196static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1197{
1198    INC_STATS(\"DOM.$implClassName.$name\");
1199END
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());
1240END
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>();
1251END
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();
1279END
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>();
1288END
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
1386sub 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
1400sub 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
1517sub 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);
1569END
1570            } else {
1571                push(@implContent, <<END);
1572    setCollectionStringIndexedGetter<${interfaceName}>(desc);
1573END
1574            }
1575        } else {
1576            push(@implContent, <<END);
1577    setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
1578END
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
1607sub 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);
1639END
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
1667sub 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
1684sub GenerateImplementationMasqueradesAsUndefined
1685{
1686    my $dataNode = shift;
1687    if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
1688    {
1689        push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
1690    }
1691}
1692
1693sub 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},
1889END
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)},
1908END
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);
1927v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args)
1928{
1929    INC_STATS("DOM.${interfaceName}.Contructor");
1930    return V8Proxy::${v8ConstructFunction}<$interfaceName>(args, &info);
1931}
1932END
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);
1944static 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}
1953END
1954    }
1955
1956    if (!$parentClassTemplate) {
1957        $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
1958    }
1959
1960    # Generate the template configuration method
1961    push(@implContent,  <<END);
1962static 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,
1965END
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),
1970END
1971    } else {
1972        push(@implContent, <<END);
1973        0, 0,
1974END
1975    }
1976
1977    if ($has_callbacks) {
1978        push(@implContent, <<END);
1979        ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
1980END
1981    } else {
1982        push(@implContent, <<END);
1983        0, 0);
1984    UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
1985END
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);
1992END
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();
1999END
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    }
2015END
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));
2080END
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);
2111END
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));
2120END
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);
2134END
2135    }
2136    if ($interfaceName eq "HTMLDocument") {
2137        push(@implContent, <<END);
2138    desc->SetHiddenPrototype(true);
2139END
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));
2149END
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
2160v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
2161{
2162    static v8::Persistent<v8::FunctionTemplate> ${className}RawCache = createRawTemplate();
2163    return ${className}RawCache;
2164}
2165
2166v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\
2167{
2168    static v8::Persistent<v8::FunctionTemplate> ${className}Cache = Configure${className}Template(GetRawTemplate());
2169    return ${className}Cache;
2170}
2171
2172bool ${className}::HasInstance(v8::Handle<v8::Value> value)
2173{
2174    return GetRawTemplate()->HasInstance(value);
2175}
2176
2177END
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);
2184ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
2185{
2186    return ${returnValue};
2187}
2188END
2189    }
2190
2191    if ($implClassName eq "DOMWindow") {
2192        push(@implContent, <<END);
2193v8::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}
2202END
2203    }
2204
2205    GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute);
2206
2207    push(@implContent, <<END);
2208
2209void ${className}::derefObject(void* object)
2210{
2211END
2212
2213    if (IsRefPtrType($interfaceName)) {
2214        push(@implContent, <<END);
2215    static_cast<${nativeType}*>(object)->deref();
2216END
2217    }
2218
2219    push(@implContent, <<END);
2220}
2221
2222} // namespace WebCore
2223END
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
2233sub 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
2247sub 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
2261sub 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);
2286public:
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
2296END
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
2322private:
2323    ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);
2324
2325    v8::Persistent<v8::Object> m_callback;
2326    WorldContextHandle m_worldContext;
2327};
2328
2329END
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
2338sub 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
2368END
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
2431sub 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
2445v8::Handle<v8::Object> ${className}::wrapSlow(${nativeType}* impl)
2446{
2447    v8::Handle<v8::Object> wrapper;
2448    V8Proxy* proxy = 0;
2449END
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
2463END
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();
2476END
2477    }
2478
2479    push(@implContent, <<END);
2480    wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl);
2481END
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();
2487END
2488    }
2489
2490    push(@implContent, <<END);
2491    if (wrapper.IsEmpty())
2492        return wrapper;
2493END
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}());
2509END
2510    }
2511
2512    push(@implContent, <<END);
2513    v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);
2514END
2515    if (IsNodeSubType($dataNode)) {
2516        push(@implContent, <<END);
2517    wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
2518END
2519    }
2520    push(@implContent, <<END);
2521    ${domMapFunction}.set(impl, wrapperHandle);
2522END
2523
2524    push(@implContent, <<END);
2525    return wrapper;
2526}
2527END
2528}
2529
2530sub 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
2561sub 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
2571sub 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
2588sub 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
2597sub 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
2744sub GetTypeFromSignature
2745{
2746    my $signature = shift;
2747
2748    return $codeGenerator->StripModule($signature->type);
2749}
2750
2751
2752sub 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
2779sub 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
2798sub 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
2856sub 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
2865sub 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
2875sub 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
2888sub 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
2966sub 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
2977sub 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
3009sub 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.
3041my %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
3069sub IsWrapperType
3070{
3071    my $type = $codeGenerator->StripModule(shift);
3072    return !($non_wrapper_types{$type});
3073}
3074
3075sub 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
3105sub 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
3177sub ReturnNativeToJSValue
3178{
3179    return "return " . NativeToJSValue(@_);
3180}
3181
3182# Internal helper
3183sub 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
3225sub 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
3234sub GetCallbackClassName
3235{
3236    my $interfaceName = shift;
3237
3238    return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback";
3239    return "V8$interfaceName";
3240}
3241
3242sub 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.
3263sub 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
3274sub DebugPrint
3275{
3276    my $output = shift;
3277
3278    print $output;
3279    print "\n";
3280}
3281