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