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