OSDN Git Service

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