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