Fix the issue that Web Audio test case fails on PR3.
[framework/web/webkit-efl.git] / Source / WebCore / bindings / scripts / CodeGeneratorV8.pm
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, 2012 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
27 package CodeGeneratorV8;
28
29 use strict;
30
31 use Digest::MD5;
32
33 use constant FileNamePrefix => "V8";
34
35 my $codeGenerator;
36
37 my $module = "";
38 my $outputDir = "";
39 my $outputHeadersDir = "";
40
41 my @headerContent = ();
42 my @implContentHeader = ();
43 my @implFixedHeader = ();
44 my @implContent = ();
45 my @implContentDecls = ();
46 my %implIncludes = ();
47 my %headerIncludes = ();
48
49 my @allParents = ();
50
51 # Default .h template
52 my $headerTemplate = << "EOF";
53 /*
54     This file is part of the WebKit open source project.
55     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
56
57     This library is free software; you can redistribute it and/or
58     modify it under the terms of the GNU Library General Public
59     License as published by the Free Software Foundation; either
60     version 2 of the License, or (at your option) any later version.
61
62     This library is distributed in the hope that it will be useful,
63     but WITHOUT ANY WARRANTY; without even the implied warranty of
64     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
65     Library General Public License for more details.
66
67     You should have received a copy of the GNU Library General Public License
68     along with this library; see the file COPYING.LIB.  If not, write to
69     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
70     Boston, MA 02111-1307, USA.
71 */
72 EOF
73
74 # Default constructor
75 sub new
76 {
77     my $object = shift;
78     my $reference = { };
79
80     $codeGenerator = shift;
81     $outputDir = shift;
82     $outputHeadersDir = shift;
83
84     bless($reference, $object);
85     return $reference;
86 }
87
88 # Params: 'domClass' struct
89 sub GenerateInterface
90 {
91     my $object = shift;
92     my $dataNode = shift;
93     my $defines = shift;
94
95     # Start actual generation
96     if ($dataNode->extendedAttributes->{"Callback"}) {
97         $object->GenerateCallbackHeader($dataNode);
98         $object->GenerateCallbackImplementation($dataNode);
99     } else {
100         $object->GenerateHeader($dataNode);
101         $object->GenerateImplementation($dataNode);
102     }
103
104     $object->WriteData($dataNode);
105 }
106
107 # Params: 'idlDocument' struct
108 sub GenerateModule
109 {
110     my $object = shift;
111     my $dataNode = shift;
112
113     $module = $dataNode->module;
114 }
115
116 sub AddToImplIncludes
117 {
118     my $header = shift;
119     my $conditional = shift;
120
121     if (not $conditional) {
122         $implIncludes{$header} = 1;
123     } elsif (not exists($implIncludes{$header})) {
124         $implIncludes{$header} = $conditional;
125     } else {
126         my $oldValue = $implIncludes{$header};
127         if ($oldValue ne 1) {
128             my %newValue = ();
129             $newValue{$conditional} = 1;
130             foreach my $condition (split(/\|/, $oldValue)) {
131                 $newValue{$condition} = 1;
132             }
133             $implIncludes{$header} = join("|", sort keys %newValue);
134         }
135     }
136 }
137
138 sub AddIncludesForType
139 {
140     my $type = $codeGenerator->StripModule(shift);
141
142     # When we're finished with the one-file-per-class
143     # reorganization, we won't need these special cases.
144     if (IsTypedArrayType($type)) {
145         AddToImplIncludes("wtf/${type}.h");
146     }
147     if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->SkipIncludeHeader($type) and $type ne "Date") {
148         # default, include the same named file
149         AddToImplIncludes(GetV8HeaderName(${type}));
150
151         if ($type =~ /SVGPathSeg/) {
152             my $joinedName = $type;
153             $joinedName =~ s/Abs|Rel//;
154             AddToImplIncludes("${joinedName}.h");
155         }
156     }
157
158     # additional includes (things needed to compile the bindings but not the header)
159
160     if ($type eq "CanvasRenderingContext2D") {
161         AddToImplIncludes("CanvasGradient.h");
162         AddToImplIncludes("CanvasPattern.h");
163         AddToImplIncludes("CanvasStyle.h");
164     }
165
166     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
167         AddToImplIncludes("PlatformString.h");
168     }
169
170     if ($type eq "CSSStyleSheet" or $type eq "StyleSheet") {
171         AddToImplIncludes("CSSImportRule.h");
172     }
173
174     if ($type eq "CSSStyleDeclaration") {
175         AddToImplIncludes("StylePropertySet.h");
176     }
177
178     if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") {
179         # So we can get String -> AtomicString conversion for namedItem().
180         AddToImplIncludes("wtf/text/AtomicString.h");
181     }
182 }
183
184 sub NeedsToVisitDOMWrapper
185 {
186     my $dataNode = shift;
187     return GetGenerateIsReachable($dataNode) || GetCustomIsReachable($dataNode);
188 }
189
190 sub GetGenerateIsReachable
191 {
192     my $dataNode = shift;
193     return $dataNode->extendedAttributes->{"GenerateIsReachable"} || $dataNode->extendedAttributes->{"V8GenerateIsReachable"} || ""
194 }
195
196 sub GetCustomIsReachable
197 {
198     my $dataNode = shift;
199     return $dataNode->extendedAttributes->{"CustomIsReachable"} || $dataNode->extendedAttributes->{"V8CustomIsReachable"};
200 }
201
202 sub GenerateVisitDOMWrapper
203 {
204     my ($dataNode, $implClassName) = @_;
205
206     if (GetCustomIsReachable($dataNode)) {
207         return;
208     }
209
210     push(@implContent, <<END);
211 void V8${implClassName}::visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
212 {
213     ${implClassName}* impl = static_cast<${implClassName}*>(object);
214 END
215     if (GetGenerateIsReachable($dataNode) eq  "ImplElementRoot" ||
216         GetGenerateIsReachable($dataNode) eq  "ImplOwnerRoot" ||
217         GetGenerateIsReachable($dataNode) eq  "ImplOwnerNodeRoot" ||
218         GetGenerateIsReachable($dataNode) eq  "ImplBaseRoot") {
219
220         my $methodName;
221         $methodName = "element" if (GetGenerateIsReachable($dataNode) eq "ImplElementRoot");
222         $methodName = "owner" if (GetGenerateIsReachable($dataNode) eq "ImplOwnerRoot");
223         $methodName = "ownerNode" if (GetGenerateIsReachable($dataNode) eq "ImplOwnerNodeRoot");
224         $methodName = "base" if (GetGenerateIsReachable($dataNode) eq "ImplBaseRoot");
225
226         push(@implContent, <<END);
227     if (Node* owner = impl->${methodName}()) {
228         v8::Persistent<v8::Object> ownerWrapper = store->domNodeMap().get(owner);
229         if (!ownerWrapper.IsEmpty()) {
230             v8::Persistent<v8::Value> value = wrapper;
231             v8::V8::AddImplicitReferences(ownerWrapper, &value, 1);
232         }
233     }
234 END
235     }
236
237     push(@implContent, <<END);
238 }
239
240 END
241 }
242
243 sub GetSVGPropertyTypes
244 {
245     my $implType = shift;
246
247     my $svgPropertyType;
248     my $svgListPropertyType;
249     my $svgNativeType;
250
251     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
252
253     $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
254     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
255
256     # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
257     $svgNativeType = "$svgNativeType ";
258
259     my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
260     if ($svgNativeType =~ /SVGPropertyTearOff/) {
261         $svgPropertyType = $svgWrappedNativeType;
262         AddToImplIncludes("SVGAnimatedPropertyTearOff.h");
263     } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
264         $svgListPropertyType = $svgWrappedNativeType;
265         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
266         $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1;
267     } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
268         $svgListPropertyType = $svgWrappedNativeType;
269         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
270         $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
271     } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
272         $svgListPropertyType = $svgWrappedNativeType;
273         $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
274     }
275
276     if ($svgPropertyType) {
277         $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint";
278     }
279
280     return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
281 }
282
283 sub GenerateHeader
284 {
285     my $object = shift;
286     my $dataNode = shift;
287
288     my $interfaceName = $dataNode->name;
289     my $className = "V8$interfaceName";
290     my $implClassName = $interfaceName;
291
292     # Copy contents of parent classes except the first parent or if it is
293     # EventTarget.
294     $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1);
295     $codeGenerator->LinkOverloadedFunctions($dataNode);
296
297     my $hasDependentLifetime = $dataNode->extendedAttributes->{"V8DependentLifetime"} || $dataNode->extendedAttributes->{"ActiveDOMObject"}
298          || GetGenerateIsReachable($dataNode) || $className =~ /SVG/;
299     if (!$hasDependentLifetime) {
300         foreach (@{$dataNode->parents}) {
301             my $parent = $codeGenerator->StripModule($_);
302             next if $parent eq "EventTarget";
303             $headerIncludes{"V8${parent}.h"} = 1;
304         }
305     }
306
307     # - Add default header template
308     push(@headerContent, GenerateHeaderContentHeader($dataNode));
309
310     $headerIncludes{"wtf/text/StringHash.h"} = 1;
311     $headerIncludes{"WrapperTypeInfo.h"} = 1;
312     $headerIncludes{"V8Binding.h"} = 1;
313     $headerIncludes{"V8DOMWrapper.h"} = 1;
314     $headerIncludes{"wtf/HashMap.h"} = 1;
315     $headerIncludes{"v8.h"} = 1;
316
317     my $headerClassInclude = GetHeaderClassInclude($implClassName);
318     $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne "";
319
320     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
321
322     foreach my $headerInclude (sort keys(%headerIncludes)) {
323         if ($headerInclude =~ /wtf|v8\.h/) {
324             push(@headerContent, "#include \<${headerInclude}\>\n");
325         } else {
326             push(@headerContent, "#include \"${headerInclude}\"\n");
327         }
328     }
329
330     push(@headerContent, "\nnamespace WebCore {\n");
331     push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType;
332     if ($svgNativeType) {
333         if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) {
334             push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n");
335         } else {
336             push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n");
337         }
338     }
339
340     push(@headerContent, "\n");
341     push(@headerContent, "class FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect";
342     push(@headerContent, "class Dictionary;\n") if IsConstructorTemplate($dataNode, "Event");
343
344     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
345     if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
346         push(@headerContent, <<END);
347 class V8${nativeType}Constructor {
348 public:
349     static v8::Persistent<v8::FunctionTemplate> GetTemplate();
350     static WrapperTypeInfo info;
351 };
352
353 END
354     }
355
356     push(@headerContent, "class $className {\n");
357     push(@headerContent, "public:\n");
358
359     push(@headerContent, "    static const bool hasDependentLifetime = ");
360     if ($hasDependentLifetime) {
361         push(@headerContent, "true;\n");
362     } elsif (@{$dataNode->parents}) {
363         # Even if this type doesn't have the V8DependentLifetime attribute its parents may.
364         # Let the compiler statically determine this for us.
365         my $separator = "";
366         foreach (@{$dataNode->parents}) {
367             my $parent = $codeGenerator->StripModule($_);
368             next if $parent eq "EventTarget";
369             $headerIncludes{"V8${parent}.h"} = 1;
370             push(@headerContent, "${separator}V8${parent}::hasDependentLifetime");
371             $separator = " || ";
372         }
373         push(@headerContent, ";\n");
374     } else {
375         push(@headerContent, "false;\n");
376     }
377
378     my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : "";
379     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
380     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
381
382     push(@headerContent, <<END);
383     static bool HasInstance(v8::Handle<v8::Value>);
384     static v8::Persistent<v8::FunctionTemplate> GetRawTemplate();
385     static v8::Persistent<v8::FunctionTemplate> GetTemplate();
386     static ${nativeType}* toNative(v8::Handle<v8::Object> object)
387     {
388         return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex));
389     }
390     inline static v8::Handle<v8::Object> wrap(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
391     static void derefObject(void*);
392     static void visitDOMWrapper(DOMDataStore*, void*, v8::Persistent<v8::Object>);
393     static WrapperTypeInfo info;
394 END
395     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
396         push(@headerContent, "    static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n");
397     }
398
399     if ($implClassName eq "DOMWindow") {
400         push(@headerContent, <<END);
401     static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate();
402 END
403     }
404
405     if ($implClassName eq "HTMLDocument") {
406       push(@headerContent, <<END);
407   static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl);
408   static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key, v8::Isolate*);
409 END
410     }
411
412     my @enabledPerContext;
413     foreach my $function (@{$dataNode->functions}) {
414         my $name = $function->signature->name;
415         my $attrExt = $function->signature->extendedAttributes;
416
417         if (($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) && !$attrExt->{"ImplementedBy"} && $function->{overloadIndex} == 1) {
418             my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
419             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
420             push(@headerContent, <<END);
421     static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&);
422 END
423             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
424         }
425         if ($attrExt->{"V8EnabledPerContext"}) {
426             push(@enabledPerContext, $function);
427         }
428     }
429
430     if (IsConstructable($dataNode)) {
431         push(@headerContent, <<END);
432     static v8::Handle<v8::Value> constructorCallback(const v8::Arguments&);
433 END
434     }
435
436     foreach my $attribute (@{$dataNode->attributes}) {
437         my $name = $attribute->signature->name;
438         my $attrExt = $attribute->signature->extendedAttributes;
439         my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
440         if (($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"} ||
441              $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
442             !$attrExt->{"ImplementedBy"}) {
443             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
444             push(@headerContent, <<END);
445     static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);
446 END
447             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
448         }
449         if (($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"} ||
450              $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) &&
451             !$attrExt->{"ImplementedBy"}) {
452             push(@headerContent, "#if ${conditionalString}\n") if $conditionalString;
453             push(@headerContent, <<END);
454     static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);
455 END
456             push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
457         }
458         if ($attrExt->{"V8EnabledPerContext"}) {
459             push(@enabledPerContext, $attribute);
460         }
461     }
462
463     GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode);
464     GenerateHeaderCustomCall($dataNode);
465     GenerateHeaderCustomInternalFieldIndices($dataNode);
466
467     if ($dataNode->extendedAttributes->{"CheckSecurity"}) {
468         push(@headerContent, <<END);
469     static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data);
470     static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data);
471 END
472     }
473
474     if (@enabledPerContext) {
475         push(@headerContent, <<END);
476     static void installPerContextProperties(v8::Handle<v8::Object>, ${implClassName}*);
477 END
478     }
479
480     my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);
481     push(@headerContent, <<END);
482 private:
483     static v8::Handle<v8::Object> wrapSlow(${wrapSlowArgumentType}, v8::Isolate*);
484 };
485
486 END
487
488     push(@headerContent, <<END);
489 v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl, v8::Isolate* isolate${forceNewObjectInput})
490 {
491 END
492     push(@headerContent, "    if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName);
493     my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName, "isolate");
494     my $getCachedWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getCachedWrapper(impl)" : "${domMapFunction}.get(impl)";
495     push(@headerContent, <<END);
496         v8::Handle<v8::Object> wrapper = $getCachedWrapper;
497         if (!wrapper.IsEmpty())
498             return wrapper;
499 END
500     push(@headerContent, "    }\n") if IsDOMNodeType($interfaceName);
501     push(@headerContent, <<END);
502     return ${className}::wrapSlow(impl, isolate);
503 }
504 END
505
506     if ($interfaceName eq 'Element' or $dataNode->extendedAttributes->{"SuppressToJSObject"}) {
507         # Do not generate toV8() for performance optimization.
508     } elsif (!($dataNode->extendedAttributes->{"CustomToJSObject"} or $dataNode->extendedAttributes->{"V8CustomToJSObject"})) {
509         push(@headerContent, <<END);
510
511 inline v8::Handle<v8::Value> toV8(${nativeType}* impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
512 {
513     if (!impl)
514         return v8NullWithCheck(isolate);
515     return ${className}::wrap(impl, isolate${forceNewObjectCall});
516 }
517 END
518     } elsif ($interfaceName ne 'Node') {
519         push(@headerContent, <<END);
520
521 v8::Handle<v8::Value> toV8(${nativeType}*, v8::Isolate* = 0${forceNewObjectParameter});
522 END
523     } else {
524         push(@headerContent, <<END);
525
526 v8::Handle<v8::Value> toV8Slow(Node*, v8::Isolate*, bool);
527
528 inline v8::Handle<v8::Value> toV8(Node* impl, v8::Isolate* isolate = 0, bool forceNewObject = false)
529 {
530     if (UNLIKELY(!impl))
531         return v8NullWithCheck(isolate);
532     if (UNLIKELY(forceNewObject))
533         return toV8Slow(impl, isolate, forceNewObject);
534     v8::Handle<v8::Value> wrapper = V8DOMWrapper::getCachedWrapper(impl);
535     if (!wrapper.IsEmpty())
536         return wrapper;
537     return toV8Slow(impl, isolate, false);
538 }
539 END
540     }
541
542     push(@headerContent, <<END);
543 inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl, v8::Isolate* isolate = 0${forceNewObjectParameter})
544 {
545     return toV8(impl.get(), isolate${forceNewObjectCall});
546 }
547 END
548
549     if (IsConstructorTemplate($dataNode, "Event")) {
550         push(@headerContent, "\nbool fill${implClassName}Init(${implClassName}Init&, const Dictionary&);\n");
551     }
552
553     push(@headerContent, "\n}\n\n");
554     push(@headerContent, "#endif // $className" . "_h\n");
555
556     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
557     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
558 }
559
560 sub GetInternalFields
561 {
562     my $dataNode = shift;
563     my $name = $dataNode->name;
564
565     my @customInternalFields = ();
566     # We can't ask whether a parent type has a given extendedAttribute,
567     # so special-case AbstractWorker and WorkerContext to include all sub-types.
568     # Event listeners on DOM nodes are explicitly supported in the GC controller.
569     # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't.
570     # FIXME: Simplify this when all EventTargets are subtypes of EventTarget.
571     if (!IsNodeSubType($dataNode)
572         && ($dataNode->extendedAttributes->{"EventTarget"}
573             || $dataNode->extendedAttributes->{"IsWorkerContext"}
574             || IsSubType($dataNode, "AbstractWorker")
575             || $name eq "SVGElementInstance"
576             || $name eq "EventTarget")) {
577         push(@customInternalFields, "eventListenerCacheIndex");
578     }
579
580     if ($name eq "DOMWindow") {
581         push(@customInternalFields, "enteredIsolatedWorldIndex");
582     }
583     return @customInternalFields;
584 }
585
586 sub GetHeaderClassInclude
587 {
588     my $className = shift;
589     if ($className =~ /SVGPathSeg/) {
590         $className =~ s/Abs|Rel//;
591     }
592     return "wtf/${className}.h" if IsTypedArrayType($className);
593     return "" if ($codeGenerator->SkipIncludeHeader($className));
594     return "${className}.h";
595 }
596
597 sub GenerateHeaderCustomInternalFieldIndices
598 {
599     my $dataNode = shift;
600     my @customInternalFields = GetInternalFields($dataNode);
601     my $customFieldCounter = 0;
602     foreach my $customInternalField (@customInternalFields) {
603         push(@headerContent, <<END);
604     static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
605 END
606         $customFieldCounter++;
607     }
608     push(@headerContent, <<END);
609     static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter};
610 END
611 }
612
613 my %indexerSpecialCases = (
614     "Storage" => 1,
615     "HTMLAppletElement" => 1,
616     "HTMLEmbedElement" => 1,
617     "HTMLObjectElement" => 1
618 );
619
620 sub GenerateHeaderNamedAndIndexedPropertyAccessors
621 {
622     my $dataNode = shift;
623     my $interfaceName = $dataNode->name;
624     my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
625     my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
626     my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
627     my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
628     my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
629     my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
630     if ($interfaceName eq "HTMLOptionsCollection") {
631         $interfaceName = "HTMLCollection";
632         $hasCustomIndexedGetter = 1;
633         $hasCustomNamedGetter = 1;
634     }
635     if ($interfaceName eq "DOMWindow") {
636         $hasCustomDeleters = 0;
637         $hasCustomEnumerator = 0;
638     }
639     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
640         $hasCustomNamedGetter = 1;
641     }
642     if ($interfaceName eq "HTMLDocument") {
643         $hasCustomNamedGetter = 0;
644         $hasCustomIndexedGetter = 0;
645     }
646     my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName};
647
648     if ($hasCustomIndexedGetter || $isIndexerSpecialCase) {
649         push(@headerContent, <<END);
650     static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&);
651 END
652     }
653
654     if ($isIndexerSpecialCase || $hasCustomIndexedSetter) {
655         push(@headerContent, <<END);
656     static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&);
657 END
658     }
659     if ($hasCustomDeleters) {
660         push(@headerContent, <<END);
661     static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&);
662 END
663     }
664     if ($hasCustomNamedGetter) {
665         push(@headerContent, <<END);
666     static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&);
667 END
668     }
669     if ($hasCustomNamedSetter) {
670         push(@headerContent, <<END);
671     static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&);
672 END
673     }
674     if ($hasCustomDeleters) {
675         push(@headerContent, <<END);
676     static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&);
677 END
678     }
679     if ($hasCustomEnumerator) {
680         push(@headerContent, <<END);
681     static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&);
682     static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&);
683 END
684     }
685 }
686
687 sub GenerateHeaderCustomCall
688 {
689     my $dataNode = shift;
690
691     if ($dataNode->extendedAttributes->{"CustomCall"}) {
692         push(@headerContent, "    static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n");
693     }
694     if ($dataNode->name eq "Event") {
695         push(@headerContent, "    static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
696         push(@headerContent, "    static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::AccessorInfo&);\n");
697     }
698     if ($dataNode->name eq "Location") {
699         push(@headerContent, "    static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
700         push(@headerContent, "    static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
701         push(@headerContent, "    static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo&);\n");
702     }
703 }
704
705 sub IsSubType
706 {
707     my $dataNode = shift;
708     my $parentType = shift;
709     return 1 if ($dataNode->name eq $parentType);
710     foreach (@allParents) {
711         my $parent = $codeGenerator->StripModule($_);
712         return 1 if $parent eq $parentType;
713     }
714     return 0;
715 }
716
717 sub IsNodeSubType
718 {
719     my $dataNode = shift;
720     return IsSubType($dataNode, "Node");
721 }
722
723 sub IsVisibleAcrossOrigins
724 {
725     my $dataNode = shift;
726     return $dataNode->extendedAttributes->{"CheckSecurity"} && !($dataNode->name eq "DOMWindow");
727 }
728
729 sub IsConstructable
730 {
731     my $dataNode = shift;
732
733     return $dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"Constructor"} || $dataNode->extendedAttributes->{"ConstructorTemplate"};
734 }
735
736 sub IsConstructorTemplate
737 {
738     my $dataNode = shift;
739     my $template = shift;
740
741     return $dataNode->extendedAttributes->{"ConstructorTemplate"} && $dataNode->extendedAttributes->{"ConstructorTemplate"} eq $template;
742 }
743
744 sub GenerateDomainSafeFunctionGetter
745 {
746     my $function = shift;
747     my $implClassName = shift;
748
749     my $className = "V8" . $implClassName;
750     my $funcName = $function->signature->name;
751
752     my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())";
753     if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) {
754         $signature = "v8::Local<v8::Signature>()";
755     }
756
757     my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature);
758
759     push(@implContentDecls, <<END);
760 static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
761 {
762     INC_STATS(\"DOM.$implClassName.$funcName._get\");
763     static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
764     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This());
765     if (holder.IsEmpty()) {
766         // can only reach here by 'object.__proto__.func', and it should passed
767         // domain security check already
768         return privateTemplate->GetFunction();
769     }
770     ${implClassName}* imp = ${className}::toNative(holder);
771     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) {
772         static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString);
773         return sharedTemplate->GetFunction();
774     }
775     return privateTemplate->GetFunction();
776 }
777
778 END
779 }
780
781 sub GenerateConstructorGetter
782 {
783     my $dataNode = shift;
784     my $implClassName = shift;
785
786     push(@implContentDecls, <<END);
787 static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
788 {
789     INC_STATS(\"DOM.$implClassName.constructors._get\");
790     v8::Handle<v8::Value> data = info.Data();
791     ASSERT(data->IsExternal() || data->IsNumber());
792     WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
793 END
794
795     if ($implClassName eq "DOMWindow") {
796         push(@implContentDecls, <<END);
797     // Get the proxy corresponding to the DOMWindow if possible to
798     // make sure that the constructor function is constructed in the
799     // context of the DOMWindow and not in the context of the caller.
800     return V8DOMWrapper::constructorForType(type, V8DOMWindow::toNative(info.Holder()));
801 END
802     } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
803         push(@implContentDecls, <<END);
804     return V8DOMWrapper::constructorForType(type, V8WorkerContext::toNative(info.Holder()));
805 END
806     } else {
807         push(@implContentDecls, "    return v8::Handle<v8::Value>();");
808     }
809
810     push(@implContentDecls, <<END);
811 }
812
813 END
814 }
815
816 sub GenerateFeatureObservation
817 {
818     my $measureAs = shift;
819
820     if ($measureAs) {
821         AddToImplIncludes("FeatureObserver.h");
822         return "    FeatureObserver::observe(activeDOMWindow(BindingState::instance()), FeatureObserver::${measureAs});\n";
823     }
824
825     return "";
826 }
827
828 sub GenerateNormalAttrGetter
829 {
830     my $attribute = shift;
831     my $dataNode = shift;
832     my $implClassName = shift;
833     my $interfaceName = shift;
834
835     my $attrExt = $attribute->signature->extendedAttributes;
836     my $attrName = $attribute->signature->name;
837     my $attrType = GetTypeFromSignature($attribute->signature);
838     $codeGenerator->AssertNotSequenceType($attrType);
839     my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1);
840
841     my $getterStringUsesImp = $implClassName ne "SVGNumber";
842     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
843
844     # Getter
845     my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
846     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
847
848     push(@implContentDecls, <<END);
849 static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
850 {
851     INC_STATS("DOM.$implClassName.$attrName._get");
852 END
853     push(@implContentDecls, GenerateFeatureObservation($attrExt->{"V8MeasureAs"}));
854
855     if ($svgNativeType) {
856         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
857         if ($svgWrappedNativeType =~ /List/) {
858             push(@implContentDecls, <<END);
859     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
860 END
861         } else {
862             push(@implContentDecls, <<END);
863     $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());
864     $svgWrappedNativeType& impInstance = wrapper->propertyReference();
865 END
866             if ($getterStringUsesImp) {
867                 push(@implContentDecls, <<END);
868     $svgWrappedNativeType* imp = &impInstance;
869 END
870             }
871         }
872     } elsif ($attrExt->{"V8OnProto"} || $attrExt->{"V8Unforgeable"}) {
873         if ($interfaceName eq "DOMWindow") {
874             push(@implContentDecls, <<END);
875     v8::Handle<v8::Object> holder = info.Holder();
876 END
877         } else {
878             # perform lookup first
879             push(@implContentDecls, <<END);
880     v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This());
881     if (holder.IsEmpty())
882         return v8::Handle<v8::Value>();
883 END
884         }
885         push(@implContentDecls, <<END);
886     ${implClassName}* imp = V8${implClassName}::toNative(holder);
887 END
888     } else {
889         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
890         my $url = $attribute->signature->extendedAttributes->{"URL"};
891         if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
892             # Generate super-compact call for regular attribute getter:
893             my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
894             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
895             AddToImplIncludes("${namespace}.h");
896             push(@implContentDecls, "    Element* imp = V8Element::toNative(info.Holder());\n");
897             push(@implContentDecls, "    return v8ExternalString(imp->getAttribute(${namespace}::${contentAttributeName}Attr), info.GetIsolate());\n");
898             push(@implContentDecls, "}\n\n");
899             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
900             return;
901             # Skip the rest of the function!
902         }
903         if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
904             push(@implContentDecls, <<END);
905     v8::Handle<v8::String> propertyName = v8::String::NewSymbol("${attrName}");
906     v8::Handle<v8::Value> value = info.Holder()->GetHiddenValue(propertyName);
907     if (!value.IsEmpty())
908         return value;
909 END
910         }
911         if (!$attribute->isStatic) {
912             push(@implContentDecls, <<END);
913     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
914 END
915         }
916     }
917
918     # Generate security checks if necessary
919     if ($attribute->signature->extendedAttributes->{"CheckSecurityForNode"}) {
920         push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $attribute->signature->name . "()))\n        return v8::Handle<v8::Value>(v8::Null(info.GetIsolate()));\n\n");
921     }
922
923     my $useExceptions = 1 if @{$attribute->getterExceptions};
924     if ($useExceptions) {
925         AddToImplIncludes("ExceptionCode.h");
926         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
927     }
928
929     my $returnType = GetTypeFromSignature($attribute->signature);
930     my $getterString;
931
932     if ($getterStringUsesImp) {
933         my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
934         push(@arguments, "ec") if $useExceptions;
935         if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
936             my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
937             AddToImplIncludes("${implementedBy}.h");
938             unshift(@arguments, "imp") if !$attribute->isStatic;
939             $functionName = "${implementedBy}::${functionName}";
940         } elsif ($attribute->isStatic) {
941             $functionName = "${implClassName}::${functionName}";
942         } else {
943             $functionName = "imp->${functionName}";
944         }
945         unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 0, 0));
946         $getterString = "${functionName}(" . join(", ", @arguments) . ")";
947     } else {
948         $getterString = "impInstance";
949     }
950
951     my $result;
952     my $wrapper;
953
954     if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") {
955         push(@implContentDecls, "    if (!imp->document())\n");
956         push(@implContentDecls, "        return v8::Handle<v8::Value>();\n");
957     }
958
959     if ($useExceptions) {
960         if ($nativeType =~ /^V8Parameter/) {
961             push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n");
962         } else {
963             push(@implContentDecls, "    $nativeType v = $getterString;\n");
964         }
965         push(@implContentDecls, "    if (UNLIKELY(ec))\n");
966         push(@implContentDecls, "        return V8Proxy::setDOMException(ec, info.GetIsolate());\n");
967
968         if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
969             push(@implContentDecls, "    if (state.hadException())\n");
970             push(@implContentDecls, "        return throwError(state.exception(), info.GetIsolate());\n");
971         }
972
973         $result = "v";
974         $result .= ".release()" if (IsRefPtrType($returnType));
975     } else {
976         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
977         $result = $getterString;
978         # Fix amigious conversion problem, by casting to the base type first ($getterString returns a type that inherits from SVGAnimatedEnumeration, not the base class directly).
979         $result = "static_pointer_cast<SVGAnimatedEnumeration>($result)" if $returnType eq "SVGAnimatedEnumeration";
980     }
981  
982     # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get
983     # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to
984     # the newly created wrapper into an internal field of the holder object.
985     if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"})
986         && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" 
987         && $returnType ne "MessagePortArray"
988         && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) {
989
990         my $arrayType = $codeGenerator->GetArrayType($returnType);
991         if ($arrayType) {
992             if (!$codeGenerator->SkipIncludeHeader($arrayType)) {
993                 AddToImplIncludes("V8$arrayType.h");
994                 AddToImplIncludes("$arrayType.h");
995             }
996             push(@implContentDecls, "    return v8Array(${getterString}, info.GetIsolate());\n");
997             push(@implContentDecls, "}\n\n");
998             return;
999         }
1000
1001         AddIncludesForType($returnType);
1002         # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already
1003         # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference.
1004         push(@implContentDecls, "    RefPtr<$returnType> result = ${getterString};\n");
1005         my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName, "info.GetIsolate()");
1006         push(@implContentDecls, "    v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Object>();\n");
1007         push(@implContentDecls, "    if (wrapper.IsEmpty()) {\n");
1008         push(@implContentDecls, "        wrapper = toV8(result.get(), info.GetIsolate());\n");
1009         push(@implContentDecls, "        if (!wrapper.IsEmpty())\n");
1010         if ($dataNode->name eq "DOMWindow") {
1011             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenWindowReference(imp->frame(), \"${attrName}\", wrapper);\n");
1012         } else {
1013             push(@implContentDecls, "            V8DOMWrapper::setNamedHiddenReference(info.Holder(), \"${attrName}\", wrapper);\n");
1014         }
1015         push(@implContentDecls, "    }\n");
1016         push(@implContentDecls, "    return wrapper;\n");
1017         push(@implContentDecls, "}\n\n");
1018         push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1019         return;
1020     }
1021
1022     if (($codeGenerator->IsSVGAnimatedType($implClassName) or $implClassName eq "SVGViewSpec") and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) {
1023         AddToImplIncludes("V8$attrType.h");
1024         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
1025         # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked.
1026         push(@implContentDecls, "    return toV8(static_cast<$svgNativeType*>($result), info.GetIsolate());\n");
1027     } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) {
1028         AddToImplIncludes("V8$attrType.h");
1029         AddToImplIncludes("SVGPropertyTearOff.h");
1030         my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType);
1031         if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) {
1032             my $getter = $result;
1033             $getter =~ s/imp->//;
1034             $getter =~ s/\(\)//;
1035
1036             my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter);
1037
1038             my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName);
1039             if ($selfIsTearOffType) {
1040                 AddToImplIncludes("SVGStaticPropertyWithParentTearOff.h");
1041                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /;
1042
1043                 if ($result =~ /matrix/ and $implClassName eq "SVGTransform") {
1044                     # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform
1045                     # and a svgMatrix() method returning a SVGMatrix, used for the bindings.
1046                     $result =~ s/matrix/svgMatrix/;
1047                 }
1048
1049                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)), info.GetIsolate());\n");
1050             } else {
1051                 AddToImplIncludes("SVGStaticPropertyTearOff.h");
1052                 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /;
1053
1054                 push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)), info.GetIsolate());\n");
1055             }
1056         } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) {
1057             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create(imp, $result)), info.GetIsolate());\n");
1058         } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) {
1059             push(@implContentDecls, "    return toV8(WTF::getPtr($result), info.GetIsolate());\n");
1060         } else {
1061             push(@implContentDecls, "    return toV8(WTF::getPtr(${tearOffType}::create($result)), info.GetIsolate());\n");
1062         }
1063     } elsif ($attribute->signature->type eq "MessagePortArray") {
1064         AddToImplIncludes("MessagePort.h");
1065         AddToImplIncludes("V8MessagePort.h");
1066         my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
1067         push(@implContentDecls, <<END);
1068     MessagePortArray* ports = imp->${getterFunc}();
1069     if (!ports)
1070         return v8::Array::New(0);
1071     MessagePortArray portsCopy(*ports);
1072     v8::Local<v8::Array> portArray = v8::Array::New(portsCopy.size());
1073     for (size_t i = 0; i < portsCopy.size(); ++i)
1074         portArray->Set(v8Integer(i, info.GetIsolate()), toV8(portsCopy[i].get(), info.GetIsolate()));
1075     return portArray;
1076 END
1077     } else {
1078         if ($attribute->signature->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) {
1079             my $getterFunc = $codeGenerator->WK_lcfirst($attribute->signature->name);
1080             push(@implContentDecls, <<END);
1081     SerializedScriptValue* serialized = imp->${getterFunc}();
1082     value = serialized ? serialized->deserialize() : v8::Handle<v8::Value>(v8::Null(info.GetIsolate()));
1083     info.Holder()->SetHiddenValue(propertyName, value);
1084     return value;
1085 END
1086         } else {
1087             push(@implContentDecls, "    " . ReturnNativeToJSValue($attribute->signature, $result, "info.GetIsolate()").";\n");
1088         }
1089     }
1090
1091     push(@implContentDecls, "}\n\n");  # end of getter
1092     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1093 }
1094
1095 sub GenerateReplaceableAttrSetter
1096 {
1097     my $dataNode = shift;
1098     my $implClassName = shift;
1099
1100     push(@implContentDecls, <<END);
1101 static void ${implClassName}ReplaceableAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
1102 {
1103     INC_STATS("DOM.$implClassName.replaceable._set");
1104 END
1105     push(@implContentDecls, GenerateFeatureObservation($dataNode->extendedAttributes->{"V8MeasureAs"}));
1106
1107     if ($implClassName eq "DOMWindow" || $dataNode->extendedAttributes->{"CheckSecurity"}) {
1108         push(@implContentDecls, <<END);
1109     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
1110     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
1111         return;
1112 END
1113     }
1114
1115     push(@implContentDecls, <<END);
1116     info.This()->ForceSet(name, value);
1117 }
1118
1119 END
1120 }
1121
1122 sub GenerateNormalAttrSetter
1123 {
1124     my $attribute = shift;
1125     my $dataNode = shift;
1126     my $implClassName = shift;
1127     my $interfaceName = shift;
1128
1129     AddToImplIncludes("V8BindingMacros.h");
1130
1131     my $attrName = $attribute->signature->name;
1132     my $attrExt = $attribute->signature->extendedAttributes;
1133
1134     my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
1135     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1136
1137     push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n");
1138     push(@implContentDecls, "    INC_STATS(\"DOM.$implClassName.$attrName._set\");\n");
1139     push(@implContentDecls, GenerateFeatureObservation($attribute->signature->extendedAttributes->{"V8MeasureAs"}));
1140
1141     # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
1142     # interface type, then if the incoming value does not implement that interface, a TypeError is
1143     # thrown rather than silently passing NULL to the C++ code.
1144     # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both
1145     # strings and numbers, so do not throw TypeError if the attribute is of these types.
1146     if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
1147         my $argType = GetTypeFromSignature($attribute->signature);
1148         if (IsWrapperType($argType)) {
1149             push(@implContentDecls, "    if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n");
1150             push(@implContentDecls, "        V8Proxy::throwTypeError(0, info.GetIsolate());\n");
1151             push(@implContentDecls, "        return;\n");
1152             push(@implContentDecls, "    }\n");
1153         }
1154     }
1155
1156     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName);
1157     if ($svgNativeType) {
1158         my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
1159         if ($svgWrappedNativeType =~ /List$/) {
1160             push(@implContentDecls, <<END);
1161     $svgNativeType* imp = V8${implClassName}::toNative(info.Holder());
1162 END
1163         } else {
1164             AddToImplIncludes("ExceptionCode.h");
1165             push(@implContentDecls, "    $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n");
1166             push(@implContentDecls, "    if (wrapper->isReadOnly()) {\n");
1167             push(@implContentDecls, "        V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, info.GetIsolate());\n");
1168             push(@implContentDecls, "        return;\n");
1169             push(@implContentDecls, "    }\n");
1170             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
1171             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
1172         }
1173     } elsif ($attrExt->{"V8OnProto"}) {
1174         push(@implContentDecls, <<END);
1175     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
1176 END
1177     } else {
1178         my $attrType = GetTypeFromSignature($attribute->signature);
1179         my $reflect = $attribute->signature->extendedAttributes->{"Reflect"};
1180         if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) {
1181             # Generate super-compact call for regular attribute setter:
1182             my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect;
1183             my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
1184             AddToImplIncludes("${namespace}.h");
1185             push(@implContentDecls, "    Element* imp = V8Element::toNative(info.Holder());\n");
1186             push(@implContentDecls, "    AtomicString v = toAtomicWebCoreStringWithNullCheck(value);\n");
1187             push(@implContentDecls, "    imp->setAttribute(${namespace}::${contentAttributeName}Attr, v);\n");
1188             push(@implContentDecls, "}\n\n");
1189             push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1190             return;
1191             # Skip the rest of the function!
1192         }
1193
1194         if (!$attribute->isStatic) {
1195             push(@implContentDecls, <<END);
1196     ${implClassName}* imp = V8${implClassName}::toNative(info.Holder());
1197 END
1198         }
1199     }
1200
1201     my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0);
1202     if ($attribute->signature->type eq "EventListener") {
1203         if ($dataNode->name eq "DOMWindow") {
1204             push(@implContentDecls, "    if (!imp->document())\n");
1205             push(@implContentDecls, "        return;\n");
1206         }
1207     } else {
1208         my $value = JSValueToNative($attribute->signature, "value", "info.GetIsolate()");
1209         my $arrayType = $codeGenerator->GetArrayType($nativeType);
1210
1211         if ($nativeType =~ /^V8Parameter/) {
1212             push(@implContentDecls, "    " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n");
1213         } elsif ($arrayType) {
1214             push(@implContentDecls, "    Vector<$arrayType> v = $value;\n");
1215         } else {
1216             push(@implContentDecls, "    $nativeType v = $value;\n");
1217         }
1218     }
1219
1220     my $result = "v";
1221     my $returnType = GetTypeFromSignature($attribute->signature);
1222     if (IsRefPtrType($returnType) && !$codeGenerator->GetArrayType($returnType)) {
1223         $result = "WTF::getPtr(" . $result . ")";
1224     }
1225
1226     my $useExceptions = 1 if @{$attribute->setterExceptions};
1227
1228     if ($useExceptions) {
1229         AddToImplIncludes("ExceptionCode.h");
1230         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
1231     }
1232
1233     if ($implClassName eq "SVGNumber") {
1234         push(@implContentDecls, "    *imp = $result;\n");
1235     } else {
1236         if ($attribute->signature->type eq "EventListener") {
1237             my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName);
1238             AddToImplIncludes("V8AbstractEventListener.h");
1239             if (!IsNodeSubType($dataNode)) {
1240                 push(@implContentDecls, "    transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n");
1241             }
1242             if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") {
1243                 AddToImplIncludes("V8EventListenerList.h");
1244                 AddToImplIncludes("V8WorkerContextErrorHandler.h");
1245                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)");
1246             } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") {
1247                 AddToImplIncludes("V8EventListenerList.h");
1248                 AddToImplIncludes("V8WindowErrorHandler.h");
1249                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)");
1250             } else {
1251                 push(@implContentDecls, "    imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)");
1252             }
1253             push(@implContentDecls, ", ec") if $useExceptions;
1254             push(@implContentDecls, ");\n");
1255         } else {
1256             my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
1257             push(@arguments, $result);
1258             push(@arguments, "ec") if $useExceptions;
1259             if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
1260                 my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
1261                 AddToImplIncludes("${implementedBy}.h");
1262                 unshift(@arguments, "imp") if !$attribute->isStatic;
1263                 $functionName = "${implementedBy}::${functionName}";
1264             } elsif ($attribute->isStatic) {
1265                 $functionName = "${interfaceName}::${functionName}";
1266             } else {
1267                 $functionName = "imp->${functionName}";
1268             }
1269             unshift(@arguments, GenerateCallWith($attribute->signature->extendedAttributes->{"CallWith"}, \@implContentDecls, "    ", 1, 0));
1270             push(@implContentDecls, "    ${functionName}(" . join(", ", @arguments) . ");\n");
1271         }
1272     }
1273
1274     if ($useExceptions) {
1275         push(@implContentDecls, "    if (UNLIKELY(ec))\n");
1276         push(@implContentDecls, "        V8Proxy::setDOMException(ec, info.GetIsolate());\n");
1277     }
1278
1279     if ($codeGenerator->ExtendedAttributeContains($attribute->signature->extendedAttributes->{"CallWith"}, "ScriptState")) {
1280         push(@implContentDecls, "    if (state.hadException())\n");
1281         push(@implContentDecls, "        throwError(state.exception(), info.GetIsolate());\n");
1282     }
1283
1284     if ($svgNativeType) {
1285         if ($useExceptions) {
1286             push(@implContentDecls, "    if (!ec)\n");
1287             push(@implContentDecls, "        wrapper->commitChange();\n");
1288         } else {
1289             push(@implContentDecls, "    wrapper->commitChange();\n");
1290         }
1291     }
1292
1293     if ($attribute->signature->type eq "SerializedScriptValue" && $attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1294         push(@implContentDecls, <<END);
1295     info.Holder()->DeleteHiddenValue(v8::String::NewSymbol("${attrName}")); // Invalidate the cached value.
1296 END
1297     }
1298
1299     push(@implContentDecls, "    return;\n");
1300     push(@implContentDecls, "}\n\n");  # end of setter
1301     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1302 }
1303
1304 sub GetFunctionTemplateCallbackName
1305 {
1306     my $function = shift;
1307     my $interfaceName = shift;
1308
1309     my $name = $function->signature->name;
1310
1311     if ($function->signature->extendedAttributes->{"Custom"} ||
1312         $function->signature->extendedAttributes->{"V8Custom"}) {
1313         if ($function->signature->extendedAttributes->{"Custom"} &&
1314             $function->signature->extendedAttributes->{"V8Custom"}) {
1315             die "Custom and V8Custom should be mutually exclusive!"
1316         }
1317         return "V8${interfaceName}::${name}Callback";
1318     } else {
1319         return "${interfaceName}V8Internal::${name}Callback";
1320     }
1321 }
1322
1323 sub GenerateNewFunctionTemplate
1324 {
1325     my $function = shift;
1326     my $interfaceName = shift;
1327     my $signature = shift;
1328
1329     my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
1330     return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)";
1331 }
1332
1333 sub GenerateEventListenerCallback
1334 {
1335     my $implClassName = shift;
1336     my $requiresHiddenDependency = shift;
1337     my $functionName = shift;
1338     my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only";
1339     my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
1340     my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove";
1341  
1342     push(@implContentDecls, <<END);
1343 static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args)
1344 {
1345     INC_STATS("DOM.${implClassName}.${functionName}EventListener()");
1346     RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType});
1347     if (listener) {
1348         V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue());
1349 END
1350     if ($requiresHiddenDependency) {
1351         push(@implContentDecls, <<END);
1352         ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex);
1353 END
1354     }
1355     push(@implContentDecls, <<END);
1356     }
1357     return v8::Undefined();
1358 }
1359
1360 END
1361 }
1362
1363 sub GenerateParametersCheckExpression
1364 {
1365     my $numParameters = shift;
1366     my $function = shift;
1367
1368     my @andExpression = ();
1369     push(@andExpression, "args.Length() == $numParameters");
1370     my $parameterIndex = 0;
1371     foreach my $parameter (@{$function->parameters}) {
1372         last if $parameterIndex >= $numParameters;
1373         my $value = "args[$parameterIndex]";
1374         my $type = GetTypeFromSignature($parameter);
1375
1376         # Only DOMString or wrapper types are checked.
1377         # For DOMString, Null, Undefined and any Object are accepted too, as
1378         # these are acceptable values for a DOMString argument (any Object can
1379         # be converted to a string via .toString).
1380         if ($codeGenerator->IsStringType($type)) {
1381             push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())");
1382         } elsif ($parameter->extendedAttributes->{"Callback"}) {
1383             # For Callbacks only checks if the value is null or object.
1384             push(@andExpression, "(${value}->IsNull() || ${value}->IsFunction())");
1385         } elsif (IsArrayType($type) || $codeGenerator->GetSequenceType($type)) {
1386             # FIXME: Add proper support for T[], T[]?, sequence<T>.
1387             if ($parameter->isNullable) {
1388                 push(@andExpression, "(${value}->IsNull() || ${value}->IsArray())");
1389             } else {
1390                 push(@andExpression, "(${value}->IsArray())");
1391             }
1392         } elsif (IsWrapperType($type)) {
1393             if ($parameter->isNullable) {
1394                 push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))");
1395             } else {
1396                 push(@andExpression, "(V8${type}::HasInstance($value))");
1397             }
1398         }
1399
1400         $parameterIndex++;
1401     }
1402     my $res = join(" && ", @andExpression);
1403     $res = "($res)" if @andExpression > 1;
1404     return $res;
1405 }
1406
1407 sub GenerateFunctionParametersCheck
1408 {
1409     my $function = shift;
1410
1411     my @orExpression = ();
1412     my $numParameters = 0;
1413     foreach my $parameter (@{$function->parameters}) {
1414         if ($parameter->extendedAttributes->{"Optional"}) {
1415             push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1416         }
1417         $numParameters++;
1418     }
1419     push(@orExpression, GenerateParametersCheckExpression($numParameters, $function));
1420     return join(" || ", @orExpression);
1421 }
1422
1423 sub GenerateOverloadedFunctionCallback
1424 {
1425     my $function = shift;
1426     my $dataNode = shift;
1427     my $implClassName = shift;
1428
1429     # Generate code for choosing the correct overload to call. Overloads are
1430     # chosen based on the total number of arguments passed and the type of
1431     # values passed in non-primitive argument slots. When more than a single
1432     # overload is applicable, precedence is given according to the order of
1433     # declaration in the IDL.
1434
1435     my $name = $function->signature->name;
1436     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1437     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1438     push(@implContentDecls, <<END);
1439 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1440 {
1441     INC_STATS(\"DOM.$implClassName.$name\");
1442 END
1443     push(@implContentDecls, GenerateFeatureObservation($function->signature->extendedAttributes->{"V8MeasureAs"}));
1444
1445     foreach my $overload (@{$function->{overloads}}) {
1446         my $parametersCheck = GenerateFunctionParametersCheck($overload);
1447         push(@implContentDecls, "    if ($parametersCheck)\n");
1448         push(@implContentDecls, "        return ${name}$overload->{overloadIndex}Callback(args);\n");
1449     }
1450     push(@implContentDecls, <<END);
1451     return V8Proxy::throwTypeError(0, args.GetIsolate());
1452 END
1453     push(@implContentDecls, "}\n\n");
1454     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1455 }
1456
1457 sub GenerateFunctionCallback
1458 {
1459     my $function = shift;
1460     my $dataNode = shift;
1461     my $implClassName = shift;
1462
1463     my $interfaceName = $dataNode->name;
1464     my $name = $function->signature->name;
1465
1466     if (@{$function->{overloads}} > 1) {
1467         # Append a number to an overloaded method's name to make it unique:
1468         $name = $name . $function->{overloadIndex};
1469     }
1470
1471     # Adding and removing event listeners are not standard callback behavior,
1472     # but they are extremely consistent across the various classes that take event listeners,
1473     # so we can generate them as a "special case".
1474     if ($name eq "addEventListener") {
1475         GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "add");
1476         return;
1477     } elsif ($name eq "removeEventListener") {
1478         GenerateEventListenerCallback($implClassName, !IsNodeSubType($dataNode), "remove");
1479         return;
1480     }
1481
1482     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
1483     push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString;
1484     push(@implContentDecls, <<END);
1485 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args)
1486 {
1487     INC_STATS(\"DOM.$implClassName.$name\");
1488 END
1489     push(@implContentDecls, GenerateFeatureObservation($function->signature->extendedAttributes->{"V8MeasureAs"}));
1490
1491     push(@implContentDecls, GenerateArgumentsCountCheck($function, $dataNode));
1492
1493     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName);
1494
1495     if ($svgNativeType) {
1496         my $nativeClassName = GetNativeType($implClassName); 
1497         if ($implClassName =~ /List$/) {
1498             push(@implContentDecls, "    $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n");
1499         } else {
1500             AddToImplIncludes("ExceptionCode.h");
1501             push(@implContentDecls, "    $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n");
1502             push(@implContentDecls, "    if (wrapper->isReadOnly())\n");
1503             push(@implContentDecls, "        return V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR, args.GetIsolate());\n");
1504             my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName);
1505             push(@implContentDecls, "    $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n");
1506             push(@implContentDecls, "    $svgWrappedNativeType* imp = &impInstance;\n");
1507         }
1508     } elsif (!$function->isStatic) {
1509         push(@implContentDecls, <<END);
1510     ${implClassName}* imp = V8${implClassName}::toNative(args.Holder());
1511 END
1512     }
1513
1514     # Check domain security if needed
1515     if (($dataNode->extendedAttributes->{"CheckSecurity"}
1516         || $interfaceName eq "DOMWindow")
1517         && !$function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
1518         # We have not find real use cases yet.
1519         push(@implContentDecls, <<END);
1520     if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true))
1521         return v8::Handle<v8::Value>();
1522 END
1523     }
1524
1525     my $raisesExceptions = @{$function->raisesExceptions};
1526     if (!$raisesExceptions) {
1527         foreach my $parameter (@{$function->parameters}) {
1528             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1529                 $raisesExceptions = 1;
1530             }
1531         }
1532     }
1533
1534     if ($raisesExceptions) {
1535         AddToImplIncludes("ExceptionCode.h");
1536         push(@implContentDecls, "    ExceptionCode ec = 0;\n");
1537         push(@implContentDecls, "    {\n");
1538         # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors
1539         # of objects (like Strings) declared later, causing compile errors. The block scope ends
1540         # right before the label 'fail:'.
1541     }
1542
1543     if ($function->signature->extendedAttributes->{"CheckSecurityForNode"}) {
1544         push(@implContentDecls, "    if (!V8BindingSecurity::shouldAllowAccessToNode(V8BindingState::Only(), imp->" . $function->signature->name . "(ec)))\n");
1545         push(@implContentDecls, "        return v8::Handle<v8::Value>(v8::Null(args.GetIsolate()));\n");
1546 END
1547     }
1548
1549     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
1550     push(@implContentDecls, $parameterCheckString);
1551
1552     # Build the function call string.
1553     push(@implContentDecls, GenerateFunctionCallString($function, $paramIndex, "    ", $implClassName, %replacements));
1554
1555     if ($raisesExceptions) {
1556         push(@implContentDecls, "    }\n");
1557         push(@implContentDecls, "    fail:\n");
1558         push(@implContentDecls, "    return V8Proxy::setDOMException(ec, args.GetIsolate());\n");
1559     }
1560
1561     push(@implContentDecls, "}\n\n");
1562     push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString;
1563 }
1564
1565 sub GenerateCallWith
1566 {
1567     my $callWith = shift;
1568     return () unless $callWith;
1569     my $outputArray = shift;
1570     my $indent = shift;
1571     my $returnVoid = shift;
1572     my $emptyContext = shift;
1573     my $function = shift;
1574
1575     my @callWithArgs;
1576     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
1577         if ($emptyContext) {
1578             push(@$outputArray, $indent . "EmptyScriptState state;\n");
1579             push(@callWithArgs, "&state");
1580         } else {
1581             push(@$outputArray, $indent . "ScriptState* state = ScriptState::current();\n");
1582             push(@$outputArray, $indent . "if (!state)\n");
1583             push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
1584             push(@callWithArgs, "state");
1585         }
1586     }
1587     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptExecutionContext")) {
1588         push(@$outputArray, $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n");
1589         push(@$outputArray, $indent . "if (!scriptContext)\n");
1590         push(@$outputArray, $indent . "    return" . ($returnVoid ? "" : " v8::Undefined()") . ";\n");
1591         push(@callWithArgs, "scriptContext");
1592     }
1593     if ($function and $codeGenerator->ExtendedAttributeContains($callWith, "ScriptArguments")) {
1594         push(@$outputArray, $indent . "RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, " . @{$function->parameters} . "));\n");
1595         push(@callWithArgs, "scriptArguments");
1596         AddToImplIncludes("ScriptArguments.h");
1597     }
1598     if ($codeGenerator->ExtendedAttributeContains($callWith, "CallStack")) {
1599         push(@$outputArray, $indent . "RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector());\n");
1600         push(@$outputArray, $indent . "if (!callStack)\n");
1601         push(@$outputArray, $indent . "    return v8::Undefined();\n");
1602         push(@callWithArgs, "callStack");
1603         AddToImplIncludes("ScriptCallStack.h");
1604         AddToImplIncludes("ScriptCallStackFactory.h");
1605     }
1606     return @callWithArgs;
1607 }
1608
1609 sub GenerateArgumentsCountCheck
1610 {
1611     my $function = shift;
1612     my $dataNode = shift;
1613
1614     my $numMandatoryParams = 0;
1615     my $optionalSeen = 0;
1616     foreach my $param (@{$function->parameters}) {
1617         if ($param->extendedAttributes->{"Optional"}) {
1618             $optionalSeen = 1;
1619         } else {
1620             die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if $optionalSeen;
1621             $numMandatoryParams++;
1622         }
1623     }
1624
1625     my $argumentsCountCheckString = "";
1626     if ($numMandatoryParams >= 1) {
1627         $argumentsCountCheckString .= "    if (args.Length() < $numMandatoryParams)\n";
1628         $argumentsCountCheckString .= "        return V8Proxy::throwNotEnoughArgumentsError(args.GetIsolate());\n";
1629     }
1630     return $argumentsCountCheckString;
1631 }
1632
1633 sub GetIndexOf
1634 {
1635     my $paramName = shift;
1636     my @paramList = @_;
1637     my $index = 0;
1638     foreach my $param (@paramList) {
1639         if ($paramName eq $param) {
1640             return $index;
1641         }
1642         $index++;
1643     }
1644     return -1;
1645 }
1646
1647 sub GenerateParametersCheck
1648 {
1649     my $function = shift;
1650     my $implClassName = shift;
1651
1652     my $parameterCheckString = "";
1653     my $paramIndex = 0;
1654     my @paramTransferListNames = ();
1655     my %replacements = ();
1656
1657     foreach my $parameter (@{$function->parameters}) {
1658         TranslateParameter($parameter);
1659
1660         my $parameterName = $parameter->name;
1661
1662         # Optional arguments with [Optional] should generate an early call with fewer arguments.
1663         # Optional arguments with [Optional=...] should not generate the early call.
1664         my $optional = $parameter->extendedAttributes->{"Optional"};
1665         if ($optional && $optional ne "DefaultIsUndefined" && $optional ne "DefaultIsNullString" && !$parameter->extendedAttributes->{"Callback"}) {
1666             $parameterCheckString .= "    if (args.Length() <= $paramIndex) {\n";
1667             my $functionCall = GenerateFunctionCallString($function, $paramIndex, "    " x 2, $implClassName, %replacements);
1668             $parameterCheckString .= $functionCall;
1669             $parameterCheckString .= "    }\n";
1670         }
1671
1672         my $parameterDefaultPolicy = "DefaultIsUndefined";
1673         if ($optional and $optional eq "DefaultIsNullString") {
1674             $parameterDefaultPolicy = "DefaultIsNullString";
1675         }
1676
1677         if (GetIndexOf($parameterName, @paramTransferListNames) != -1) {
1678             $replacements{$parameterName} = "messagePortArray" . ucfirst($parameterName);
1679             $paramIndex++;
1680             next;
1681         }
1682
1683         AddToImplIncludes("ExceptionCode.h");
1684         my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex);
1685         if ($parameter->extendedAttributes->{"Callback"}) {
1686             my $className = GetCallbackClassName($parameter->type);
1687             AddToImplIncludes("$className.h");
1688             if ($optional) {
1689                 $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName;\n";
1690                 $parameterCheckString .= "    if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n";
1691                 $parameterCheckString .= "        if (!args[$paramIndex]->IsFunction())\n";
1692                 $parameterCheckString .= "            return throwError(TYPE_MISMATCH_ERR, args.GetIsolate());\n";
1693                 $parameterCheckString .= "        $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
1694                 $parameterCheckString .= "    }\n";
1695             } else {
1696                 $parameterCheckString .= "    if (args.Length() <= $paramIndex || !args[$paramIndex]->IsFunction())\n";
1697                 $parameterCheckString .= "        return throwError(TYPE_MISMATCH_ERR, args.GetIsolate());\n";
1698                 $parameterCheckString .= "    RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n";
1699             }
1700         } elsif ($parameter->extendedAttributes->{"Clamp"}) {
1701                 my $nativeValue = "${parameterName}NativeValue";
1702                 my $paramType = $parameter->type;
1703                 $parameterCheckString .= "    $paramType $parameterName = 0\n";
1704                 $parameterCheckString .= "    EXCEPTION_BLOCK(double, $nativeValue, args[$paramIndex]->NumberValue());\n";
1705                 $parameterCheckString .= "    if (!isnan($nativeValue))\n";
1706                 $parameterCheckString .= "        $parameterName = clampTo<$paramType>($nativeValue);\n";
1707         } elsif ($parameter->type eq "SerializedScriptValue") {
1708             AddToImplIncludes("SerializedScriptValue.h");
1709             my $useTransferList = 0;
1710             my $transferListName = "";
1711             my $TransferListName = "";
1712             if ($parameter->extendedAttributes->{"TransferList"}) {
1713                 $transferListName = $parameter->extendedAttributes->{"TransferList"};
1714                 push(@paramTransferListNames, $transferListName);
1715
1716                 my @allParameterNames = ();
1717                 foreach my $parameter (@{$function->parameters}) {
1718                     push(@allParameterNames, $parameter->name);
1719                 }
1720                 my $transferListIndex = GetIndexOf($transferListName, @allParameterNames);
1721                 if ($transferListIndex == -1) {
1722                     die "IDL error: TransferList refers to a nonexistent argument";
1723                 }
1724
1725                 AddToImplIncludes("wtf/ArrayBuffer.h");
1726                 AddToImplIncludes("MessagePort.h");
1727                 $TransferListName = ucfirst($transferListName);
1728                 $parameterCheckString .= "    MessagePortArray messagePortArray$TransferListName;\n";
1729                 $parameterCheckString .= "    ArrayBufferArray arrayBufferArray$TransferListName;\n";
1730                 $parameterCheckString .= "    if (args.Length() > $transferListIndex) {\n";
1731                 $parameterCheckString .= "        if (!extractTransferables(args[$transferListIndex], messagePortArray$TransferListName, arrayBufferArray$TransferListName))\n";
1732                 $parameterCheckString .= "            return V8Proxy::throwTypeError(\"Could not extract transferables\");\n";
1733                 $parameterCheckString .= "    }\n";
1734                 $useTransferList = 1;
1735             }
1736             $parameterCheckString .= "    bool ${parameterName}DidThrow = false;\n";
1737             if (!$useTransferList) {
1738                     $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], 0, 0, ${parameterName}DidThrow, args.GetIsolate());\n";
1739             } else {
1740                     $parameterCheckString .= "    $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], &messagePortArray$TransferListName, &arrayBufferArray$TransferListName, ${parameterName}DidThrow, args.GetIsolate());\n";
1741             }
1742             $parameterCheckString .= "    if (${parameterName}DidThrow)\n";
1743             $parameterCheckString .= "        return v8::Undefined();\n";
1744         } elsif (TypeCanFailConversion($parameter)) {
1745             $parameterCheckString .= "    $nativeType $parameterName = " .
1746                  JSValueToNative($parameter, "args[$paramIndex]", "args.GetIsolate()") . ";\n";
1747             $parameterCheckString .= "    if (UNLIKELY(!$parameterName)) {\n";
1748             $parameterCheckString .= "        ec = TYPE_MISMATCH_ERR;\n";
1749             $parameterCheckString .= "        goto fail;\n";
1750             $parameterCheckString .= "    }\n";
1751         } elsif ($nativeType =~ /^V8Parameter/) {
1752             my $value = JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()");
1753             $parameterCheckString .= "    " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n";
1754         } else {
1755             AddToImplIncludes("V8BindingMacros.h");
1756             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
1757             # interface type, then if the incoming value does not implement that interface, a TypeError
1758             # is thrown rather than silently passing NULL to the C++ code.
1759             # Per the Web IDL and ECMAScript specifications, incoming values can always be converted
1760             # to both strings and numbers, so do not throw TypeError if the argument is of these
1761             # types.
1762             if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
1763                 my $argValue = "args[$paramIndex]";
1764                 my $argType = GetTypeFromSignature($parameter);
1765                 if (IsWrapperType($argType)) {
1766                     $parameterCheckString .= "    if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue))\n";
1767                     $parameterCheckString .= "        return V8Proxy::throwTypeError(0, args.GetIsolate());\n";
1768                 }
1769             }
1770             $parameterCheckString .= "    EXCEPTION_BLOCK($nativeType, $parameterName, " .
1771                  JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(args, $paramIndex, $parameterDefaultPolicy)", "args.GetIsolate()") . ");\n";
1772             if ($nativeType eq 'Dictionary') {
1773                $parameterCheckString .= "    if (!$parameterName.isUndefinedOrNull() && !$parameterName.isObject())\n";
1774                $parameterCheckString .= "        return V8Proxy::throwTypeError(\"Not an object.\", args.GetIsolate());\n";
1775             }
1776         }
1777
1778         if ($parameter->extendedAttributes->{"IsIndex"}) {
1779             $parameterCheckString .= "    if (UNLIKELY($parameterName < 0)) {\n";
1780             $parameterCheckString .= "        ec = INDEX_SIZE_ERR;\n";
1781             $parameterCheckString .= "        goto fail;\n";
1782             $parameterCheckString .= "    }\n";
1783         }
1784
1785         $paramIndex++;
1786     }
1787     return ($parameterCheckString, $paramIndex, %replacements);
1788 }
1789
1790 sub GenerateConstructorCallback
1791 {
1792     my $function = shift;
1793     my $dataNode = shift;
1794     my $implClassName = shift;
1795
1796     my $raisesExceptions = @{$function->raisesExceptions};
1797     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1798         $raisesExceptions = 1;
1799     }
1800     if (!$raisesExceptions) {
1801         foreach my $parameter (@{$function->parameters}) {
1802             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1803                 $raisesExceptions = 1;
1804             }
1805         }
1806     }
1807
1808     my $maybeObserveFeature = GenerateFeatureObservation($function->signature->extendedAttributes->{"V8MeasureAs"});
1809
1810     my @beforeArgumentList;
1811     my @afterArgumentList;
1812     push(@implContent, <<END);
1813 v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
1814 {
1815     INC_STATS("DOM.${implClassName}.Constructor");
1816     ${maybeObserveFeature}
1817     if (!args.IsConstructCall())
1818         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1819
1820     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1821         return args.Holder();
1822 END
1823
1824     push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));
1825
1826     if ($raisesExceptions) {
1827         AddToImplIncludes("ExceptionCode.h");
1828         push(@implContent, "\n");
1829         push(@implContent, "    ExceptionCode ec = 0;\n");
1830     }
1831
1832     # FIXME: Currently [Constructor(...)] does not yet support [Optional] arguments.
1833     # It just supports [Optional=DefaultIsUndefined] or [Optional=DefaultIsNullString].
1834     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
1835     push(@implContent, $parameterCheckString);
1836
1837     if ($dataNode->extendedAttributes->{"CallWith"} && $dataNode->extendedAttributes->{"CallWith"} eq "ScriptExecutionContext") {
1838         push(@beforeArgumentList, "context");
1839         push(@implContent, <<END);
1840
1841     ScriptExecutionContext* context = getScriptExecutionContext();
1842     if (!context)
1843         return V8Proxy::throwError(V8Proxy::ReferenceError, "${implClassName} constructor's associated context is not available", args.GetIsolate());
1844 END
1845     }
1846
1847     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1848         push(@afterArgumentList, "ec");
1849     }
1850
1851     my @argumentList;
1852     my $index = 0;
1853     foreach my $parameter (@{$function->parameters}) {
1854         last if $index eq $paramIndex;
1855         if ($replacements{$parameter->name}) {
1856             push(@argumentList, $replacements{$parameter->name});
1857         } else {
1858             push(@argumentList, $parameter->name);
1859         }
1860         $index++;
1861     }
1862
1863     my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
1864     push(@implContent, "\n");
1865     push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::create(${argumentString});\n");
1866     push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");
1867
1868     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1869         push(@implContent, "    if (ec)\n");
1870         push(@implContent, "        goto fail;\n");
1871     }
1872
1873     my $DOMObject = GetDomMapName($dataNode, $implClassName);
1874     push(@implContent, <<END);
1875
1876     V8DOMWrapper::setDOMWrapper(wrapper, &info, impl.get());
1877     V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
1878     return args.Holder();
1879 END
1880
1881     if ($raisesExceptions) {
1882         push(@implContent, "  fail:\n");
1883         push(@implContent, "    return throwError(ec, args.GetIsolate());\n");
1884     }
1885
1886     push(@implContent, "}\n");
1887     push(@implContent, "\n");
1888 }
1889
1890 sub GenerateEventConstructorCallback
1891 {
1892     my $dataNode = shift;
1893     my $implClassName = shift;
1894
1895     AddToImplIncludes("Dictionary.h");
1896     AddToImplIncludes("V8BindingMacros.h");
1897     push(@implContent, <<END);
1898 v8::Handle<v8::Value> V8${implClassName}::constructorCallback(const v8::Arguments& args)
1899 {
1900     INC_STATS("DOM.${implClassName}.Constructor");
1901
1902     if (!args.IsConstructCall())
1903         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1904
1905     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1906         return args.Holder();
1907
1908     if (args.Length() < 1)
1909         return V8Proxy::throwNotEnoughArgumentsError(args.GetIsolate());
1910
1911     STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, type, args[0]);
1912     ${implClassName}Init eventInit;
1913     if (args.Length() >= 2) {
1914         EXCEPTION_BLOCK(Dictionary, options, args[1]);
1915         if (!fill${implClassName}Init(eventInit, options))
1916             return v8::Undefined();
1917     }
1918
1919     RefPtr<${implClassName}> event = ${implClassName}::create(type, eventInit);
1920
1921     V8DOMWrapper::setDOMWrapper(args.Holder(), &info, event.get());
1922     V8DOMWrapper::setJSWrapperForDOMObject(event.release(), v8::Persistent<v8::Object>::New(args.Holder()), args.GetIsolate());
1923     return args.Holder();
1924 }
1925
1926 bool fill${implClassName}Init(${implClassName}Init& eventInit, const Dictionary& options)
1927 {
1928 END
1929
1930     foreach my $interfaceBase (@{$dataNode->parents}) {
1931         push(@implContent, <<END);
1932     if (!fill${interfaceBase}Init(eventInit, options))
1933         return false;
1934
1935 END
1936     }
1937
1938     for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
1939         my $attribute = @{$dataNode->attributes}[$index];
1940         if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
1941             my $attributeName = $attribute->signature->name;
1942             push(@implContent, "    options.get(\"$attributeName\", eventInit.$attributeName);\n");
1943         }
1944     }
1945
1946     push(@implContent, <<END);
1947     return true;
1948 }
1949
1950 END
1951 }
1952
1953 sub GenerateNamedConstructorCallback
1954 {
1955     my $function = shift;
1956     my $dataNode = shift;
1957     my $implClassName = shift;
1958
1959     my $raisesExceptions = @{$function->raisesExceptions};
1960     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
1961         $raisesExceptions = 1;
1962     }
1963     if (!$raisesExceptions) {
1964         foreach my $parameter (@{$function->parameters}) {
1965             if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) {
1966                 $raisesExceptions = 1;
1967             }
1968         }
1969     }
1970
1971     my $maybeObserveFeature = GenerateFeatureObservation($function->signature->extendedAttributes->{"V8MeasureAs"});
1972
1973     my @beforeArgumentList;
1974     my @afterArgumentList;
1975
1976     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
1977         push(@implContent, <<END);
1978 WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, V8${implClassName}::derefObject, V8${implClassName}::toActiveDOMObject, 0, 0, WrapperTypeObjectPrototype };
1979
1980 END
1981     } else {
1982         push(@implContent, <<END);
1983 WrapperTypeInfo V8${implClassName}Constructor::info = { V8${implClassName}Constructor::GetTemplate, 0, 0, 0, 0, WrapperTypeObjectPrototype };
1984
1985 END
1986     }
1987
1988     push(@implContent, <<END);
1989 static v8::Handle<v8::Value> V8${implClassName}ConstructorCallback(const v8::Arguments& args)
1990 {
1991     INC_STATS("DOM.${implClassName}.Constructor");
1992     ${maybeObserveFeature}
1993     if (!args.IsConstructCall())
1994         return V8Proxy::throwTypeError("DOM object constructor cannot be called as a function.");
1995
1996     if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
1997         return args.Holder();
1998
1999     Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
2000     if (!frame)
2001         return V8Proxy::throwError(V8Proxy::ReferenceError, "${implClassName} constructor associated frame is unavailable", args.GetIsolate());
2002
2003     Document* document = frame->document();
2004
2005     // Make sure the document is added to the DOM Node map. Otherwise, the ${implClassName} instance
2006     // may end up being the only node in the map and get garbage-collected prematurely.
2007     toV8(document, args.GetIsolate());
2008
2009 END
2010
2011     push(@implContent, GenerateArgumentsCountCheck($function, $dataNode));
2012
2013     if ($raisesExceptions) {
2014         AddToImplIncludes("ExceptionCode.h");
2015         push(@implContent, "\n");
2016         push(@implContent, "    ExceptionCode ec = 0;\n");
2017     }
2018
2019     my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $implClassName);
2020     push(@implContent, $parameterCheckString);
2021
2022     push(@beforeArgumentList, "document");
2023
2024     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
2025         push(@afterArgumentList, "ec");
2026     }
2027
2028     my @argumentList;
2029     my $index = 0;
2030     foreach my $parameter (@{$function->parameters}) {
2031         last if $index eq $paramIndex;
2032         if ($replacements{$parameter->name}) {
2033             push(@argumentList, $replacements{$parameter->name});
2034         } else {
2035             push(@argumentList, $parameter->name);
2036         }
2037         $index++;
2038     }
2039
2040     my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList);
2041     push(@implContent, "\n");
2042     push(@implContent, "    RefPtr<${implClassName}> impl = ${implClassName}::createForJSConstructor(${argumentString});\n");
2043     push(@implContent, "    v8::Handle<v8::Object> wrapper = args.Holder();\n");
2044
2045     if ($dataNode->extendedAttributes->{"ConstructorRaisesException"}) {
2046         push(@implContent, "    if (ec)\n");
2047         push(@implContent, "        goto fail;\n");
2048     }
2049
2050     my $DOMObject = GetDomMapName($dataNode, $implClassName);
2051     push(@implContent, <<END);
2052
2053     V8DOMWrapper::setDOMWrapper(wrapper, &V8${implClassName}Constructor::info, impl.get());
2054     V8DOMWrapper::setJSWrapperFor${DOMObject}(impl.release(), v8::Persistent<v8::Object>::New(wrapper), args.GetIsolate());
2055     return args.Holder();
2056 END
2057
2058     if ($raisesExceptions) {
2059         push(@implContent, "  fail:\n");
2060         push(@implContent, "    return throwError(ec, args.GetIsolate());\n");
2061     }
2062
2063     push(@implContent, "}\n");
2064
2065     push(@implContent, <<END);
2066
2067 v8::Persistent<v8::FunctionTemplate> V8${implClassName}Constructor::GetTemplate()
2068 {
2069     static v8::Persistent<v8::FunctionTemplate> cachedTemplate;
2070     if (!cachedTemplate.IsEmpty())
2071         return cachedTemplate;
2072
2073     v8::HandleScope scope;
2074     v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8${implClassName}ConstructorCallback);
2075
2076     v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate();
2077     instance->SetInternalFieldCount(V8${implClassName}::internalFieldCount);
2078     result->SetClassName(v8::String::New("${implClassName}"));
2079     result->Inherit(V8${implClassName}::GetTemplate());
2080
2081     cachedTemplate = v8::Persistent<v8::FunctionTemplate>::New(result);
2082     return cachedTemplate;
2083 }
2084
2085 END
2086 }
2087
2088 sub GenerateBatchedAttributeData
2089 {
2090     my $dataNode = shift;
2091     my $interfaceName = $dataNode->name;
2092     my $attributes = shift;
2093
2094     foreach my $attribute (@$attributes) {
2095         my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
2096         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2097         GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", "");
2098         push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2099     }
2100 }
2101
2102 sub GenerateSingleBatchedAttribute
2103 {
2104     my $interfaceName = shift;
2105     my $attribute = shift;
2106     my $delimiter = shift;
2107     my $indent = shift;
2108     my $attrName = $attribute->signature->name;
2109     my $attrExt = $attribute->signature->extendedAttributes;
2110
2111     my $accessControl = "v8::DEFAULT";
2112     if ($attrExt->{"DoNotCheckSecurityOnGetter"}) {
2113         $accessControl = "v8::ALL_CAN_READ";
2114     } elsif ($attrExt->{"DoNotCheckSecurityOnSetter"}) {
2115         $accessControl = "v8::ALL_CAN_WRITE";
2116     } elsif ($attrExt->{"DoNotCheckSecurity"}) {
2117         $accessControl = "v8::ALL_CAN_READ";
2118         if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) {
2119             $accessControl .= " | v8::ALL_CAN_WRITE";
2120         }
2121     }
2122     if ($attrExt->{"V8Unforgeable"}) {
2123         $accessControl .= " | v8::PROHIBITS_OVERWRITING";
2124     }
2125     $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")";
2126
2127     my $customAccessor =
2128         $attrExt->{"Custom"} ||
2129         $attrExt->{"CustomSetter"} ||
2130         $attrExt->{"CustomGetter"} ||
2131         $attrExt->{"V8Custom"} ||
2132         $attrExt->{"V8CustomSetter"} ||
2133         $attrExt->{"V8CustomGetter"} ||
2134         "";
2135     if ($customAccessor eq "VALUE_IS_MISSING") {
2136         # use the naming convension, interface + (capitalize) attr name
2137         $customAccessor = $interfaceName . "::" . $attrName;
2138     }
2139
2140     my $getter;
2141     my $setter;
2142     my $propAttr = "v8::None";
2143     my $hasCustomSetter = 0;
2144
2145     # Check attributes.
2146     if ($attrExt->{"NotEnumerable"}) {
2147         $propAttr .= " | v8::DontEnum";
2148     }
2149     if ($attrExt->{"V8Unforgeable"}) {
2150         $propAttr .= " | v8::DontDelete";
2151     }
2152
2153     my $on_proto = "0 /* on instance */";
2154     my $data = "0 /* no data */";
2155
2156     # Constructor
2157     if ($attribute->signature->type =~ /Constructor$/) {
2158         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
2159         $constructorType =~ s/Constructor$//;
2160         # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
2161         # We do not generate the header file for NamedConstructor of class XXXX,
2162         # since we generate the NamedConstructor declaration into the header file of class XXXX.
2163         if ($constructorType !~ /Constructor$/ || $attribute->signature->extendedAttributes->{"V8CustomConstructor"} || $attribute->signature->extendedAttributes->{"CustomConstructor"}) {
2164             AddToImplIncludes("V8${constructorType}.h", $attribute->signature->extendedAttributes->{"Conditional"});
2165         }
2166         if ($customAccessor) {
2167             $getter = "V8${customAccessor}AccessorGetter";
2168         } else {
2169             $data = "&V8${constructorType}::info";
2170             $getter = "${interfaceName}V8Internal::${interfaceName}ConstructorGetter";
2171         }
2172         $setter = "${interfaceName}V8Internal::${interfaceName}ReplaceableAttrSetter";
2173     } else {
2174         # Default Getter and Setter
2175         $getter = "${interfaceName}V8Internal::${attrName}AttrGetter";
2176         $setter = "${interfaceName}V8Internal::${attrName}AttrSetter";
2177
2178         if ($attrExt->{"Replaceable"}) {
2179             $setter = "${interfaceName}V8Internal::${interfaceName}ReplaceableAttrSetter";
2180         }
2181
2182         # Custom Setter
2183         if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
2184             $hasCustomSetter = 1;
2185             $setter = "V8${customAccessor}AccessorSetter";
2186         }
2187
2188         # Custom Getter
2189         if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) {
2190             $getter = "V8${customAccessor}AccessorGetter";
2191         }
2192     }
2193
2194     # Read only attributes
2195     if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) {
2196         $setter = "0";
2197     }
2198
2199     # An accessor can be installed on the proto
2200     if ($attrExt->{"V8OnProto"}) {
2201         $on_proto = "1 /* on proto */";
2202     }
2203
2204     my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type .
2205                       "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
2206
2207     push(@implContent, $indent . "    \/\/ $commentInfo\n");
2208     push(@implContent, $indent . "    {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n");
2209 }
2210
2211 sub IsStandardFunction
2212 {
2213     my $dataNode = shift;
2214     my $function = shift;
2215
2216     my $interfaceName = $dataNode->name;
2217     my $attrExt = $function->signature->extendedAttributes;
2218     return 0 if $attrExt->{"V8Unforgeable"};
2219     return 0 if $function->isStatic;
2220     return 0 if $attrExt->{"V8EnabledAtRuntime"};
2221     return 0 if $attrExt->{"V8EnabledPerContext"};
2222     return 0 if RequiresCustomSignature($function);
2223     return 0 if $attrExt->{"V8DoNotCheckSignature"};
2224     return 0 if ($attrExt->{"DoNotCheckSecurity"} && ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow"));
2225     return 0 if $attrExt->{"NotEnumerable"};
2226     return 0 if $attrExt->{"V8ReadOnly"};
2227     return 1;
2228 }
2229
2230 sub GenerateNonStandardFunction
2231 {
2232     my $dataNode = shift;
2233     my $function = shift;
2234
2235     my $interfaceName = $dataNode->name;
2236     my $attrExt = $function->signature->extendedAttributes;
2237     my $name = $function->signature->name;
2238
2239     my $property_attributes = "v8::DontDelete";
2240     if ($attrExt->{"NotEnumerable"}) {
2241         $property_attributes .= " | v8::DontEnum";
2242     }
2243     if ($attrExt->{"V8ReadOnly"}) {
2244         $property_attributes .= " | v8::ReadOnly";
2245     }
2246
2247     my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')";
2248
2249     my $template = "proto";
2250     if ($attrExt->{"V8Unforgeable"}) {
2251         $template = "instance";
2252     }
2253     if ($function->isStatic) {
2254         $template = "desc";
2255     }
2256
2257     my $conditional = "";
2258     if ($attrExt->{"V8EnabledAtRuntime"}) {
2259         # Only call Set()/SetAccessor() if this method should be enabled
2260         my $enable_function = GetRuntimeEnableFunctionName($function->signature);
2261         $conditional = "if (${enable_function}())\n        ";
2262     }
2263     if ($attrExt->{"V8EnabledPerContext"}) {
2264         # Only call Set()/SetAccessor() if this method should be enabled
2265         my $enable_function = GetContextEnableFunction($function->signature);
2266         $conditional = "if (${enable_function}(impl->document()))\n        ";
2267     }
2268
2269     if ($attrExt->{"DoNotCheckSecurity"} &&
2270         ($dataNode->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "DOMWindow")) {
2271         # Mark the accessor as ReadOnly and set it on the proto object so
2272         # it can be shadowed. This is really a hack to make it work.
2273         # There are several sceneria to call into the accessor:
2274         #   1) from the same domain: "window.open":
2275         #      the accessor finds the DOM wrapper in the proto chain;
2276         #   2) from the same domain: "window.__proto__.open":
2277         #      the accessor will NOT find a DOM wrapper in the prototype chain
2278         #   3) from another domain: "window.open":
2279         #      the access find the DOM wrapper in the prototype chain
2280         #   "window.__proto__.open" from another domain will fail when
2281         #   accessing '__proto__'
2282         #
2283         # The solution is very hacky and fragile, it really needs to be replaced
2284         # by a better solution.
2285         $property_attributes .= " | v8::ReadOnly";
2286         push(@implContent, <<END);
2287
2288     // $commentInfo
2289     ${conditional}$template->SetAccessor(v8::String::New("$name"), ${interfaceName}V8Internal::${name}AttrGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes));
2290 END
2291         return;
2292     }
2293
2294     my $signature = "defaultSignature";
2295     if ($attrExt->{"V8DoNotCheckSignature"} || $function->isStatic) {
2296        $signature = "v8::Local<v8::Signature>()";
2297     }
2298
2299     if (RequiresCustomSignature($function)) {
2300         $signature = "${name}Signature";
2301         push(@implContent, "\n    // Custom Signature '$name'\n", CreateCustomSignature($function));
2302     }
2303
2304     # Normal function call is a template
2305     my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
2306
2307     if ($property_attributes eq "v8::DontDelete") {
2308         $property_attributes = "";
2309     } else {
2310         $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)";
2311     }
2312
2313     if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") {
2314         die "This shouldn't happen: Intraface '$interfaceName' $commentInfo\n";
2315     }
2316
2317     my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2318     push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2319
2320     push(@implContent, "    ${conditional}$template->Set(v8::String::New(\"$name\"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes);\n");
2321
2322     push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
2323 }
2324
2325 sub GenerateImplementationIndexer
2326 {
2327     my $dataNode = shift;
2328     my $indexer = shift;
2329     my $interfaceName = $dataNode->name;
2330
2331     # FIXME: Figure out what NumericIndexedGetter is really supposed to do. Right now, it's only set on WebGL-related files.
2332     my $hasCustomSetter = $dataNode->extendedAttributes->{"CustomIndexedSetter"} && !$dataNode->extendedAttributes->{"NumericIndexedGetter"};
2333     my $hasGetter = $dataNode->extendedAttributes->{"IndexedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
2334
2335     # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled,
2336     # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide
2337     # simplistic, mirrored indexer handling in addition to named property handling.
2338     my $isSpecialCase = exists $indexerSpecialCases{$interfaceName};
2339     if ($isSpecialCase) {
2340         $hasGetter = 1;
2341         if ($dataNode->extendedAttributes->{"CustomNamedSetter"}) {
2342             $hasCustomSetter = 1;
2343         }
2344     }
2345
2346     my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode);
2347
2348     # FIXME: Find a way to not have to special-case HTMLOptionsCollection.
2349     if ($interfaceName eq "HTMLOptionsCollection") {
2350         $hasEnumerator = 1;
2351         $hasGetter = 1;
2352     }
2353
2354     if (!$hasGetter) {
2355         return;
2356     }
2357
2358     AddToImplIncludes("V8Collection.h");
2359
2360     if (!$indexer) {
2361         $indexer = $codeGenerator->FindSuperMethod($dataNode, "item");
2362     }
2363
2364     my $indexerType = $indexer ? $indexer->type : 0;
2365
2366     # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563).
2367     if ($interfaceName eq "WebKitCSSKeyframesRule") {
2368         $indexerType = "WebKitCSSKeyframeRule";
2369     }
2370
2371     if ($indexerType && !$hasCustomSetter) {
2372         if ($indexerType eq "DOMString") {
2373             my $conversion = $indexer->extendedAttributes->{"TreatReturnedNullStringAs"};
2374             if ($conversion && $conversion eq "Null") {
2375                 push(@implContent, <<END);
2376     setCollectionStringOrUndefinedIndexedGetter<${interfaceName}>(desc);
2377 END
2378             } else {
2379                 push(@implContent, <<END);
2380     setCollectionStringIndexedGetter<${interfaceName}>(desc);
2381 END
2382             }
2383         } else {
2384             push(@implContent, <<END);
2385     setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc);
2386 END
2387             # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type.
2388             AddToImplIncludes("V8${indexerType}.h");
2389         }
2390
2391         return;
2392     }
2393
2394     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
2395     my $setOn = "Instance";
2396
2397     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
2398     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
2399     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
2400     # on the object.
2401     if ($interfaceName eq "DOMWindow") {
2402         $setOn = "Prototype";
2403         $hasDeleter = 0;
2404     }
2405
2406     push(@implContent, "    desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter");
2407     push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0");
2408     push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment.
2409     push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0");
2410     push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator;
2411     push(@implContent, ");\n");
2412 }
2413
2414 sub GenerateImplementationNamedPropertyGetter
2415 {
2416     my $dataNode = shift;
2417     my $namedPropertyGetter = shift;
2418     my $interfaceName = $dataNode->name;
2419     my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"CustomNamedGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
2420
2421     # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit
2422     # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection).
2423     if ($interfaceName eq "HTMLOptionsCollection") {
2424         $interfaceName = "HTMLCollection";
2425         $hasCustomNamedGetter = 1;
2426     }
2427
2428     if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") {
2429         $hasCustomNamedGetter = 1;
2430     }
2431
2432     if ($interfaceName eq "HTMLDocument") {
2433         $hasCustomNamedGetter = 0;
2434     }
2435
2436     my $hasGetter = $dataNode->extendedAttributes->{"NamedGetter"} || $hasCustomNamedGetter;
2437     if (!$hasGetter) {
2438         return;
2439     }
2440
2441     if (!$namedPropertyGetter) {
2442         $namedPropertyGetter = $codeGenerator->FindSuperMethod($dataNode, "namedItem");
2443     }
2444
2445     if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomNamedGetter) {
2446         AddToImplIncludes("V8Collection.h");
2447         my $type = $namedPropertyGetter->type;
2448         push(@implContent, <<END);
2449     setCollectionNamedGetter<${interfaceName}, ${type}>(desc);
2450 END
2451         return;
2452     }
2453
2454     my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"CustomNamedSetter"};
2455     my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"};
2456     my $hasEnumerator = $dataNode->extendedAttributes->{"CustomEnumerateProperty"};
2457     my $setOn = "Instance";
2458
2459     # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow
2460     # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to
2461     # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set
2462     # on the object.
2463     if ($interfaceName eq "DOMWindow") {
2464         $setOn = "Prototype";
2465         $hasDeleter = 0;
2466         $hasEnumerator = 0;
2467     }
2468
2469     push(@implContent, "    desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, ");
2470     push(@implContent, $hasCustomNamedSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, ");
2471     # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes.
2472     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, ");
2473     push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, ");
2474     push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0");
2475     push(@implContent, ");\n");
2476 }
2477
2478 sub GenerateImplementationCustomCall
2479 {
2480     my $dataNode = shift;
2481     my $interfaceName = $dataNode->name;
2482     my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"};
2483
2484     if ($hasCustomCall) {
2485         push(@implContent, "    desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n");
2486     }
2487 }
2488
2489 sub GenerateImplementationMasqueradesAsUndefined
2490 {
2491     my $dataNode = shift;
2492     if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"})
2493     {
2494         push(@implContent, "    desc->InstanceTemplate()->MarkAsUndetectable();\n");
2495     }
2496 }
2497
2498 sub IsTypedArrayType
2499 {
2500     my $type = shift;
2501     return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView"));
2502     return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array"));
2503     return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array"));
2504     return 1 if (($type eq "Float32Array") or ($type eq "Float64Array"));
2505     return 0;
2506 }
2507
2508
2509 sub GenerateImplementation
2510 {
2511     my $object = shift;
2512     my $dataNode = shift;
2513     my $interfaceName = $dataNode->name;
2514     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($dataNode);
2515     my $className = "V8$interfaceName";
2516     my $implClassName = $interfaceName;
2517
2518     # - Add default header template
2519     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
2520
2521     AddToImplIncludes("RuntimeEnabledFeatures.h");
2522     AddToImplIncludes("ContextFeatures.h");
2523     AddToImplIncludes("V8Proxy.h");
2524     AddToImplIncludes("V8Binding.h");
2525     AddToImplIncludes("V8BindingState.h");
2526     AddToImplIncludes("V8DOMWrapper.h");
2527     AddToImplIncludes("V8IsolatedContext.h");
2528
2529     AddIncludesForType($interfaceName);
2530
2531     my $toActive = $dataNode->extendedAttributes->{"ActiveDOMObject"} ? "${className}::toActiveDOMObject" : "0";
2532     my $domVisitor = NeedsToVisitDOMWrapper($dataNode) ? "${className}::visitDOMWrapper" : "0";
2533
2534     # Find the super descriptor.
2535     my $parentClass = "";
2536     my $parentClassTemplate = "";
2537     foreach (@{$dataNode->parents}) {
2538         my $parent = $codeGenerator->StripModule($_);
2539         if ($parent eq "EventTarget") {
2540             next;
2541         }
2542         AddToImplIncludes("V8${parent}.h");
2543         $parentClass = "V8" . $parent;
2544         $parentClassTemplate = $parentClass . "::GetTemplate()";
2545         last;
2546     }
2547     push(@implContentDecls, "namespace WebCore {\n\n");
2548     my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0";
2549
2550     my $WrapperTypePrototype = $dataNode->isException ? "WrapperTypeErrorPrototype" : "WrapperTypeObjectPrototype";
2551
2552     push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, $toActive, $domVisitor, $parentClassInfo, $WrapperTypePrototype };\n\n");
2553     push(@implContentDecls, "namespace ${interfaceName}V8Internal {\n\n");
2554
2555     push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
2556
2557     my $hasConstructors = 0;
2558     my $hasReplaceable = 0;
2559
2560     # Generate property accessors for attributes.
2561     for (my $index = 0; $index < @{$dataNode->attributes}; $index++) {
2562         my $attribute = @{$dataNode->attributes}[$index];
2563         my $attrType = $attribute->signature->type;
2564
2565         # Generate special code for the constructor attributes.
2566         if ($attrType =~ /Constructor$/) {
2567             if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
2568                 $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
2569                 $hasConstructors = 1;
2570             }
2571             next;
2572         }
2573
2574         if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") {
2575             $attribute->signature->extendedAttributes->{"V8OnProto"} = 1;
2576         }
2577
2578         if ($attrType eq "SerializedScriptValue") {
2579             AddToImplIncludes("SerializedScriptValue.h");
2580         }
2581
2582         # Do not generate accessor if this is a custom attribute.  The
2583         # call will be forwarded to a hand-written accessor
2584         # implementation.
2585         if ($attribute->signature->extendedAttributes->{"Custom"} ||
2586             $attribute->signature->extendedAttributes->{"V8Custom"}) {
2587             next;
2588         }
2589
2590         # Generate the accessor.
2591         if (!($attribute->signature->extendedAttributes->{"CustomGetter"} ||
2592             $attribute->signature->extendedAttributes->{"V8CustomGetter"})) {
2593             GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName);
2594         }
2595
2596         if ($attribute->signature->extendedAttributes->{"Replaceable"}) {
2597             $hasReplaceable = 1;
2598         } elsif (!$attribute->signature->extendedAttributes->{"CustomSetter"} &&
2599             !$attribute->signature->extendedAttributes->{"V8CustomSetter"} &&
2600             $attribute->type !~ /^readonly/ &&
2601             !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) {
2602             GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName);
2603         }
2604     }
2605
2606     if ($hasConstructors) {
2607         GenerateConstructorGetter($dataNode, $implClassName);
2608     }
2609
2610     if ($hasConstructors || $hasReplaceable) {
2611         GenerateReplaceableAttrSetter($dataNode, $implClassName);
2612     }
2613
2614     if (NeedsToVisitDOMWrapper($dataNode)) {
2615         GenerateVisitDOMWrapper($dataNode, $implClassName);
2616     }
2617
2618     my $indexer;
2619     my $namedPropertyGetter;
2620     my @enabledPerContextFunctions;
2621     my @normalFunctions;
2622     # Generate methods for functions.
2623     foreach my $function (@{$dataNode->functions}) {
2624         my $isCustom = $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"};
2625         if (!$isCustom) {
2626             GenerateFunctionCallback($function, $dataNode, $implClassName);
2627             if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) {
2628                 GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName);
2629             }
2630         }
2631
2632         if ($function->signature->name eq "item") {
2633             $indexer = $function->signature;
2634         }
2635
2636         if ($function->signature->name eq "namedItem") {
2637             $namedPropertyGetter = $function->signature;
2638         }
2639
2640         # If the function does not need domain security check, we need to
2641         # generate an access getter that returns different function objects
2642         # for different calling context.
2643         if (($dataNode->extendedAttributes->{"CheckSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckSecurity"}) {
2644             if (!$isCustom || $function->{overloadIndex} == 1) {
2645                 GenerateDomainSafeFunctionGetter($function, $implClassName);
2646             }
2647         }
2648
2649         # Separate out functions that are enabled per context so we can process them specially.
2650         if ($function->signature->extendedAttributes->{"V8EnabledPerContext"}) {
2651             push(@enabledPerContextFunctions, $function);
2652         } else {
2653             push(@normalFunctions, $function);
2654         }
2655     }
2656
2657     # Attributes
2658     my $attributes = $dataNode->attributes;
2659
2660     # For the DOMWindow interface we partition the attributes into the
2661     # ones that disallows shadowing and the rest.
2662     my @disallowsShadowing;
2663     # Also separate out attributes that are enabled at runtime so we can process them specially.
2664     my @enabledAtRuntimeAttributes;
2665     my @enabledPerContextAttributes;
2666     my @normalAttributes;
2667     foreach my $attribute (@$attributes) {
2668
2669         if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8Unforgeable"}) {
2670             push(@disallowsShadowing, $attribute);
2671         } elsif ($attribute->signature->extendedAttributes->{"V8EnabledAtRuntime"}) {
2672             push(@enabledAtRuntimeAttributes, $attribute);
2673         } elsif ($attribute->signature->extendedAttributes->{"V8EnabledPerContext"}) {
2674             push(@enabledPerContextAttributes, $attribute);
2675         } else {
2676             push(@normalAttributes, $attribute);
2677         }
2678     }
2679     $attributes = \@normalAttributes;
2680     # Put the attributes that disallow shadowing on the shadow object.
2681     if (@disallowsShadowing) {
2682         push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n");
2683         GenerateBatchedAttributeData($dataNode, \@disallowsShadowing);
2684         push(@implContent, "};\n\n");
2685     }
2686
2687     my $has_attributes = 0;
2688     if (@$attributes) {
2689         $has_attributes = 1;
2690         push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n");
2691         GenerateBatchedAttributeData($dataNode, $attributes);
2692         push(@implContent, "};\n\n");
2693     }
2694
2695     # Setup table of standard callback functions
2696     my $num_callbacks = 0;
2697     my $has_callbacks = 0;
2698     foreach my $function (@normalFunctions) {
2699         # Only one table entry is needed for overloaded methods:
2700         next if $function->{overloadIndex} > 1;
2701         # Don't put any nonstandard functions into this table:
2702         next if !IsStandardFunction($dataNode, $function);
2703         if (!$has_callbacks) {
2704             $has_callbacks = 1;
2705             push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n");
2706         }
2707         my $name = $function->signature->name;
2708         my $callback = GetFunctionTemplateCallbackName($function, $interfaceName);
2709         my $conditionalString = $codeGenerator->GenerateConditionalString($function->signature);
2710         push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
2711         push(@implContent, <<END);
2712     {"$name", $callback},
2713 END
2714         push(@implContent, "#endif\n") if $conditionalString;
2715         $num_callbacks++;
2716     }
2717     push(@implContent, "};\n\n")  if $has_callbacks;
2718
2719     # Setup constants
2720     my $has_constants = 0;
2721     my @constantsEnabledAtRuntime;
2722     if (@{$dataNode->constants}) {
2723         $has_constants = 1;
2724         push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n");
2725     }
2726     foreach my $constant (@{$dataNode->constants}) {
2727         my $name = $constant->name;
2728         my $value = $constant->value;
2729         my $attrExt = $constant->extendedAttributes;
2730         my $conditional = $attrExt->{"Conditional"};
2731         my $implementedBy = $attrExt->{"ImplementedBy"};
2732         if ($implementedBy) {
2733             AddToImplIncludes("${implementedBy}.h");
2734         }
2735         if ($attrExt->{"V8EnabledAtRuntime"}) {
2736             push(@constantsEnabledAtRuntime, $constant);
2737         } else {
2738             # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl
2739             # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF".  It would be better if we
2740             # handled this here, and converted it to a -1 constant in the c++ output.
2741             if ($conditional) {
2742                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2743                 push(@implContent, "#if ${conditionalString}\n");
2744             }
2745             push(@implContent, <<END);
2746     {"${name}", static_cast<signed int>($value)},
2747 END
2748             push(@implContent, "#endif\n") if $conditional;
2749         }
2750     }
2751     if ($has_constants) {
2752         push(@implContent, "};\n\n");
2753         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
2754     }
2755
2756     push(@implContentDecls, "} // namespace ${interfaceName}V8Internal\n\n");
2757
2758     if ($dataNode->extendedAttributes->{"NamedConstructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
2759         GenerateNamedConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
2760     } elsif ($dataNode->extendedAttributes->{"Constructor"} && !($dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CustomConstructor"})) {
2761         GenerateConstructorCallback($dataNode->constructor, $dataNode, $interfaceName);
2762     } elsif (IsConstructorTemplate($dataNode, "Event")) {
2763         GenerateEventConstructorCallback($dataNode, $interfaceName);
2764     }
2765
2766     my $access_check = "";
2767     if ($dataNode->extendedAttributes->{"CheckSecurity"} && !($interfaceName eq "DOMWindow")) {
2768         $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
2769     }
2770
2771     # For the DOMWindow interface, generate the shadow object template
2772     # configuration method.
2773     if ($implClassName eq "DOMWindow") {
2774         push(@implContent, <<END);
2775 static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ)
2776 {
2777     batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));
2778
2779     // Install a security handler with V8.
2780     templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
2781     templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2782     return templ;
2783 }
2784 END
2785     }
2786
2787     if (!$parentClassTemplate) {
2788         $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()";
2789     }
2790
2791     # Generate the template configuration method
2792     push(@implContent,  <<END);
2793 static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc)
2794 {
2795     desc->ReadOnlyPrototype();
2796
2797     v8::Local<v8::Signature> defaultSignature;
2798 END
2799     if ($dataNode->extendedAttributes->{"V8EnabledAtRuntime"}) {
2800         my $enable_function = GetRuntimeEnableFunctionName($dataNode);
2801         push(@implContent, <<END);
2802     if (!${enable_function}())
2803         defaultSignature = configureTemplate(desc, \"\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, 0, 0, 0, 0);
2804     else
2805 END
2806     }
2807     push(@implContent,  <<END);
2808     defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount,
2809 END
2810     # Set up our attributes if we have them
2811     if ($has_attributes) {
2812         push(@implContent, <<END);
2813         ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs),
2814 END
2815     } else {
2816         push(@implContent, <<END);
2817         0, 0,
2818 END
2819     }
2820
2821     if ($has_callbacks) {
2822         push(@implContent, <<END);
2823         ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks));
2824 END
2825     } else {
2826         push(@implContent, <<END);
2827         0, 0);
2828 END
2829     }
2830     
2831     AddToImplIncludes("wtf/UnusedParam.h");
2832     push(@implContent, <<END);
2833     UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
2834 END
2835
2836     if (IsConstructable($dataNode)) {
2837         push(@implContent, <<END);
2838     desc->SetCallHandler(V8${interfaceName}::constructorCallback);
2839 END
2840     }
2841
2842     if ($access_check or @enabledAtRuntimeAttributes or @normalFunctions or $has_constants) {
2843         push(@implContent,  <<END);
2844     v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
2845     v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate();
2846     UNUSED_PARAM(instance); // In some cases, it will not be used.
2847     UNUSED_PARAM(proto); // In some cases, it will not be used.
2848 END
2849     }
2850
2851     push(@implContent,  "    $access_check\n");
2852
2853     # Setup the enable-at-runtime attrs if we have them
2854     foreach my $runtime_attr (@enabledAtRuntimeAttributes) {
2855         my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature);
2856         my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_attr->signature);
2857         push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2858         push(@implContent, "    if (${enable_function}()) {\n");
2859         push(@implContent, "        static const BatchedAttribute attrData =\\\n");
2860         GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", "    ");
2861         push(@implContent, <<END);
2862         configureAttribute(instance, proto, attrData);
2863     }
2864 END
2865         push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2866     }
2867
2868     # Setup the enable-at-runtime constants if we have them
2869     foreach my $runtime_const (@constantsEnabledAtRuntime) {
2870         my $enable_function = GetRuntimeEnableFunctionName($runtime_const);
2871         my $conditionalString = $codeGenerator->GenerateConditionalString($runtime_const);
2872         my $name = $runtime_const->name;
2873         my $value = $runtime_const->value;
2874         push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2875         push(@implContent, "    if (${enable_function}()) {\n");
2876         push(@implContent, <<END);
2877         static const BatchedConstant constData = {"${name}", static_cast<signed int>(${value})};
2878         batchConfigureConstants(desc, proto, &constData, 1);
2879 END
2880         push(@implContent, "    }\n");
2881         push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2882     }
2883
2884     GenerateImplementationIndexer($dataNode, $indexer);
2885     GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter);
2886     GenerateImplementationCustomCall($dataNode);
2887     GenerateImplementationMasqueradesAsUndefined($dataNode);
2888
2889     # Define our functions with Set() or SetAccessor()
2890     my $total_functions = 0;
2891     foreach my $function (@normalFunctions) {
2892         # Only one accessor is needed for overloaded methods:
2893         next if $function->{overloadIndex} > 1;
2894
2895         $total_functions++;
2896         next if IsStandardFunction($dataNode, $function);
2897         GenerateNonStandardFunction($dataNode, $function);
2898         $num_callbacks++;
2899     }
2900
2901     die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions;
2902
2903     if ($has_constants) {
2904         push(@implContent, <<END);
2905     batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts));
2906 END
2907     }
2908
2909     # Special cases
2910     if ($interfaceName eq "DOMWindow") {
2911         push(@implContent, <<END);
2912
2913     proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2914     desc->SetHiddenPrototype(true);
2915     instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
2916     // Set access check callbacks, but turned off initially.
2917     // When a context is detached from a frame, turn on the access check.
2918     // Turning on checks also invalidates inline caches of the object.
2919     instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
2920 END
2921     }
2922     if ($interfaceName eq "HTMLDocument") {
2923         push(@implContent, <<END);
2924     desc->SetHiddenPrototype(true);
2925 END
2926     }
2927     if ($interfaceName eq "Location") {
2928         push(@implContent, <<END);
2929
2930     // For security reasons, these functions are on the instance instead
2931     // of on the prototype object to ensure that they cannot be overwritten.
2932     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));
2933     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));
2934     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));
2935 END
2936     }
2937
2938     my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName);
2939     push(@implContent, <<END);
2940
2941     // Custom toString template
2942     desc->Set(getToStringName(), getToStringTemplate());
2943     return desc;
2944 }
2945
2946 v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate()
2947 {
2948     V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
2949     V8BindingPerIsolateData::TemplateMap::iterator result = data->rawTemplateMap().find(&info);
2950     if (result != data->rawTemplateMap().end())
2951         return result->second;
2952
2953     v8::HandleScope handleScope;
2954     v8::Persistent<v8::FunctionTemplate> templ = createRawTemplate();
2955     data->rawTemplateMap().add(&info, templ);
2956     return templ;
2957 }
2958
2959 v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()
2960 {
2961     V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
2962     V8BindingPerIsolateData::TemplateMap::iterator result = data->templateMap().find(&info);
2963     if (result != data->templateMap().end())
2964         return result->second;
2965
2966     v8::HandleScope handleScope;
2967     v8::Persistent<v8::FunctionTemplate> templ =
2968         Configure${className}Template(GetRawTemplate());
2969     data->templateMap().add(&info, templ);
2970     return templ;
2971 }
2972
2973 bool ${className}::HasInstance(v8::Handle<v8::Value> value)
2974 {
2975     return GetRawTemplate()->HasInstance(value);
2976 }
2977
2978 END
2979
2980     if (@enabledPerContextAttributes or @enabledPerContextFunctions) {
2981         push(@implContent, <<END);
2982 void ${className}::installPerContextProperties(v8::Handle<v8::Object> instance, ${implClassName}* impl)
2983 {
2984     v8::Local<v8::Object> proto = v8::Local<v8::Object>::Cast(instance->GetPrototype());
2985     // When building QtWebkit with V8 this variable is unused when none of the features are enabled.
2986     UNUSED_PARAM(proto);
2987 END
2988
2989         if (@enabledPerContextAttributes) {
2990             # Setup the enable-by-settings attrs if we have them
2991             foreach my $runtimeAttr (@enabledPerContextAttributes) {
2992                 my $enableFunction = GetContextEnableFunction($runtimeAttr->signature);
2993                 my $conditionalString = $codeGenerator->GenerateConditionalString($runtimeAttr->signature);
2994                 push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
2995                 push(@implContent, "    if (${enableFunction}(impl->document())) {\n");
2996                 push(@implContent, "        static const BatchedAttribute attrData =\\\n");
2997                 GenerateSingleBatchedAttribute($interfaceName, $runtimeAttr, ";", "    ");
2998                 push(@implContent, <<END);
2999         configureAttribute(instance, proto, attrData);
3000 END
3001                 push(@implContent, "    }\n");
3002                 push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
3003             }
3004         }
3005
3006         # Setup the enable-by-settings functions if we have them
3007         if (@enabledPerContextFunctions) {
3008             push(@implContent,  <<END);
3009     v8::Local<v8::Signature> defaultSignature = v8::Signature::New(GetTemplate());
3010     UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.
3011 END
3012
3013             foreach my $runtimeFunc (@enabledPerContextFunctions) {
3014                 my $enableFunction = GetContextEnableFunction($runtimeFunc->signature);
3015                 my $conditionalString = $codeGenerator->GenerateConditionalString($runtimeFunc->signature);
3016                 push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString;
3017                 push(@implContent, "    if (${enableFunction}(impl->document())) {\n");
3018                 my $name = $runtimeFunc->signature->name;
3019                 my $callback = GetFunctionTemplateCallbackName($runtimeFunc, $interfaceName);
3020                 push(@implContent, <<END);
3021         proto->Set(v8::String::New("${name}"), v8::FunctionTemplate::New(${callback}, v8::Handle<v8::Value>(), defaultSignature)->GetFunction());
3022 END
3023                 push(@implContent, "    }\n");
3024                 push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
3025             }
3026         }
3027
3028         push(@implContent, <<END);
3029 }
3030 END
3031     }
3032
3033     if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
3034         # MessagePort is handled like an active dom object even though it doesn't inherit
3035         # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject.
3036         my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)";
3037         push(@implContent, <<END);
3038 ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object)
3039 {
3040     return ${returnValue};
3041 }      
3042 END
3043     }
3044
3045     if ($implClassName eq "DOMWindow") {
3046         push(@implContent, <<END);
3047 v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate()
3048 {
3049     static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache;
3050     if (V8DOMWindowShadowObjectCache.IsEmpty()) {
3051         V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New());
3052         ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache);
3053     }
3054     return V8DOMWindowShadowObjectCache;
3055 }
3056 END
3057     }
3058
3059     GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType);
3060
3061     push(@implContent, <<END);
3062
3063 void ${className}::derefObject(void* object)
3064 {
3065     static_cast<${nativeType}*>(object)->deref();
3066 }
3067
3068 } // namespace WebCore
3069 END
3070
3071     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3072     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
3073     
3074     # We've already added the header for this file in implFixedHeader, so remove
3075     # it from implIncludes to ensure we don't #include it twice.
3076     delete $implIncludes{"${className}.h"};
3077 }
3078
3079 sub GenerateHeaderContentHeader
3080 {
3081     my $dataNode = shift;
3082     my $className = "V8" . $dataNode->name;
3083     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3084
3085     my @headerContentHeader = split("\r", $headerTemplate);
3086
3087     push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString;
3088     push(@headerContentHeader, "\n#ifndef ${className}" . "_h");
3089     push(@headerContentHeader, "\n#define ${className}" . "_h\n\n");
3090     return @headerContentHeader;
3091 }
3092
3093 sub GenerateImplementationContentHeader
3094 {
3095     my $dataNode = shift;
3096     my $className = "V8" . $dataNode->name;
3097     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3098
3099     my @implContentHeader = split("\r", $headerTemplate);
3100
3101     push(@implContentHeader, "\n#include \"config.h\"\n");
3102     push(@implContentHeader, "#include \"${className}.h\"\n\n");
3103     push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
3104     return @implContentHeader;
3105 }
3106
3107 sub GenerateCallbackHeader
3108 {
3109     my $object = shift;
3110     my $dataNode = shift;
3111
3112     my $interfaceName = $dataNode->name;
3113     my $className = "V8$interfaceName";
3114
3115
3116     # - Add default header template
3117     push(@headerContent, GenerateHeaderContentHeader($dataNode));
3118
3119     my @unsortedIncludes = ();
3120     push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\"");
3121     push(@unsortedIncludes, "#include \"$interfaceName.h\"");
3122     push(@unsortedIncludes, "#include \"WorldContextHandle.h\"");
3123     push(@unsortedIncludes, "#include <v8.h>");
3124     push(@unsortedIncludes, "#include <wtf/Forward.h>");
3125     push(@headerContent, join("\n", sort @unsortedIncludes));
3126     
3127     push(@headerContent, "\n\nnamespace WebCore {\n\n");
3128     push(@headerContent, "class ScriptExecutionContext;\n\n");
3129     push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
3130
3131     push(@headerContent, <<END);
3132 public:
3133     static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context)
3134     {
3135         ASSERT(value->IsObject());
3136         ASSERT(context);
3137         return adoptRef(new ${className}(value->ToObject(), context));
3138     }
3139
3140     virtual ~${className}();
3141
3142 END
3143
3144     # Functions
3145     my $numFunctions = @{$dataNode->functions};
3146     if ($numFunctions > 0) {
3147         push(@headerContent, "    // Functions\n");
3148         foreach my $function (@{$dataNode->functions}) {
3149             my @params = @{$function->parameters};
3150             if (!$function->signature->extendedAttributes->{"Custom"} &&
3151                 !(GetNativeType($function->signature->type) eq "bool")) {
3152                     push(@headerContent, "    COMPILE_ASSERT(false)");
3153             }
3154
3155             push(@headerContent, "    virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "(");
3156
3157             my @args = ();
3158             foreach my $param (@params) {
3159                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name);
3160             }
3161             push(@headerContent, join(", ", @args));
3162             push(@headerContent, ");\n");
3163         }
3164     }
3165
3166     push(@headerContent, <<END);
3167
3168 private:
3169     ${className}(v8::Local<v8::Object>, ScriptExecutionContext*);
3170
3171     v8::Persistent<v8::Object> m_callback;
3172     WorldContextHandle m_worldContext;
3173 };
3174
3175 END
3176
3177     push(@headerContent, "}\n\n");
3178     push(@headerContent, "#endif // $className" . "_h\n\n");
3179
3180     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3181     push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString;
3182 }
3183
3184 sub GenerateCallbackImplementation
3185 {
3186     my $object = shift;
3187     my $dataNode = shift;
3188     my $interfaceName = $dataNode->name;
3189     my $className = "V8$interfaceName";
3190
3191     # - Add default header template
3192     push(@implFixedHeader, GenerateImplementationContentHeader($dataNode));
3193          
3194     AddToImplIncludes("ScriptExecutionContext.h");
3195     AddToImplIncludes("V8Binding.h");
3196     AddToImplIncludes("V8CustomVoidCallback.h");
3197     AddToImplIncludes("V8Proxy.h");
3198
3199     push(@implContent, "#include <wtf/Assertions.h>\n\n");
3200     push(@implContent, "namespace WebCore {\n\n");
3201     push(@implContent, <<END);
3202 ${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context)
3203     : ActiveDOMCallback(context)
3204     , m_callback(v8::Persistent<v8::Object>::New(callback))
3205     , m_worldContext(UseCurrentWorld)
3206 {
3207 }
3208
3209 ${className}::~${className}()
3210 {
3211     m_callback.Dispose();
3212 }
3213
3214 END
3215
3216     # Functions
3217     my $numFunctions = @{$dataNode->functions};
3218     if ($numFunctions > 0) {
3219         push(@implContent, "// Functions\n");
3220         foreach my $function (@{$dataNode->functions}) {
3221             my @params = @{$function->parameters};
3222             if ($function->signature->extendedAttributes->{"Custom"} ||
3223                 !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) {
3224                 next;
3225             }
3226
3227             AddIncludesForType($function->signature->type);
3228             push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "(");
3229
3230             my @args = ();
3231             my @argsCheck = ();
3232             my $thisType = $function->signature->extendedAttributes->{"PassThisToCallback"};
3233             foreach my $param (@params) {
3234                 my $paramName = $param->name;
3235                 AddIncludesForType($param->type);
3236                 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $paramName);
3237                 if ($thisType and $thisType eq $param->type) {
3238                     push(@argsCheck, <<END);
3239     ASSERT(${paramName});
3240
3241 END
3242                 }
3243             }
3244             push(@implContent, join(", ", @args));
3245
3246             push(@implContent, ")\n");
3247             push(@implContent, "{\n");
3248             push(@implContent, @argsCheck) if @argsCheck;
3249             push(@implContent, "    if (!canInvokeCallback())\n");
3250             push(@implContent, "        return true;\n\n");
3251             push(@implContent, "    v8::HandleScope handleScope;\n\n");
3252             push(@implContent, "    v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n");
3253             push(@implContent, "    if (v8Context.IsEmpty())\n");
3254             push(@implContent, "        return true;\n\n");
3255             push(@implContent, "    v8::Context::Scope scope(v8Context);\n\n");
3256
3257             @args = ();
3258             foreach my $param (@params) {
3259                 my $paramName = $param->name;
3260                 push(@implContent, "    v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName) . ";\n");
3261                 push(@implContent, "    if (${paramName}Handle.IsEmpty()) {\n");
3262                 push(@implContent, "        if (!isScriptControllerTerminating())\n");
3263                 push(@implContent, "            CRASH();\n");
3264                 push(@implContent, "        return true;\n");
3265                 push(@implContent, "    }\n");
3266                 push(@args, "        ${paramName}Handle");
3267             }
3268
3269             if (scalar(@args) > 0) {
3270                 push(@implContent, "\n    v8::Handle<v8::Value> argv[] = {\n");
3271                 push(@implContent, join(",\n", @args));
3272                 push(@implContent, "\n    };\n\n");
3273             } else {
3274                 push(@implContent, "\n    v8::Handle<v8::Value> *argv = 0;\n\n");
3275             }
3276             push(@implContent, "    bool callbackReturnValue = false;\n");
3277             if ($thisType) {
3278                 foreach my $param (@params) {
3279                     next if $param->type ne $thisType;
3280                     my $paramName = $param->name;
3281                     push(@implContent, "    return !invokeCallback(m_callback, v8::Handle<v8::Object>::Cast(${paramName}Handle), " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
3282                     last;
3283                 }
3284             } else {
3285                 push(@implContent, "    return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n");
3286             }
3287             push(@implContent, "}\n");
3288         }
3289     }
3290
3291     push(@implContent, "\n} // namespace WebCore\n\n");
3292
3293     my $conditionalString = $codeGenerator->GenerateConditionalString($dataNode);
3294     push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString;
3295 }
3296
3297 sub GenerateToV8Converters
3298 {
3299     my $dataNode = shift;
3300     my $interfaceName = shift;
3301     my $className = shift;
3302     my $nativeType = shift;
3303
3304     my $domMapName = GetDomMapName($dataNode, $interfaceName);
3305     my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : "";
3306     my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : "";
3307     my $wrapSlowArgumentType = GetPassRefPtrType($nativeType);
3308
3309     push(@implContent, <<END);
3310
3311 v8::Handle<v8::Object> ${className}::wrapSlow(${wrapSlowArgumentType} impl, v8::Isolate* isolate)
3312 {
3313     v8::Handle<v8::Object> wrapper;
3314 END
3315
3316     my $proxyInit;
3317     if (IsNodeSubType($dataNode)) {
3318         $proxyInit = "V8Proxy::retrieve(impl->document()->frame())";
3319         # DocumentType nodes are the only nodes that may have a NULL document.
3320         if ($interfaceName eq "DocumentType") {
3321             $proxyInit = "impl->document() ? $proxyInit : 0";
3322         }
3323     } else {
3324         $proxyInit = "0";
3325     }
3326     push(@implContent, <<END);
3327     V8Proxy* proxy = $proxyInit;
3328 END
3329
3330     if (IsSubType($dataNode, "Document")) {
3331         push(@implContent, <<END);
3332     if (proxy && proxy->windowShell()->context().IsEmpty() && proxy->windowShell()->initContextIfNeeded()) {
3333         // initContextIfNeeded may have created a wrapper for the object, retry from the start.
3334         return ${className}::wrap(impl.get(), isolate);
3335     }
3336 END
3337     }
3338
3339     # FIXME: We need a better way of recovering the correct prototype chain
3340     # for every sort of object. For now, we special-case cross-origin visible
3341     # objects (i.e., those with CheckSecurity).
3342     if (IsVisibleAcrossOrigins($dataNode)) {
3343         push(@implContent, <<END);
3344     if (impl->frame()) {
3345         proxy = V8Proxy::retrieve(impl->frame());
3346         if (proxy)
3347             proxy->windowShell()->initContextIfNeeded();
3348     }
3349 END
3350     }
3351
3352     if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
3353         push(@implContent, <<END);
3354
3355     // Enter the node's context and create the wrapper in that context.
3356     v8::Handle<v8::Context> context;
3357     if (proxy && !proxy->matchesCurrentContext()) {
3358         // For performance, we enter the context only if the currently running context
3359         // is different from the context that we are about to enter.
3360         context = proxy->context();
3361         if (!context.IsEmpty())
3362             context->Enter();
3363     }
3364 END
3365     }
3366
3367     push(@implContent, <<END);
3368     wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl.get());
3369 END
3370     if (IsNodeSubType($dataNode) || IsVisibleAcrossOrigins($dataNode)) {
3371         push(@implContent, <<END);
3372     // Exit the node's context if it was entered.
3373     if (!context.IsEmpty())
3374         context->Exit();
3375 END
3376     }
3377
3378     push(@implContent, <<END);
3379     if (UNLIKELY(wrapper.IsEmpty()))
3380         return wrapper;
3381 END
3382
3383     my $hasEnabledPerContextFunctions = 0;
3384     foreach my $function (@{$dataNode->functions}) {
3385         if ($function->signature->extendedAttributes->{"V8EnabledPerContext"}) {
3386             $hasEnabledPerContextFunctions = 1;
3387         }
3388     }
3389     if ($hasEnabledPerContextFunctions) {
3390         push(@implContent, <<END);
3391     installPerContextProperties(wrapper, impl.get());
3392 END
3393     }
3394
3395     push(@implContent, <<END);
3396
3397     v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);
3398
3399     if (!hasDependentLifetime)
3400         wrapperHandle.MarkIndependent();
3401 END
3402     if (IsNodeSubType($dataNode)) {
3403         push(@implContent, <<END);
3404     wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
3405 END
3406     }
3407     push(@implContent, <<END);
3408     V8DOMWrapper::setJSWrapperFor${domMapName}(impl, wrapperHandle, isolate);
3409     return wrapper;
3410 }
3411 END
3412 }
3413
3414 sub GetDomMapFunction
3415 {
3416     my $dataNode = shift;
3417     my $interfaceName = shift;
3418     my $getIsolate = shift;
3419
3420     return "get" . GetDomMapName($dataNode, $interfaceName) . "Map(" . $getIsolate . ")";
3421 }
3422
3423 sub GetDomMapName
3424 {
3425     my $dataNode = shift;
3426     my $type = shift;
3427
3428     return "ActiveDOMNode" if (IsNodeSubType($dataNode) && $dataNode->extendedAttributes->{"ActiveDOMObject"});
3429     return "DOMNode" if IsNodeSubType($dataNode);
3430     return "ActiveDOMObject" if $dataNode->extendedAttributes->{"ActiveDOMObject"};
3431     return "DOMObject";
3432 }
3433
3434 sub GetNativeTypeForConversions
3435 {
3436     my $dataNode = shift;
3437     my $type = shift;
3438
3439     $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); 
3440     return $type;
3441 }
3442
3443 sub GenerateFunctionCallString()
3444 {
3445     my $function = shift;
3446     my $numberOfParameters = shift;
3447     my $indent = shift;
3448     my $implClassName = shift;
3449     my %replacements = @_;
3450
3451     my $name = $function->signature->name;
3452     my $returnType = GetTypeFromSignature($function->signature);
3453     my $nativeReturnType = GetNativeType($returnType, 0);
3454     my $result = "";
3455
3456     my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/);
3457     $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType;
3458
3459     if ($function->signature->extendedAttributes->{"ImplementedAs"}) {
3460         $name = $function->signature->extendedAttributes->{"ImplementedAs"};
3461     }
3462
3463     my $index = 0;
3464     my $hasScriptState = 0;
3465
3466     my @arguments;
3467     my $functionName;
3468     my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
3469     if ($implementedBy) {
3470         AddToImplIncludes("${implementedBy}.h");
3471         unshift(@arguments, "imp") if !$function->isStatic;
3472         $functionName = "${implementedBy}::${name}";
3473     } elsif ($function->isStatic) {
3474         $functionName = "${implClassName}::${name}";
3475     } else {
3476         $functionName = "imp->${name}";
3477     }
3478
3479     my $callWith = $function->signature->extendedAttributes->{"CallWith"};
3480     my @callWithOutput = ();
3481     my @callWithArgs = GenerateCallWith($callWith, \@callWithOutput, $indent, 0, 1, $function);
3482     $result .= join("", @callWithOutput);
3483     unshift(@arguments, @callWithArgs);
3484     $index += @callWithArgs;
3485     $numberOfParameters += @callWithArgs;
3486
3487     foreach my $parameter (@{$function->parameters}) {
3488         if ($index eq $numberOfParameters) {
3489             last;
3490         }
3491         my $paramName = $parameter->name;
3492         my $paramType = $parameter->type;
3493
3494         if ($replacements{$paramName}) {
3495             push @arguments, $replacements{$paramName};
3496         } elsif ($parameter->type eq "IDBKey" || $parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") {
3497             push @arguments, "$paramName.get()";
3498         } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) {
3499             push @arguments, "$paramName->propertyReference()";
3500             $result .= $indent . "if (!$paramName)\n";
3501             $result .= $indent . "    return V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR, args.GetIsolate());\n";
3502         } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") {
3503             push @arguments, "$paramName.get()";
3504         } else {
3505             push @arguments, $paramName;
3506         }
3507         $index++;
3508     }
3509
3510     if (@{$function->raisesExceptions}) {
3511         push @arguments, "ec";
3512     }
3513
3514     my $functionString = "$functionName(" . join(", ", @arguments) . ")";
3515
3516     my $return = "result";
3517     my $returnIsRef = IsRefPtrType($returnType);
3518
3519     if ($returnType eq "void") {
3520         $result .= $indent . "$functionString;\n";
3521     } elsif ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState") or @{$function->raisesExceptions}) {
3522         $result .= $indent . $nativeReturnType . " result = $functionString;\n";
3523     } else {
3524         # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary
3525         $return = $functionString;
3526         $returnIsRef = 0;
3527
3528         if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) {
3529             $return = "WTF::getPtr(" . $return . ")";
3530         }
3531     }
3532
3533     if (@{$function->raisesExceptions}) {
3534         $result .= $indent . "if (UNLIKELY(ec))\n";
3535         $result .= $indent . "    goto fail;\n";
3536     }
3537
3538     if ($codeGenerator->ExtendedAttributeContains($callWith, "ScriptState")) {
3539         $result .= $indent . "if (state.hadException())\n";
3540         $result .= $indent . "    return throwError(state.exception(), args.GetIsolate());\n"
3541     }
3542
3543     if ($isSVGTearOffType) {
3544         AddToImplIncludes("V8$returnType.h");
3545         AddToImplIncludes("SVGPropertyTearOff.h");
3546         my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType);
3547         $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)), args.GetIsolate());\n";
3548         return $result;
3549     }
3550
3551     # If the implementing class is a POD type, commit changes
3552     if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) {
3553         $result .= $indent . "wrapper->commitChange();\n";
3554     }
3555
3556     $return .= ".release()" if ($returnIsRef);
3557     $result .= $indent . ReturnNativeToJSValue($function->signature, $return, "args.GetIsolate()") . ";\n";
3558
3559     return $result;
3560 }
3561
3562
3563 sub GetTypeFromSignature
3564 {
3565     my $signature = shift;
3566
3567     return $codeGenerator->StripModule($signature->type);
3568 }
3569
3570
3571 sub GetNativeTypeFromSignature
3572 {
3573     my $signature = shift;
3574     my $parameterIndex = shift;
3575
3576     my $type = GetTypeFromSignature($signature);
3577
3578     if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
3579         # Special-case index arguments because we need to check that they aren't < 0.
3580         return "int";
3581     }
3582
3583     $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0);
3584
3585     if ($parameterIndex >= 0 && $type eq "V8Parameter") {
3586         # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString],
3587         # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString].
3588         my $mode = "";
3589         if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) {
3590             $mode = "WithUndefinedOrNullCheck";
3591         } elsif (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "NullString") or $signature->extendedAttributes->{"Reflect"}) {
3592             $mode = "WithNullCheck";
3593         }
3594         # FIXME: Add the case for 'elsif ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'.
3595         $type .= "<$mode>";
3596     }
3597
3598     return $type;
3599 }
3600
3601 sub IsRefPtrType
3602 {
3603     my $type = shift;
3604
3605     return 0 if $type eq "boolean";
3606     return 0 if $type eq "float";
3607     return 0 if $type eq "int";
3608     return 0 if $type eq "Date";
3609     return 0 if $type eq "DOMString";
3610     return 0 if $type eq "double";
3611     return 0 if $type eq "short";
3612     return 0 if $type eq "long";
3613     return 0 if $type eq "unsigned";
3614     return 0 if $type eq "unsigned long";
3615     return 0 if $type eq "unsigned short";
3616
3617     return 1;
3618 }
3619
3620 sub GetNativeType
3621 {
3622     my $type = shift;
3623     my $isParameter = shift;
3624
3625     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
3626     if ($svgNativeType) {
3627         if ($svgNativeType =~ /List$/) {
3628             return "${svgNativeType}*";
3629         } else {
3630             return "RefPtr<${svgNativeType} >";
3631         }
3632     }
3633
3634     my $sequenceType = $codeGenerator->GetSequenceType($type);
3635     return "Vector<${sequenceType}>" if $sequenceType;
3636
3637     if ($type eq "float" or $type eq "double") {
3638         return $type;
3639     }
3640
3641     return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter;
3642     return "int" if $type eq "int";
3643     return "int" if $type eq "short" or $type eq "unsigned short";
3644     return "unsigned" if $type eq "unsigned long";
3645     return "int" if $type eq "long";
3646     return "long long" if $type eq "long long";
3647     return "unsigned long long" if $type eq "unsigned long long";
3648     return "bool" if $type eq "boolean";
3649     return "String" if $type eq "DOMString";
3650     return "Range::CompareHow" if $type eq "CompareHow";
3651     return "DOMTimeStamp" if $type eq "DOMTimeStamp";
3652     return "unsigned" if $type eq "unsigned int";
3653     return "Node*" if $type eq "EventTarget" and $isParameter;
3654     return "double" if $type eq "Date";
3655     return "ScriptValue" if $type eq "DOMObject";
3656     return "Dictionary" if $type eq "Dictionary";
3657
3658     return "String" if $type eq "DOMUserData";  # FIXME: Temporary hack?
3659
3660     # temporary hack
3661     return "RefPtr<NodeFilter>" if $type eq "NodeFilter";
3662
3663     return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue";
3664
3665     return "RefPtr<IDBKey>" if $type eq "IDBKey";
3666
3667     # necessary as resolvers could be constructed on fly.
3668     return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver";
3669
3670     return "RefPtr<DOMStringList>" if $type eq "DOMString[]";
3671     return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter;
3672
3673     return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener";
3674
3675     # FIXME: Support T[], T[]?, sequence<T> generically
3676     return "RefPtr<DOMStringList>" if $type eq "DOMStringList";
3677
3678     # Default, assume native type is a pointer with same type name as idl type
3679     return "${type}*";
3680 }
3681
3682 sub GetNativeTypeForCallbacks
3683 {
3684     my $type = shift;
3685     return "const String&" if $type eq "DOMString";
3686     return "SerializedScriptValue*" if $type eq "SerializedScriptValue";
3687
3688     # Callbacks use raw pointers, so pass isParameter = 1
3689     return GetNativeType($type, 1);
3690 }
3691
3692 sub TranslateParameter
3693 {
3694     my $signature = shift;
3695
3696     # The IDL uses some pseudo-types which don't really exist.
3697     if ($signature->type eq "TimeoutHandler") {
3698       $signature->type("DOMString");
3699     }
3700 }
3701
3702 sub TypeCanFailConversion
3703 {
3704     my $signature = shift;
3705
3706     my $type = GetTypeFromSignature($signature);
3707
3708     AddToImplIncludes("ExceptionCode.h") if $type eq "Attr";
3709     return 1 if $type eq "Attr";
3710     return 1 if $type eq "VoidCallback";
3711     return 0;
3712 }
3713
3714 sub JSValueToNative
3715 {
3716     my $signature = shift;
3717     my $value = shift;
3718     my $getIsolate = shift;
3719
3720     my $type = GetTypeFromSignature($signature);
3721
3722     return "$value" if $type eq "JSObject";
3723     return "$value->BooleanValue()" if $type eq "boolean";
3724     return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double";
3725
3726     return "toInt32($value)" if $type eq "long" or $type eq "short";
3727     return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short";
3728     return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long";
3729     return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow";
3730     return "toWebCoreDate($value)" if $type eq "Date";
3731     return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList";
3732     # FIXME: Add proper support for T[], T[]? and sequence<T>.
3733     return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMString[]";
3734
3735     if ($type eq "DOMString" or $type eq "DOMUserData") {
3736         return $value;
3737     }
3738
3739     if ($type eq "SerializedScriptValue") {
3740         AddToImplIncludes("SerializedScriptValue.h");
3741         return "SerializedScriptValue::create($value, $getIsolate)";
3742     }
3743
3744     if ($type eq "IDBKey") {
3745         AddToImplIncludes("IDBBindingUtilities.h");
3746         AddToImplIncludes("IDBKey.h");
3747         return "createIDBKeyFromValue($value)";
3748     }
3749
3750     if ($type eq "Dictionary") {
3751         AddToImplIncludes("Dictionary.h");
3752         return $value;
3753     }
3754
3755     if ($type eq "DOMObject") {
3756         AddToImplIncludes("ScriptValue.h");
3757         return "ScriptValue($value)";
3758     }
3759
3760     if ($type eq "NodeFilter") {
3761         return "V8DOMWrapper::wrapNativeNodeFilter($value)";
3762     }
3763
3764     if ($type eq "MediaQueryListListener") {
3765         AddToImplIncludes("MediaQueryListListener.h");
3766         return "MediaQueryListListener::create(" . $value . ")";
3767     }
3768
3769     # Default, assume autogenerated type conversion routines
3770     if ($type eq "EventTarget") {
3771         AddToImplIncludes("V8Node.h");
3772
3773         # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget.
3774         return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3775     }
3776
3777     if ($type eq "XPathNSResolver") {
3778         return "V8DOMWrapper::getXPathNSResolver($value)";
3779     }
3780
3781     my $arrayType = $codeGenerator->GetArrayType($type);
3782     if ($arrayType) {
3783         return "toNativeArray<$arrayType>($value)";
3784     }
3785
3786     my $sequenceType = $codeGenerator->GetSequenceType($type);
3787     if ($sequenceType) {
3788         return "toNativeArray<$sequenceType>($value)";
3789     }
3790
3791     AddIncludesForType($type);
3792
3793     if (IsDOMNodeType($type)) {
3794         AddToImplIncludes("V8${type}.h");
3795
3796         # Perform type checks on the parameter, if it is expected Node type,
3797         # return NULL.
3798         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3799     } else {
3800         AddToImplIncludes("V8$type.h");
3801
3802         # Perform type checks on the parameter, if it is expected Node type,
3803         # return NULL.
3804         return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0";
3805     }
3806 }
3807
3808 sub GetV8HeaderName
3809 {
3810     my $type = shift;
3811     return "V8Event.h" if $type eq "DOMTimeStamp";
3812     return "EventListener.h" if $type eq "EventListener";
3813     return "EventTarget.h" if $type eq "EventTarget";
3814     return "SerializedScriptValue.h" if $type eq "SerializedScriptValue";
3815     return "ScriptValue.h" if $type eq "DOMObject";
3816     return "V8DOMStringList.h" if $type eq "DOMString[]";
3817     return "V8${type}.h";
3818 }
3819
3820 sub CreateCustomSignature
3821 {
3822     my $function = shift;
3823     my $count = @{$function->parameters};
3824     my $name = $function->signature->name;
3825     my $result = "    const int ${name}Argc = ${count};\n" .
3826       "    v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { ";
3827     my $first = 1;
3828     foreach my $parameter (@{$function->parameters}) {
3829         if ($first) { $first = 0; }
3830         else { $result .= ", "; }
3831         if (IsWrapperType($parameter->type)) {
3832             if ($parameter->type eq "XPathNSResolver") {
3833                 # Special case for XPathNSResolver.  All other browsers accepts a callable,
3834                 # so, even though it's against IDL, accept objects here.
3835                 $result .= "v8::Handle<v8::FunctionTemplate>()";
3836             } else {
3837                 my $type = $parameter->type;
3838                 my $sequenceType = $codeGenerator->GetSequenceType($type);
3839                 if ($sequenceType) {
3840                     if ($codeGenerator->SkipIncludeHeader($sequenceType)) {
3841                         $result .= "v8::Handle<v8::FunctionTemplate>()";
3842                         next;
3843                     }
3844                     AddToImplIncludes("$sequenceType.h");
3845                 } else {
3846                     my $header = GetV8HeaderName($type);
3847                     AddToImplIncludes($header);
3848                 }
3849                 $result .= "V8${type}::GetRawTemplate()";
3850             }
3851         } else {
3852             $result .= "v8::Handle<v8::FunctionTemplate>()";
3853         }
3854     }
3855     $result .= " };\n";
3856     $result .= "    v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n";
3857     return $result;
3858 }
3859
3860
3861 sub RequiresCustomSignature
3862 {
3863     my $function = shift;
3864     # No signature needed for Custom function
3865     if ($function->signature->extendedAttributes->{"Custom"} ||
3866         $function->signature->extendedAttributes->{"V8Custom"}) {
3867         return 0;
3868     }
3869     # No signature needed for overloaded function
3870     if (@{$function->{overloads}} > 1) {
3871         return 0;
3872     }
3873     if ($function->isStatic) {
3874         return 0;
3875     }
3876     # Type checking is performed in the generated code
3877     if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
3878       return 0;
3879     }
3880     foreach my $parameter (@{$function->parameters}) {
3881         my $optional = $parameter->extendedAttributes->{"Optional"};
3882         if (($optional && $optional ne "DefaultIsUndefined" && $optional ne "DefaultIsNullString") || $parameter->extendedAttributes->{"Callback"}) {
3883             return 0;
3884         }
3885     }
3886
3887     foreach my $parameter (@{$function->parameters}) {
3888         if (IsWrapperType($parameter->type)) {
3889             return 1;
3890         }
3891     }
3892     return 0;
3893 }
3894
3895
3896 my %non_wrapper_types = (
3897     'CompareHow' => 1,
3898     'DOMObject' => 1,
3899     'DOMString' => 1,
3900     'DOMString[]' => 1,
3901     'DOMTimeStamp' => 1,
3902     'Date' => 1,
3903     'Dictionary' => 1,
3904     'EventListener' => 1,
3905     'EventTarget' => 1,
3906     'IDBKey' => 1,
3907     'JSObject' => 1,
3908     'MediaQueryListListener' => 1,
3909     'NodeFilter' => 1,
3910     'SerializedScriptValue' => 1,
3911     'boolean' => 1,
3912     'double' => 1,
3913     'float' => 1,
3914     'int' => 1,
3915     'long long' => 1,
3916     'long' => 1,
3917     'short' => 1,
3918     'unsigned int' => 1,
3919     'unsigned long long' => 1,
3920     'unsigned long' => 1,
3921     'unsigned short' => 1
3922 );
3923
3924
3925 sub IsWrapperType
3926 {
3927     my $type = $codeGenerator->StripModule(shift);
3928     return !($non_wrapper_types{$type});
3929 }
3930
3931 sub IsArrayType
3932 {
3933     my $type = $codeGenerator->StripModule(shift);
3934     # FIXME: Add proper support for T[], T[]?, sequence<T>.
3935     return $type =~ m/\[\]$/;
3936 }
3937
3938 sub IsDOMNodeType
3939 {
3940     my $type = shift;
3941
3942     return 1 if $type eq 'Attr';
3943     return 1 if $type eq 'CDATASection';
3944     return 1 if $type eq 'Comment';
3945     return 1 if $type eq 'Document';
3946     return 1 if $type eq 'DocumentFragment';
3947     return 1 if $type eq 'DocumentType';
3948     return 1 if $type eq 'Element';
3949     return 1 if $type eq 'EntityReference';
3950     return 1 if $type eq 'HTMLCanvasElement';
3951     return 1 if $type eq 'HTMLDocument';
3952     return 1 if $type eq 'HTMLElement';
3953     return 1 if $type eq 'HTMLUnknownElement';
3954     return 1 if $type eq 'HTMLFormElement';
3955     return 1 if $type eq 'HTMLTableCaptionElement';
3956     return 1 if $type eq 'HTMLTableSectionElement';
3957     return 1 if $type eq 'Node';
3958     return 1 if $type eq 'ProcessingInstruction';
3959     return 1 if $type eq 'SVGElement';
3960     return 1 if $type eq 'SVGDocument';
3961     return 1 if $type eq 'SVGSVGElement';
3962     return 1 if $type eq 'SVGUseElement';
3963     return 1 if $type eq 'Text';
3964
3965     return 0;
3966 }
3967
3968
3969 sub NativeToJSValue
3970 {
3971     my $signature = shift;
3972     my $value = shift;
3973     my $getIsolate = shift;
3974     my $getIsolateArg = $getIsolate ? ", $getIsolate" : "";
3975     my $type = GetTypeFromSignature($signature);
3976
3977     return ($getIsolate ? "v8Boolean($value, $getIsolate)" : "v8Boolean($value)") if $type eq "boolean";
3978     return "v8::Handle<v8::Value>()" if $type eq "void";     # equivalent to v8::Undefined()
3979
3980     # HTML5 says that unsigned reflected attributes should be in the range
3981     # [0, 2^31). When a value isn't in this range, a default value (or 0)
3982     # should be returned instead.
3983     if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) {
3984         $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g;
3985         return "v8UnsignedInteger(std::max(0, " . $value . ")$getIsolateArg)";
3986     }
3987
3988     # For all the types where we use 'int' as the representation type,
3989     # we use v8Integer() which has a fast small integer conversion check.
3990     my $nativeType = GetNativeType($type);
3991     return "v8Integer($value$getIsolateArg)" if $nativeType eq "int";
3992     return "v8UnsignedInteger($value$getIsolateArg)" if $nativeType eq "unsigned";
3993
3994     return "v8DateOrNull($value$getIsolateArg)" if $type eq "Date";
3995     # long long and unsigned long long are not representable in ECMAScript.
3996     return "v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp";
3997     return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type);
3998     return "$value.v8Value()" if $nativeType eq "ScriptValue";
3999
4000     if ($codeGenerator->IsStringType($type)) {
4001         my $conv = $signature->extendedAttributes->{"TreatReturnedNullStringAs"};
4002         if (defined $conv) {
4003             return "v8StringOrNull($value$getIsolateArg)" if $conv eq "Null";
4004             return "v8StringOrUndefined($value$getIsolateArg)" if $conv eq "Undefined";
4005             return "v8StringOrFalse($value$getIsolateArg)" if $conv eq "False";
4006
4007             die "Unknown value for TreatReturnedNullStringAs extended attribute";
4008         }
4009         return "v8String($value$getIsolateArg)";
4010     }
4011
4012     my $arrayType = $codeGenerator->GetArrayType($type);
4013     if ($arrayType) {
4014         if ($type eq "DOMString[]") {
4015             AddToImplIncludes("V8DOMStringList.h");
4016             AddToImplIncludes("DOMStringList.h");
4017         } elsif (!$codeGenerator->SkipIncludeHeader($arrayType)) {
4018             AddToImplIncludes("V8$arrayType.h");
4019             AddToImplIncludes("$arrayType.h");
4020         }
4021         return "v8Array($value$getIsolateArg)";
4022     }
4023
4024     my $sequenceType = $codeGenerator->GetSequenceType($type);
4025     if ($sequenceType) {
4026         if (!$codeGenerator->SkipIncludeHeader($sequenceType)) {
4027             AddToImplIncludes("V8$sequenceType.h");
4028             AddToImplIncludes("$sequenceType.h");
4029         }
4030         return "v8Array($value, $getIsolate)";
4031     }
4032
4033     AddIncludesForType($type);
4034
4035     # special case for non-DOM node interfaces
4036     if (IsDOMNodeType($type)) {
4037         return "toV8(${value}" . ($signature->extendedAttributes->{"ReturnNewObject"} ? "$getIsolateArg, true)" : "$getIsolateArg)");
4038     }
4039
4040     if ($type eq "EventTarget") {
4041         return "V8DOMWrapper::convertEventTargetToV8Object($value$getIsolateArg)";
4042     }
4043
4044     if ($type eq "EventListener") {
4045         AddToImplIncludes("V8AbstractEventListener.h");
4046         return "${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(" . ($getIsolate ? "v8::Null($getIsolate)" : "v8::Null()") . ")";
4047     }
4048
4049     if ($type eq "SerializedScriptValue") {
4050         AddToImplIncludes("$type.h");
4051         return "$value ? $value->deserialize() : v8::Handle<v8::Value>(" . ($getIsolate ? "v8::Null($getIsolate)" : "v8::Null()") . ")";
4052     }
4053
4054     AddToImplIncludes("wtf/RefCounted.h");
4055     AddToImplIncludes("wtf/RefPtr.h");
4056     AddToImplIncludes("wtf/GetPtr.h");
4057
4058     return "toV8($value$getIsolateArg)";
4059 }
4060
4061 sub ReturnNativeToJSValue
4062 {
4063     return "return " . NativeToJSValue(@_);
4064 }
4065
4066 # Internal helper
4067 sub WriteData
4068 {
4069     my $object = shift;
4070     my $dataNode = shift;
4071
4072     my $name = $dataNode->name;
4073     my $prefix = FileNamePrefix;
4074     my $headerFileName = "$outputHeadersDir/$prefix$name.h";
4075     my $implFileName = "$outputDir/$prefix$name.cpp";
4076
4077     # Update a .cpp file if the contents are changed.
4078     my $contents = join "", @implContentHeader, @implFixedHeader;
4079
4080     my @includes = ();
4081     my %implIncludeConditions = ();
4082     foreach my $include (keys %implIncludes) {
4083         my $condition = $implIncludes{$include};
4084         my $checkType = $include;
4085         $checkType =~ s/\.h//;
4086         next if $codeGenerator->IsSVGAnimatedType($checkType);
4087
4088         if ($include =~ /wtf/) {
4089             $include = "\<$include\>";
4090         } else {
4091             $include = "\"$include\"";
4092         }
4093
4094         if ($condition eq 1) {
4095             push @includes, $include;
4096         } else {
4097             push @{$implIncludeConditions{$condition}}, $include;
4098         }
4099     }
4100     foreach my $include (sort @includes) {
4101         $contents .= "#include $include\n";
4102     }
4103     foreach my $condition (sort keys %implIncludeConditions) {
4104         $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n";
4105         foreach my $include (sort @{$implIncludeConditions{$condition}}) {
4106             $contents .= "#include $include\n";
4107         }
4108         $contents .= "#endif\n";
4109     }
4110
4111     $contents .= "\n";
4112     $contents .= join "", @implContentDecls, @implContent;
4113     $codeGenerator->UpdateFile($implFileName, $contents);
4114
4115     %implIncludes = ();
4116     @implFixedHeader = ();
4117     @implContentDecls = ();
4118     @implContent = ();
4119
4120     # Update a .h file if the contents are changed.
4121     $contents = join "", @headerContent;
4122     $codeGenerator->UpdateFile($headerFileName, $contents);
4123
4124     @headerContent = ();
4125 }
4126
4127 sub GetCallbackClassName
4128 {
4129     my $interfaceName = shift;
4130
4131     return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback";
4132     return "V8$interfaceName";
4133 }
4134
4135 sub ConvertToV8Parameter
4136 {
4137     my $signature = shift;
4138     my $nativeType = shift;
4139     my $variableName = shift;
4140     my $value = shift;
4141     my $suffix = shift;
4142
4143     die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/;
4144     if ($signature->type eq "DOMString") {
4145         AddToImplIncludes("V8BindingMacros.h");
4146         my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK";
4147         $macro .= "_$suffix" if $suffix;
4148         return "$macro($nativeType, $variableName, $value);"
4149     } else {
4150         # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData"
4151         return "$nativeType $variableName($value, true);";
4152     }
4153 }
4154
4155 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled.
4156 sub GetRuntimeEnableFunctionName
4157 {
4158     my $signature = shift;
4159
4160     # If a parameter is given (e.g. "V8EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method.
4161     return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"V8EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"V8EnabledAtRuntime"} && $signature->extendedAttributes->{"V8EnabledAtRuntime"} ne "VALUE_IS_MISSING");
4162
4163     # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled().
4164     return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled";
4165 }
4166
4167 sub GetContextEnableFunction
4168 {
4169     my $signature = shift;
4170
4171     # If a parameter is given (e.g. "V8EnabledPerContext=FeatureName") return the {FeatureName}Allowed() method.
4172     if ($signature->extendedAttributes->{"V8EnabledPerContext"} && $signature->extendedAttributes->{"V8EnabledPerContext"} ne "VALUE_IS_MISSING") {
4173         return "ContextFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"V8EnabledPerContext"}) . "Enabled";
4174     }
4175
4176     # Or it fallbacks to the attribute name if the parameter value is missing.
4177     my $attributeName = $signature->name;
4178     return "ContextFeatures::" . $codeGenerator->WK_lcfirst($attributeName) . "Enabled";
4179 }
4180
4181 sub GetPassRefPtrType
4182 {
4183     my $className = shift;
4184
4185     my $angleBracketSpace = $className =~ />$/ ? " " : "";
4186     return "PassRefPtr<${className}${angleBracketSpace}>";
4187 }
4188
4189 sub DebugPrint
4190 {
4191     my $output = shift;
4192
4193     print $output;
4194     print "\n";
4195 }
4196
4197 1;