Rename [ConvertUndefinedOrNullToNullString] to
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGeneratorJS.pm
1 #
2 # Copyright (C) 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4 # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
5 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6 # Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
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 # Copyright (C) 2011 Patrick Gansterer <paroga@webkit.org>
11 #
12 # This library is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU Library General Public
14 # License as published by the Free Software Foundation; either
15 # version 2 of the License, or (at your option) any later version.
16 #
17 # This library is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 # Library General Public License for more details.
21 #
22 # You should have received a copy of the GNU Library General Public License
23 # along with this library; see the file COPYING.LIB.  If not, write to
24 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 # Boston, MA 02110-1301, USA.
26
27 package CodeGeneratorJS;
28
29 use strict;
30
31 use constant FileNamePrefix => "JS";
32
33 my ($codeGenerator);
34
35 my $module = "";
36 my $outputDir = "";
37 my $writeDependencies = 0;
38
39 my @headerContentHeader = ();
40 my @headerContent = ();
41 my %headerIncludes = ();
42 my %headerTrailingIncludes = ();
43
44 my @implContentHeader = ();
45 my @implContent = ();
46 my %implIncludes = ();
47 my @depsContent = ();
48 my $numCachedAttributes = 0;
49 my $currentCachedAttribute = 0;
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., 51 Franklin Street, Fifth Floor,
70     Boston, MA 02110-1301, 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     shift; # $outputHeadersDir
83     shift; # $useLayerOnTop
84     shift; # $preprocessor
85     $writeDependencies = shift;
86
87     bless($reference, $object);
88     return $reference;
89 }
90
91 sub leftShift($$) {
92     my ($value, $distance) = @_;
93     return (($value << $distance) & 0xFFFFFFFF);
94 }
95
96 # Params: 'domClass' struct
97 sub GenerateInterface
98 {
99     my $object = shift;
100     my $dataNode = shift;
101     my $defines = shift;
102
103     $codeGenerator->LinkOverloadedFunctions($dataNode);
104
105     # Start actual generation
106     if ($dataNode->extendedAttributes->{"Callback"}) {
107         $object->GenerateCallbackHeader($dataNode);
108         $object->GenerateCallbackImplementation($dataNode);
109     } else {
110         $object->GenerateHeader($dataNode);
111         $object->GenerateImplementation($dataNode);
112     }
113
114     $object->WriteData($dataNode);
115 }
116
117 sub GenerateAttributeEventListenerCall
118 {
119     my $className = shift;
120     my $implSetterFunctionName = shift;
121     my $windowEventListener = shift;
122
123     my $wrapperObject = $windowEventListener ? "globalObject" : "thisObject";
124     my @GenerateEventListenerImpl = ();
125
126     if ($className eq "JSSVGElementInstance") {
127         # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
128         $wrapperObject = "asObject(correspondingElementWrapper)";
129
130         push(@GenerateEventListenerImpl, <<END);
131     JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement());
132     if (correspondingElementWrapper.isObject())
133 END
134
135         # Add leading whitespace to format the impl->set... line correctly
136         push(@GenerateEventListenerImpl, "    ");
137     }
138
139     push(@GenerateEventListenerImpl, "    impl->set$implSetterFunctionName(createJSAttributeEventListener(exec, value, $wrapperObject));\n");
140     return @GenerateEventListenerImpl;
141 }
142
143 sub GenerateEventListenerCall
144 {
145     my $className = shift;
146     my $functionName = shift;
147     my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()";
148
149     $implIncludes{"JSEventListener.h"} = 1;
150
151     my @GenerateEventListenerImpl = ();
152     my $wrapperObject = "castedThis";
153     if ($className eq "JSSVGElementInstance") {
154         # SVGElementInstances have to create JSEventListeners with the wrapper equal to the correspondingElement
155         $wrapperObject = "asObject(correspondingElementWrapper)";
156
157         push(@GenerateEventListenerImpl, <<END);
158     JSValue correspondingElementWrapper = toJS(exec, castedThis->globalObject(), impl->correspondingElement());
159     if (!correspondingElementWrapper.isObject())
160         return JSValue::encode(jsUndefined());
161 END
162     }
163
164     push(@GenerateEventListenerImpl, <<END);
165     JSValue listener = exec->argument(1);
166     if (!listener.isObject())
167         return JSValue::encode(jsUndefined());
168     impl->${functionName}EventListener(ustringToAtomicString(exec->argument(0).toString(exec)->value(exec)), JSEventListener::create(asObject(listener), $wrapperObject, false, currentWorld(exec))$passRefPtrHandling, exec->argument(2).toBoolean(exec));
169     return JSValue::encode(jsUndefined());
170 END
171     return @GenerateEventListenerImpl;
172 }
173
174 # Params: 'idlDocument' struct
175 sub GenerateModule
176 {
177     my $object = shift;
178     my $dataNode = shift;
179
180     $module = $dataNode->module;
181 }
182
183 sub GetParentClassName
184 {
185     my $dataNode = shift;
186
187     return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
188     return "JSDOMWrapper" if (@{$dataNode->parents} eq 0);
189     return "JS" . $codeGenerator->StripModule($dataNode->parents(0));
190 }
191
192 sub GetVisibleClassName
193 {
194     my $className = shift;
195
196     return "DOMException" if $className eq "DOMCoreException";
197     return "FormData" if $className eq "DOMFormData";
198     return "MimeType" if $className eq "DOMMimeType";
199     return "MimeTypeArray" if $className eq "DOMMimeTypeArray";
200     return "Plugin" if $className eq "DOMPlugin";
201     return "PluginArray" if $className eq "DOMPluginArray";
202     
203     return $className;
204 }
205
206 sub GetCallbackClassName
207 {
208     my $className = shift;
209
210     return "JSCustomVoidCallback" if $className eq "VoidCallback";
211     return "JS$className";
212 }
213
214 sub IndexGetterReturnsStrings
215 {
216     my $type = shift;
217
218     return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList" or $type eq "DOMStringList" or $type eq "DOMTokenList" or $type eq "DOMSettableTokenList";
219     return 0;
220 }
221
222 sub AddIncludesForTypeInImpl
223 {
224     my $type = $codeGenerator->StripModule(shift);
225     my $isCallback = @_ ? shift : 0;
226     
227     AddIncludesForType($type, $isCallback, \%implIncludes);
228     
229     # additional includes (things needed to compile the bindings but not the header)
230     if ($type eq "CanvasRenderingContext2D") {
231         $implIncludes{"CanvasGradient.h"} = 1;
232         $implIncludes{"CanvasPattern.h"} = 1;
233         $implIncludes{"CanvasStyle.h"} = 1;
234     }
235
236     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver" or $type eq "MessagePort") {
237         $implIncludes{"PlatformString.h"} = 1;
238     }
239
240     if ($type eq "Document") {
241         $implIncludes{"NodeFilter.h"} = 1;
242     }
243
244     if ($type eq "MediaQueryListListener") {
245         $implIncludes{"MediaQueryListListener.h"} = 1;
246     }
247 }
248
249 sub AddIncludesForTypeInHeader
250 {
251     my $type = $codeGenerator->StripModule(shift);
252     my $isCallback = @_ ? shift : 0;
253     
254     AddIncludesForType($type, $isCallback, \%headerIncludes);
255 }
256
257 sub AddIncludesForType
258 {
259     my $type = shift;
260     my $isCallback = shift;
261     my $includesRef = shift;
262
263     # When we're finished with the one-file-per-class
264     # reorganization, we won't need these special cases.
265     if ($codeGenerator->IsPrimitiveType($type) or $codeGenerator->AvoidInclusionOfType($type)
266         or $type eq "DOMString" or $type eq "DOMObject" or $type eq "Array" or $type eq "DOMTimeStamp") {
267     } elsif ($type =~ /SVGPathSeg/) {
268         my $joinedName = $type;
269         $joinedName =~ s/Abs|Rel//;
270         $includesRef->{"${joinedName}.h"} = 1;
271     } elsif ($type eq "XPathNSResolver") {
272         $includesRef->{"JSXPathNSResolver.h"} = 1;
273         $includesRef->{"JSCustomXPathNSResolver.h"} = 1;
274     } elsif ($type eq "DOMString[]") {
275         # FIXME: Add proper support for T[], T[]?, sequence<T>
276         $includesRef->{"JSDOMStringList.h"} = 1;
277     } elsif ($isCallback) {
278         $includesRef->{"JS${type}.h"} = 1;
279     } elsif (IsTypedArrayType($type)) {
280         $includesRef->{"<wtf/${type}.h>"} = 1;
281     } else {
282         # default, include the same named file
283         $includesRef->{"${type}.h"} = 1;
284     }
285 }
286
287 # FIXME: This method will go away once all SVG animated properties are converted to the new scheme.
288 sub AddIncludesForSVGAnimatedType
289 {
290     my $type = shift;
291     $type =~ s/SVGAnimated//;
292
293     if ($type eq "Point" or $type eq "Rect") {
294         $implIncludes{"Float$type.h"} = 1;
295     } elsif ($type eq "String") {
296         $implIncludes{"PlatformString.h"} = 1;
297     }
298 }
299
300 sub AddToImplIncludes
301 {
302     my $header = shift;
303     my $conditional = shift;
304
305     if (not $conditional) {
306         $implIncludes{$header} = 1;
307     } elsif (not exists($implIncludes{$header})) {
308         $implIncludes{$header} = $conditional;
309     } else {
310         my $oldValue = $implIncludes{$header};
311         if ($oldValue ne 1) {
312             my %newValue = ();
313             $newValue{$conditional} = 1;
314             foreach my $condition (split(/\|/, $oldValue)) {
315                 $newValue{$condition} = 1;
316             }
317             $implIncludes{$header} = join("|", sort keys %newValue);
318         }
319     }
320 }
321
322 sub IsScriptProfileType
323 {
324     my $type = shift;
325     return 1 if ($type eq "ScriptProfileNode");
326     return 0;
327 }
328
329 sub IsTypedArrayType
330 {
331     my $type = shift;
332     return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView"));
333     return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array"));
334     return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array"));
335     return 1 if (($type eq "Float32Array") or ($type eq "Float64Array"));
336     return 0;
337 }
338
339 sub AddTypedefForScriptProfileType
340 {
341     my $type = shift;
342     (my $jscType = $type) =~ s/Script//;
343
344     push(@headerContent, "typedef JSC::$jscType $type;\n\n");
345 }
346
347 sub AddClassForwardIfNeeded
348 {
349     my $implClassName = shift;
350
351     # SVGAnimatedLength/Number/etc. are typedefs to SVGAnimatedTemplate, so don't use class forwards for them!
352     unless ($codeGenerator->IsSVGAnimatedType($implClassName) or IsScriptProfileType($implClassName) or IsTypedArrayType($implClassName)) {
353         push(@headerContent, "class $implClassName;\n\n");
354     # ScriptProfile and ScriptProfileNode are typedefs to JSC::Profile and JSC::ProfileNode.
355     } elsif (IsScriptProfileType($implClassName)) {
356         $headerIncludes{"<profiler/ProfileNode.h>"} = 1;
357         AddTypedefForScriptProfileType($implClassName);
358     }
359 }
360
361 sub HashValueForClassAndName
362 {
363     my $class = shift;
364     my $name = shift;
365
366     # SVG Filter enums live in WebCore namespace (platform/graphics/)
367     if ($class =~ /^SVGFE*/ or $class =~ /^SVGComponentTransferFunctionElement$/) {
368         return "WebCore::$name";
369     }
370
371     return "${class}::$name";
372 }
373
374 sub hashTableAccessor
375 {
376     my $noStaticTables = shift;
377     my $className = shift;
378     if ($noStaticTables) {
379         return "get${className}Table(exec)";
380     } else {
381         return "&${className}Table";
382     }
383 }
384
385 sub prototypeHashTableAccessor
386 {
387     my $noStaticTables = shift;
388     my $className = shift;
389     if ($noStaticTables) {
390         return "get${className}PrototypeTable(exec)";
391     } else {
392         return "&${className}PrototypeTable";
393     }
394 }
395
396 sub GenerateConditionalString
397 {
398     my $node = shift;
399     my $conditional = $node->extendedAttributes->{"Conditional"};
400     if ($conditional) {
401         return $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
402     } else {
403         return "";
404     }
405 }
406
407 sub GenerateGetOwnPropertySlotBody
408 {
409     my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_;
410
411     my $namespaceMaybe = ($inlined ? "JSC::" : "");
412
413     my @getOwnPropertySlotImpl = ();
414
415     if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
416         push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue proto = thisObject->prototype();\n");
417         push(@getOwnPropertySlotImpl, "    if (proto.isObject() && static_cast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
418         push(@getOwnPropertySlotImpl, "        return false;\n\n");
419     }
420
421     my $manualLookupGetterGeneration = sub {
422         my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
423         if ($requiresManualLookup) {
424             push(@getOwnPropertySlotImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
425             push(@getOwnPropertySlotImpl, "    if (entry) {\n");
426             push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
427             push(@getOwnPropertySlotImpl, "        return true;\n");
428             push(@getOwnPropertySlotImpl, "    }\n");
429         }
430     };
431
432     if (!$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
433         &$manualLookupGetterGeneration();
434     }
435
436     if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
437         push(@getOwnPropertySlotImpl, "    bool ok;\n");
438         push(@getOwnPropertySlotImpl, "    unsigned index = propertyName.toUInt32(ok);\n");
439
440         # If the item function returns a string then we let the ConvertNullStringTo handle the cases
441         # where the index is out of range.
442         if (IndexGetterReturnsStrings($implClassName)) {
443             push(@getOwnPropertySlotImpl, "    if (ok) {\n");
444         } else {
445             push(@getOwnPropertySlotImpl, "    if (ok && index < static_cast<$implClassName*>(thisObject->impl())->length()) {\n");
446         }
447         if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
448             push(@getOwnPropertySlotImpl, "        slot.setValue(thisObject->getByIndex(exec, index));\n");
449         } else {
450             push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
451         }
452         push(@getOwnPropertySlotImpl, "        return true;\n");
453         push(@getOwnPropertySlotImpl, "    }\n");
454     }
455
456     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
457         push(@getOwnPropertySlotImpl, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(thisObject->impl()), propertyName)) {\n");
458         push(@getOwnPropertySlotImpl, "        slot.setCustom(thisObject, thisObject->nameGetter);\n");
459         push(@getOwnPropertySlotImpl, "        return true;\n");
460         push(@getOwnPropertySlotImpl, "    }\n");
461         if ($inlined) {
462             $headerIncludes{"wtf/text/AtomicString.h"} = 1;
463         } else {
464             $implIncludes{"wtf/text/AtomicString.h"} = 1;
465         }
466     }
467
468     if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
469         &$manualLookupGetterGeneration();
470     }
471
472     if ($dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}) {
473         push(@getOwnPropertySlotImpl, "    if (thisObject->getOwnPropertySlotDelegate(exec, propertyName, slot))\n");
474         push(@getOwnPropertySlotImpl, "        return true;\n");
475     }
476
477     if ($hasAttributes) {
478         if ($inlined) {
479             die "Cannot inline if NoStaticTables is set." if ($dataNode->extendedAttributes->{"NoStaticTables"});
480             push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, slot);\n");
481         } else {
482             push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
483         }
484     } else {
485         push(@getOwnPropertySlotImpl, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");
486     }
487
488     return @getOwnPropertySlotImpl;
489 }
490
491 sub GenerateGetOwnPropertyDescriptorBody
492 {
493     my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_;
494     
495     my $namespaceMaybe = ($inlined ? "JSC::" : "");
496     
497     my @getOwnPropertyDescriptorImpl = ();
498     if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
499         if ($interfaceName eq "DOMWindow") {
500             push(@implContent, "    if (!thisObject->allowsAccessFrom(exec))\n");
501         } else {
502             push(@implContent, "    if (!allowAccessToFrame(exec, thisObject->impl()->frame()))\n");
503         }
504         push(@implContent, "        return false;\n");
505     }
506     
507     if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
508         push(@getOwnPropertyDescriptorImpl, "    ${namespaceMaybe}JSValue proto = thisObject->prototype();\n");
509         push(@getOwnPropertyDescriptorImpl, "    if (proto.isObject() && static_cast<${namespaceMaybe}JSObject*>(asObject(proto))->hasProperty(exec, propertyName))\n");
510         push(@getOwnPropertyDescriptorImpl, "        return false;\n\n");
511     }
512     
513     my $manualLookupGetterGeneration = sub {
514         my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
515         if ($requiresManualLookup) {
516             push(@getOwnPropertyDescriptorImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
517             push(@getOwnPropertyDescriptorImpl, "    if (entry) {\n");
518             push(@getOwnPropertyDescriptorImpl, "        PropertySlot slot;\n");
519             push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, entry->propertyGetter());\n");
520             push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());\n");
521             push(@getOwnPropertyDescriptorImpl, "        return true;\n");
522             push(@getOwnPropertyDescriptorImpl, "    }\n");
523         }
524     };
525     
526     if (!$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
527         &$manualLookupGetterGeneration();
528     }
529     
530     if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
531         push(@getOwnPropertyDescriptorImpl, "    bool ok;\n");
532         push(@getOwnPropertyDescriptorImpl, "    unsigned index = propertyName.toUInt32(ok);\n");
533         push(@getOwnPropertyDescriptorImpl, "    if (ok && index < static_cast<$implClassName*>(thisObject->impl())->length()) {\n");
534         if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
535             # Assume that if there's a setter, the index will be writable
536             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
537                 push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete);\n");
538             } else {
539                 push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(thisObject->getByIndex(exec, index), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
540             }
541         } else {
542             push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
543             push(@getOwnPropertyDescriptorImpl, "        slot.setCustomIndex(thisObject, index, indexGetter);\n");
544             # Assume that if there's a setter, the index will be writable
545             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
546                 push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete);\n");
547             } else {
548                 push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ${namespaceMaybe}DontDelete | ${namespaceMaybe}ReadOnly);\n");
549             }
550         }
551         push(@getOwnPropertyDescriptorImpl, "        return true;\n");
552         push(@getOwnPropertyDescriptorImpl, "    }\n");
553     }
554     
555     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
556         push(@getOwnPropertyDescriptorImpl, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(thisObject->impl()), propertyName)) {\n");
557         push(@getOwnPropertyDescriptorImpl, "        ${namespaceMaybe}PropertySlot slot;\n");
558         push(@getOwnPropertyDescriptorImpl, "        slot.setCustom(thisObject, nameGetter);\n");
559         push(@getOwnPropertyDescriptorImpl, "        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);\n");
560         push(@getOwnPropertyDescriptorImpl, "        return true;\n");
561         push(@getOwnPropertyDescriptorImpl, "    }\n");
562         if ($inlined) {
563             $headerIncludes{"wtf/text/AtomicString.h"} = 1;
564         } else {
565             $implIncludes{"wtf/text/AtomicString.h"} = 1;
566         }
567     }
568     
569     if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
570         &$manualLookupGetterGeneration();
571     }
572     
573     if ($dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}) {
574         push(@getOwnPropertyDescriptorImpl, "    if (thisObject->getOwnPropertyDescriptorDelegate(exec, propertyName, descriptor))\n");
575         push(@getOwnPropertyDescriptorImpl, "        return true;\n");
576     }
577     
578     if ($hasAttributes) {
579         if ($inlined) {
580             die "Cannot inline if NoStaticTables is set." if ($dataNode->extendedAttributes->{"NoStaticTables"});
581             push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, s_info.staticPropHashTable, thisObject, propertyName, descriptor);\n");
582         } else {
583             push(@getOwnPropertyDescriptorImpl, "    return ${namespaceMaybe}getStaticValueDescriptor<$className, Base>(exec, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
584         }
585     } else {
586         push(@getOwnPropertyDescriptorImpl, "    return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n");
587     }
588     
589     return @getOwnPropertyDescriptorImpl;
590 }
591
592 sub GenerateHeaderContentHeader
593 {
594     my $dataNode = shift;
595     my $className = "JS" . $dataNode->name;
596
597     my @headerContentHeader = split("\r", $headerTemplate);
598
599     # - Add header protection
600     push(@headerContentHeader, "\n#ifndef $className" . "_h");
601     push(@headerContentHeader, "\n#define $className" . "_h\n\n");
602
603     my $conditionalString = GenerateConditionalString($dataNode);
604     push(@headerContentHeader, "#if ${conditionalString}\n\n") if $conditionalString;
605     return @headerContentHeader;
606 }
607
608 sub GenerateImplementationContentHeader
609 {
610     my $dataNode = shift;
611     my $className = "JS" . $dataNode->name;
612
613     my @implContentHeader = split("\r", $headerTemplate);
614
615     push(@implContentHeader, "\n#include \"config.h\"\n");
616     my $conditionalString = GenerateConditionalString($dataNode);
617     push(@implContentHeader, "\n#if ${conditionalString}\n\n") if $conditionalString;
618     push(@implContentHeader, "#include \"$className.h\"\n\n");
619     return @implContentHeader;
620 }
621
622 my %usesToJSNewlyCreated = (
623     "CDATASection" => 1,
624     "Element" => 1,
625     "Node" => 1,
626     "Text" => 1,
627     "Touch" => 1,
628     "TouchList" => 1
629 );
630
631 sub GetFunctionName
632 {
633     my ($className, $function) = @_;
634     my $kind = $function->isStatic ? "Constructor" : "Prototype";
635     return $codeGenerator->WK_lcfirst($className) . $kind . "Function" . $codeGenerator->WK_ucfirst($function->signature->name);
636 }
637
638 sub GenerateHeader
639 {
640     my $object = shift;
641     my $dataNode = shift;
642
643     my $interfaceName = $dataNode->name;
644     my $className = "JS$interfaceName";
645     my $implClassName = $interfaceName;
646     my @ancestorInterfaceNames = ();
647     my %structureFlags = ();
648
649     # We only support multiple parents with SVG (for now).
650     if (@{$dataNode->parents} > 1) {
651         die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
652         $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@ancestorInterfaceNames);
653     }
654
655     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
656     my $hasRealParent = @{$dataNode->parents} > 0;
657     my $hasParent = $hasLegacyParent || $hasRealParent;
658     my $parentClassName = GetParentClassName($dataNode);
659     my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"};
660     my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"};
661     
662     # - Add default header template and header protection
663     push(@headerContentHeader, GenerateHeaderContentHeader($dataNode));
664
665     if ($hasParent) {
666         $headerIncludes{"$parentClassName.h"} = 1;
667     } else {
668         $headerIncludes{"JSDOMBinding.h"} = 1;
669         $headerIncludes{"<runtime/JSGlobalObject.h>"} = 1;
670         $headerIncludes{"<runtime/ObjectPrototype.h>"} = 1;
671     }
672
673     if ($dataNode->extendedAttributes->{"CustomCall"}) {
674         $headerIncludes{"<runtime/CallData.h>"} = 1;
675     }
676
677     if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"}) {
678         $headerIncludes{"<runtime/Lookup.h>"} = 1;
679         $headerIncludes{"<wtf/AlwaysInline.h>"} = 1;
680     }
681
682     if ($hasParent && $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
683         if (IsTypedArrayType($implClassName)) {
684             $headerIncludes{"<wtf/$implClassName.h>"} = 1;
685         } else {
686             $headerIncludes{"$implClassName.h"} = 1;
687         }
688     }
689     
690     $headerIncludes{"<runtime/JSObject.h>"} = 1;
691     $headerIncludes{"SVGElement.h"} = 1 if $className =~ /^JSSVG/;
692
693     my $implType = $implClassName;
694     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
695     $implType = $svgNativeType if $svgNativeType;
696
697     my $svgPropertyOrListPropertyType;
698     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
699     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
700
701     my $numConstants = @{$dataNode->constants};
702     my $numAttributes = @{$dataNode->attributes};
703     my $numFunctions = @{$dataNode->functions};
704
705     push(@headerContent, "\nnamespace WebCore {\n\n");
706
707     if ($codeGenerator->IsSVGAnimatedType($implClassName)) {
708         $headerIncludes{"$implClassName.h"} = 1;
709     } else {
710         # Implementation class forward declaration
711         if ($interfaceName eq "DOMWindow" || $dataNode->extendedAttributes->{"IsWorkerContext"}) {
712             AddClassForwardIfNeeded($implClassName) unless $svgPropertyOrListPropertyType;
713         }
714     }
715
716     AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
717     AddClassForwardIfNeeded("JSDictionary") if IsConstructorTemplate($dataNode, "Event");
718
719     # Class declaration
720     push(@headerContent, "class $className : public $parentClassName {\n");
721
722     # Static create methods
723     push(@headerContent, "public:\n");
724     push(@headerContent, "    typedef $parentClassName Base;\n");
725     if ($interfaceName eq "DOMWindow") {
726         push(@headerContent, "    static $className* create(JSC::JSGlobalData& globalData, JSC::Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* windowShell)\n");
727         push(@headerContent, "    {\n");
728         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalData.heap)) ${className}(globalData, structure, impl, windowShell);\n");
729         push(@headerContent, "        ptr->finishCreation(globalData, windowShell);\n");
730         push(@headerContent, "        return ptr;\n");
731         push(@headerContent, "    }\n\n");
732     } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
733         push(@headerContent, "    static $className* create(JSC::JSGlobalData& globalData, JSC::Structure* structure, PassRefPtr<$implType> impl)\n");
734         push(@headerContent, "    {\n");
735         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalData.heap)) ${className}(globalData, structure, impl);\n");
736         push(@headerContent, "        ptr->finishCreation(globalData);\n");
737         push(@headerContent, "        return ptr;\n");
738         push(@headerContent, "    }\n\n");
739     } else {
740         AddIncludesForTypeInHeader($implType) unless $svgPropertyOrListPropertyType;
741         push(@headerContent, "    static $className* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
742         push(@headerContent, "    {\n");
743         push(@headerContent, "        $className* ptr = new (NotNull, JSC::allocateCell<$className>(globalObject->globalData().heap)) $className(structure, globalObject, impl);\n");
744         push(@headerContent, "        ptr->finishCreation(globalObject->globalData());\n");
745         push(@headerContent, "        return ptr;\n");
746         push(@headerContent, "    }\n\n");
747     }
748
749     # Prototype
750     push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::ExecState*, JSC::JSGlobalObject*);\n") unless ($dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"});
751
752     $headerTrailingIncludes{"${className}Custom.h"} = 1 if $dataNode->extendedAttributes->{"CustomHeader"};
753
754     $implIncludes{"${className}Custom.h"} = 1 if !$dataNode->extendedAttributes->{"CustomHeader"} && ($dataNode->extendedAttributes->{"CustomPutFunction"} || $dataNode->extendedAttributes->{"DelegatingPutFunction"});
755
756     my $hasGetter = $numAttributes > 0 
757                  || !$dataNode->extendedAttributes->{"OmitConstructor"}
758                  || $dataNode->extendedAttributes->{"HasIndexGetter"}
759                  || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}
760                  || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
761                  || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}
762                  || $dataNode->extendedAttributes->{"HasNameGetter"}
763                  || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
764
765     # Getters
766     if ($hasGetter) {
767         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);\n");
768         push(@headerContent, "    static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&);\n");
769         push(@headerContent, "    static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"};
770         push(@headerContent, "    bool getOwnPropertySlotDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"};
771         push(@headerContent, "    bool getOwnPropertyDescriptorDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n") if $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"};
772         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
773     }
774
775     # Check if we have any writable properties
776     my $hasReadWriteProperties = 0;
777     foreach (@{$dataNode->attributes}) {
778         if ($_->type !~ /^readonly\ attribute$/) {
779             $hasReadWriteProperties = 1;
780         }
781     }
782
783     my $hasSetter = $hasReadWriteProperties
784                  || $dataNode->extendedAttributes->{"CustomPutFunction"}
785                  || $dataNode->extendedAttributes->{"DelegatingPutFunction"}
786                  || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
787
788     # Getters
789     if ($hasSetter) {
790         push(@headerContent, "    static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
791         push(@headerContent, "    static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue);\n") if $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
792         push(@headerContent, "    bool putDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, JSC::PutPropertySlot&);\n") if $dataNode->extendedAttributes->{"DelegatingPutFunction"};
793     }
794
795     if (!$hasParent) {
796         push(@headerContent, "    static void destroy(JSC::JSCell*);\n");
797     }
798
799     # Class info
800     push(@headerContent, "    static const JSC::ClassInfo s_info;\n\n");
801
802     # Structure ID
803     if ($interfaceName eq "DOMWindow") {
804         $structureFlags{"JSC::ImplementsHasInstance"} = 1;
805     }
806     push(@headerContent, "    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n");
807     push(@headerContent, "    {\n");
808     if ($interfaceName eq "DOMWindow" || $dataNode->extendedAttributes->{"IsWorkerContext"}) {
809         push(@headerContent, "        return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::GlobalObjectType, StructureFlags), &s_info);\n");
810     } else {
811         push(@headerContent, "        return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n");
812     }
813     push(@headerContent, "    }\n\n");
814
815     # Custom pushEventHandlerScope function
816     push(@headerContent, "    JSC::ScopeChainNode* pushEventHandlerScope(JSC::ExecState*, JSC::ScopeChainNode*) const;\n\n") if $dataNode->extendedAttributes->{"CustomPushEventHandlerScope"};
817
818     # Custom call functions
819     push(@headerContent, "    static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&);\n\n") if $dataNode->extendedAttributes->{"CustomCall"};
820
821     # Custom deleteProperty function
822     push(@headerContent, "    static bool deleteProperty(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier&);\n") if $dataNode->extendedAttributes->{"CustomDeleteProperty"};
823
824     # Custom getPropertyNames function exists on DOMWindow
825     if ($interfaceName eq "DOMWindow") {
826         push(@headerContent, "    static void getPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
827         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;
828     }
829
830     # Custom defineProperty function exists on DOMWindow
831     push(@headerContent, "    static bool defineOwnProperty(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor&, bool shouldThrow);\n") if $interfaceName eq "DOMWindow";
832
833     # Custom getOwnPropertyNames function
834     if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
835         push(@headerContent, "    static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, JSC::EnumerationMode mode = JSC::ExcludeDontEnumProperties);\n");
836         $structureFlags{"JSC::OverridesGetPropertyNames"} = 1;       
837     }
838
839     # Custom defineGetter function
840     push(@headerContent, "    static void defineGetter(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineGetter"};
841
842     # Custom defineSetter function
843     push(@headerContent, "    static void defineSetter(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomDefineSetter"};
844
845     # Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
846     if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"}) {
847         $structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
848     }
849
850     # Constructor object getter
851     push(@headerContent, "    static JSC::JSValue getConstructor(JSC::ExecState*, JSC::JSGlobalObject*);\n") if !$dataNode->extendedAttributes->{"OmitConstructor"};
852
853     my $numCustomFunctions = 0;
854     my $numCustomAttributes = 0;
855
856     # Attribute and function enums
857     if ($numAttributes > 0) {
858         foreach (@{$dataNode->attributes}) {
859             my $attribute = $_;
860             $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"};
861             $numCustomAttributes++ if ($attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"});
862             $numCustomAttributes++ if ($attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"});
863             if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
864                 push(@headerContent, "    JSC::WriteBarrier<JSC::Unknown> m_" . $attribute->signature->name . ";\n");
865                 $numCachedAttributes++;
866                 $needsMarkChildren = 1;
867             }
868         }
869     }
870
871     # visit function
872     if ($needsMarkChildren) {
873         push(@headerContent, "    static void visitChildren(JSCell*, JSC::SlotVisitor&);\n\n");
874         $structureFlags{"JSC::OverridesVisitChildren"} = 1;
875     }
876
877     if ($numCustomAttributes > 0) {
878         push(@headerContent, "\n    // Custom attributes\n");
879
880         foreach my $attribute (@{$dataNode->attributes}) {
881             if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"}) {
882                 my $methodName = $codeGenerator->WK_lcfirst($attribute->signature->name);
883                 push(@headerContent, "    JSC::JSValue " . $methodName . "(JSC::ExecState*) const;\n");
884             }
885             if (($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"}) && $attribute->type !~ /^readonly/) {
886                 push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue);\n");
887             }
888         }
889     }
890
891     foreach my $function (@{$dataNode->functions}) {
892         $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"JSCCustom"};
893     }
894
895     if ($numCustomFunctions > 0) {
896         push(@headerContent, "\n    // Custom functions\n");
897         foreach my $function (@{$dataNode->functions}) {
898             next unless $function->signature->extendedAttributes->{"Custom"} or $function->signature->extendedAttributes->{"JSCCustom"};
899             next if $function->{overloads} && $function->{overloadIndex} != 1;
900             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
901             push(@headerContent, "    JSC::JSValue " . $functionImplementationName . "(JSC::ExecState*);\n");
902         }
903     }
904
905     if (!$hasParent) {
906         push(@headerContent, "    $implType* impl() const { return m_impl; }\n");
907         push(@headerContent, "    void releaseImpl() { m_impl->deref(); m_impl = 0; }\n\n");
908         push(@headerContent, "    void releaseImplIfNotNull() { if (m_impl) { m_impl->deref(); m_impl = 0; } }\n\n");
909         push(@headerContent, "private:\n");
910         push(@headerContent, "    $implType* m_impl;\n");
911     } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
912         push(@headerContent, "    $implClassName* impl() const\n");
913         push(@headerContent, "    {\n");
914         push(@headerContent, "        return static_cast<$implClassName*>(Base::impl());\n");
915         push(@headerContent, "    }\n");
916     }
917
918     if (IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) {
919         push(@headerContent, "    static const JSC::TypedArrayType TypedArrayStorageType = JSC::");
920         push(@headerContent, "TypedArrayInt8") if $implType eq "Int8Array";
921         push(@headerContent, "TypedArrayInt16") if $implType eq "Int16Array";
922         push(@headerContent, "TypedArrayInt32") if $implType eq "Int32Array";
923         push(@headerContent, "TypedArrayUint8") if $implType eq "Uint8Array";
924         push(@headerContent, "TypedArrayUint8Clamped") if $implType eq "Uint8ClampedArray";
925         push(@headerContent, "TypedArrayUint16") if $implType eq "Uint16Array";
926         push(@headerContent, "TypedArrayUint32") if $implType eq "Uint32Array";
927         push(@headerContent, "TypedArrayFloat32") if $implType eq "Float32Array";
928         push(@headerContent, "TypedArrayFloat64") if $implType eq "Float64Array";
929         push(@headerContent, ";\n");
930         push(@headerContent, "    intptr_t m_storageLength;\n");
931         push(@headerContent, "    void* m_storage;\n");
932     }
933
934     push(@headerContent, "protected:\n");
935     # Constructor
936     if ($interfaceName eq "DOMWindow") {
937         push(@headerContent, "    $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
938     } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
939         push(@headerContent, "    $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>);\n");
940     } else {
941         push(@headerContent, "    $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n");
942         push(@headerContent, "    void finishCreation(JSC::JSGlobalData&);\n");
943     }
944
945     # structure flags
946     push(@headerContent, "    static const unsigned StructureFlags = ");
947     foreach my $structureFlag (keys %structureFlags) {
948         push(@headerContent, $structureFlag . " | ");
949     }
950     push(@headerContent, "Base::StructureFlags;\n");
951
952     # Index getter
953     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
954         push(@headerContent, "    static JSC::JSValue indexGetter(JSC::ExecState*, JSC::JSValue, unsigned);\n");
955     }
956     if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
957         push(@headerContent, "    JSC::JSValue getByIndex(JSC::ExecState*, unsigned index);\n");
958         
959     }
960     
961     # Index setter
962     if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
963         push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue);\n");
964     }
965     # Name getter
966     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
967         push(@headerContent, "private:\n");
968         push(@headerContent, "    static bool canGetItemsForName(JSC::ExecState*, $implClassName*, const JSC::Identifier&);\n");
969         push(@headerContent, "    static JSC::JSValue nameGetter(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
970     }
971
972     push(@headerContent, "};\n\n");
973
974     if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"} && !$dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
975         push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertySlot(JSC::JSCell* cell, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertySlot& slot)\n");
976         push(@headerContent, "{\n");
977         push(@headerContent, "    ${className}* thisObject = JSC::jsCast<${className}*>(cell);\n");
978         push(@headerContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
979         push(@headerContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1));
980         push(@headerContent, "}\n\n");
981         push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertyDescriptor(JSC::JSObject* object, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor)\n");
982         push(@headerContent, "{\n");
983         push(@headerContent, "    ${className}* thisObject = JSC::jsCast<${className}*>(object);\n");
984         push(@headerContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
985         push(@headerContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1));
986         push(@headerContent, "}\n\n");
987     }
988
989     if (!$hasParent ||
990         $dataNode->extendedAttributes->{"GenerateIsReachable"} || 
991         $dataNode->extendedAttributes->{"CustomIsReachable"} || 
992         $dataNode->extendedAttributes->{"CustomFinalize"} ||
993         $dataNode->extendedAttributes->{"ActiveDOMObject"}) {
994         push(@headerContent, "class JS${implClassName}Owner : public JSC::WeakHandleOwner {\n");
995         push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
996         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
997         push(@headerContent, "};\n");
998         push(@headerContent, "\n");
999         push(@headerContent, "inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, $implType*)\n");
1000         push(@headerContent, "{\n");
1001         push(@headerContent, "    DEFINE_STATIC_LOCAL(JS${implClassName}Owner, js${implClassName}Owner, ());\n");
1002         push(@headerContent, "    return &js${implClassName}Owner;\n");
1003         push(@headerContent, "}\n");
1004         push(@headerContent, "\n");
1005         push(@headerContent, "inline void* wrapperContext(DOMWrapperWorld* world, $implType*)\n");
1006         push(@headerContent, "{\n");
1007         push(@headerContent, "    return world;\n");
1008         push(@headerContent, "}\n");
1009         push(@headerContent, "\n");
1010     }
1011
1012     if (!$hasParent || $dataNode->extendedAttributes->{"GenerateToJS"} || $dataNode->extendedAttributes->{"CustomToJS"}) {
1013         push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $implType*);\n");
1014     }
1015     if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
1016         if ($interfaceName eq "NodeFilter") {
1017             push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::JSGlobalData&, JSC::JSValue);\n");
1018         } else {
1019             push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n");
1020         }
1021     }
1022     if ($usesToJSNewlyCreated{$interfaceName}) {
1023         push(@headerContent, "JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName*);\n");
1024     }
1025     
1026     push(@headerContent, "\n");
1027
1028     # Add prototype declaration.
1029     %structureFlags = ();
1030     push(@headerContent, "class ${className}Prototype : public JSC::JSNonFinalObject {\n");
1031     push(@headerContent, "public:\n");
1032     push(@headerContent, "    typedef JSC::JSNonFinalObject Base;\n");
1033     if ($interfaceName ne "DOMWindow" && !$dataNode->extendedAttributes->{"IsWorkerContext"}) {
1034         push(@headerContent, "    static JSC::JSObject* self(JSC::ExecState*, JSC::JSGlobalObject*);\n");
1035     }
1036
1037     push(@headerContent, "    static ${className}Prototype* create(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)\n");
1038     push(@headerContent, "    {\n");
1039     push(@headerContent, "        ${className}Prototype* ptr = new (NotNull, JSC::allocateCell<${className}Prototype>(globalData.heap)) ${className}Prototype(globalData, globalObject, structure);\n");
1040     push(@headerContent, "        ptr->finishCreation(globalData);\n");
1041     push(@headerContent, "        return ptr;\n");
1042     push(@headerContent, "    }\n\n");
1043
1044     push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
1045     if ($numFunctions > 0 || $numConstants > 0) {
1046         push(@headerContent, "    static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n");
1047         push(@headerContent, "    static bool getOwnPropertyDescriptor(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n");
1048         $structureFlags{"JSC::OverridesGetOwnPropertySlot"} = 1;
1049     }
1050     if ($dataNode->extendedAttributes->{"CustomMarkFunction"} or $needsMarkChildren) {
1051         $structureFlags{"JSC::OverridesVisitChildren"} = 1;
1052     }
1053     push(@headerContent,
1054         "    static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)\n" .
1055         "    {\n" .
1056         "        return JSC::Structure::create(globalData, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), &s_info);\n" .
1057         "    }\n");
1058     if ($dataNode->extendedAttributes->{"DelegatingPrototypePutFunction"}) {
1059         push(@headerContent, "    static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
1060         push(@headerContent, "    bool putDelegate(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue, JSC::PutPropertySlot&);\n");
1061     }
1062
1063     # Custom defineGetter function
1064     push(@headerContent, "    static void defineGetter(JSC::JSObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomPrototypeDefineGetter"};
1065
1066     push(@headerContent, "\nprivate:\n");
1067     push(@headerContent, "    ${className}Prototype(JSC::JSGlobalData& globalData, JSC::JSGlobalObject*, JSC::Structure* structure) : JSC::JSNonFinalObject(globalData, structure) { }\n");
1068
1069     # structure flags
1070     push(@headerContent, "protected:\n");
1071     push(@headerContent, "    static const unsigned StructureFlags = ");
1072     foreach my $structureFlag (keys %structureFlags) {
1073         push(@headerContent, $structureFlag . " | ");
1074     }
1075     push(@headerContent, "Base::StructureFlags;\n");
1076
1077     push(@headerContent, "};\n\n");
1078
1079     if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
1080         $headerIncludes{"JSDOMBinding.h"} = 1;
1081         GenerateConstructorDeclaration(\@headerContent, $className, $dataNode, $interfaceName);
1082     }
1083
1084     if ($numFunctions > 0) {
1085         push(@headerContent,"// Functions\n\n");
1086         foreach my $function (@{$dataNode->functions}) {
1087             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1088             my $functionName = GetFunctionName($className, $function);
1089             push(@headerContent, "JSC::EncodedJSValue JSC_HOST_CALL ${functionName}(JSC::ExecState*);\n");
1090         }
1091     }
1092
1093     if ($numAttributes > 0 || !$dataNode->extendedAttributes->{"OmitConstructor"}) {
1094         push(@headerContent,"// Attributes\n\n");
1095         foreach my $attribute (@{$dataNode->attributes}) {
1096             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1097             push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1098             unless ($attribute->type =~ /readonly/) {
1099                 my $setter = "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1100                 push(@headerContent, "void ${setter}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1101             }
1102         }
1103         
1104         if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
1105             my $getter = "js" . $interfaceName . "Constructor";
1106             push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1107         }
1108
1109         if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
1110             my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
1111             push(@headerContent, "void ${constructorFunctionName}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue);\n");
1112         }
1113     }
1114
1115     if ($numConstants > 0) {
1116         push(@headerContent,"// Constants\n\n");
1117         foreach my $constant (@{$dataNode->constants}) {
1118             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
1119             my $conditional = $constant->extendedAttributes->{"Conditional"};
1120             if ($conditional) {
1121                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
1122                 push(@headerContent, "#if ${conditionalString}\n");
1123             }
1124             push(@headerContent, "JSC::JSValue ${getter}(JSC::ExecState*, JSC::JSValue, const JSC::Identifier&);\n");
1125             push(@headerContent, "#endif\n") if $conditional;
1126         }
1127     }
1128
1129     my $conditionalString = GenerateConditionalString($dataNode);
1130     push(@headerContent, "\n} // namespace WebCore\n\n");
1131     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
1132     push(@headerContent, "#endif\n");
1133
1134     # - Generate dependencies.
1135     if ($writeDependencies && @ancestorInterfaceNames) {
1136         push(@depsContent, "$className.h : ", join(" ", map { "$_.idl" } @ancestorInterfaceNames), "\n");
1137         push(@depsContent, map { "$_.idl :\n" } @ancestorInterfaceNames); 
1138     }
1139 }
1140
1141 sub GenerateAttributesHashTable($$)
1142 {
1143     my ($object, $dataNode) = @_;
1144
1145     # FIXME: These should be functions on $dataNode.
1146     my $interfaceName = $dataNode->name;
1147     my $className = "JS$interfaceName";
1148     
1149     # - Add all attributes in a hashtable definition
1150     my $numAttributes = @{$dataNode->attributes};
1151     $numAttributes++ if !$dataNode->extendedAttributes->{"OmitConstructor"};
1152
1153     return 0  if !$numAttributes;
1154
1155     my $hashSize = $numAttributes;
1156     my $hashName = $className . "Table";
1157
1158     my @hashKeys = ();
1159     my @hashSpecials = ();
1160     my @hashValue1 = ();
1161     my @hashValue2 = ();
1162     my %conditionals = ();
1163
1164     my @entries = ();
1165
1166     foreach my $attribute (@{$dataNode->attributes}) {
1167         my $name = $attribute->signature->name;
1168         push(@hashKeys, $name);
1169
1170         my @specials = ();
1171         push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
1172         push(@specials, "DontEnum") if $attribute->signature->extendedAttributes->{"DontEnum"};
1173         push(@specials, "ReadOnly") if $attribute->type =~ /readonly/;
1174         my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1175         push(@hashSpecials, $special);
1176
1177         my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1178         push(@hashValue1, $getter);
1179
1180         if ($attribute->type =~ /readonly/) {
1181             push(@hashValue2, "0");
1182         } else {
1183             my $setter = "setJS" . $interfaceName . $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1184             push(@hashValue2, $setter);
1185         }
1186
1187         my $conditional = $attribute->signature->extendedAttributes->{"Conditional"};
1188         if ($conditional) {
1189             $conditionals{$name} = $conditional;
1190         }
1191     }
1192
1193     if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
1194         push(@hashKeys, "constructor");
1195         my $getter = "js" . $interfaceName . "Constructor";
1196         push(@hashValue1, $getter);
1197         if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
1198             my $setter = "setJS" . $interfaceName . "Constructor";
1199             push(@hashValue2, $setter);
1200             push(@hashSpecials, "DontEnum | DontDelete");
1201         } else {            
1202             push(@hashValue2, "0");
1203             push(@hashSpecials, "DontEnum | ReadOnly");
1204         }
1205     }
1206
1207     $object->GenerateHashTable($hashName, $hashSize,
1208                                \@hashKeys, \@hashSpecials,
1209                                \@hashValue1, \@hashValue2,
1210                                \%conditionals);
1211     return $numAttributes;
1212 }
1213
1214 sub GenerateParametersCheckExpression
1215 {
1216     my $numParameters = shift;
1217     my $function = shift;
1218
1219     my @andExpression = ();
1220     push(@andExpression, "argsCount == $numParameters");
1221     my $parameterIndex = 0;
1222     my %usedArguments = ();
1223     foreach my $parameter (@{$function->parameters}) {
1224         last if $parameterIndex >= $numParameters;
1225         my $value = "arg$parameterIndex";
1226         my $type = $codeGenerator->StripModule($parameter->type);
1227
1228         # Only DOMString or wrapper types are checked.
1229         # For DOMString, Null, Undefined and any Object are accepted too, as
1230         # these are acceptable values for a DOMString argument (any Object can
1231         # be converted to a string via .toString).
1232         if ($codeGenerator->IsStringType($type)) {
1233             push(@andExpression, "(${value}.isUndefinedOrNull() || ${value}.isString() || ${value}.isObject())");
1234             $usedArguments{$parameterIndex} = 1;
1235         } elsif ($parameter->extendedAttributes->{"Callback"}) {
1236             # For Callbacks only checks if the value is null or object.
1237             push(@andExpression, "(${value}.isNull() || ${value}.isObject())");
1238             $usedArguments{$parameterIndex} = 1;
1239         } elsif (IsArrayType($type)) {
1240             # FIXME: Add proper support for T[], T[]?, sequence<T>
1241             push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(&JSArray::s_info)))");
1242             $usedArguments{$parameterIndex} = 1;
1243         } elsif (!IsNativeType($type)) {
1244             push(@andExpression, "(${value}.isNull() || (${value}.isObject() && asObject(${value})->inherits(&JS${type}::s_info)))");
1245             $usedArguments{$parameterIndex} = 1;
1246         }
1247         $parameterIndex++;
1248     }
1249     my $res = join(" && ", @andExpression);
1250     $res = "($res)" if @andExpression > 1;
1251     return ($res, keys %usedArguments);
1252 }
1253
1254 sub GenerateFunctionParametersCheck
1255 {
1256     my $function = shift;
1257
1258     my @orExpression = ();
1259     my $numParameters = 0;
1260     my @neededArguments = ();
1261
1262     foreach my $parameter (@{$function->parameters}) {
1263         if ($parameter->extendedAttributes->{"Optional"}) {
1264             my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1265             push(@orExpression, $expression);
1266             push(@neededArguments, @usedArguments);
1267         }
1268         $numParameters++;
1269     }
1270     my ($expression, @usedArguments) = GenerateParametersCheckExpression($numParameters, $function);
1271     push(@orExpression, $expression);
1272     push(@neededArguments, @usedArguments);
1273     return (join(" || ", @orExpression), @neededArguments);
1274 }
1275
1276 sub GenerateOverloadedFunction
1277 {
1278     my $function = shift;
1279     my $dataNode = shift;
1280     my $implClassName = shift;
1281
1282     # Generate code for choosing the correct overload to call. Overloads are
1283     # chosen based on the total number of arguments passed and the type of
1284     # values passed in non-primitive argument slots. When more than a single
1285     # overload is applicable, precedence is given according to the order of
1286     # declaration in the IDL.
1287
1288     my $kind = $function->isStatic ? "Constructor" : "Prototype";
1289     my $functionName = "js${implClassName}${kind}Function" . $codeGenerator->WK_ucfirst($function->signature->name);
1290
1291     push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
1292     push(@implContent, <<END);
1293 {
1294     size_t argsCount = exec->argumentCount();
1295 END
1296
1297     my %fetchedArguments = ();
1298
1299     foreach my $overload (@{$function->{overloads}}) {
1300         my ($parametersCheck, @neededArguments) = GenerateFunctionParametersCheck($overload);
1301
1302         foreach my $parameterIndex (@neededArguments) {
1303             next if exists $fetchedArguments{$parameterIndex};
1304             push(@implContent, "    JSValue arg$parameterIndex(exec->argument($parameterIndex));\n");
1305             $fetchedArguments{$parameterIndex} = 1;
1306         }
1307
1308         push(@implContent, "    if ($parametersCheck)\n");
1309         push(@implContent, "        return ${functionName}$overload->{overloadIndex}(exec);\n");
1310     }
1311     push(@implContent, <<END);
1312     return throwVMTypeError(exec);
1313 }
1314
1315 END
1316 }
1317
1318 sub GenerateImplementation
1319 {
1320     my ($object, $dataNode) = @_;
1321
1322     my $interfaceName = $dataNode->name;
1323     my $className = "JS$interfaceName";
1324     my $implClassName = $interfaceName;
1325
1326     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
1327     my $hasRealParent = @{$dataNode->parents} > 0;
1328     my $hasParent = $hasLegacyParent || $hasRealParent;
1329     my $parentClassName = GetParentClassName($dataNode);
1330     my $visibleClassName = GetVisibleClassName($interfaceName);
1331     my $eventTarget = $dataNode->extendedAttributes->{"EventTarget"};
1332     my $needsMarkChildren = $dataNode->extendedAttributes->{"CustomMarkFunction"} || $dataNode->extendedAttributes->{"EventTarget"};
1333
1334     # - Add default header template
1335     push(@implContentHeader, GenerateImplementationContentHeader($dataNode));
1336
1337     AddIncludesForSVGAnimatedType($interfaceName) if $className =~ /^JSSVGAnimated/;
1338
1339     $implIncludes{"<wtf/GetPtr.h>"} = 1;
1340     $implIncludes{"<runtime/PropertyNameArray.h>"} = 1 if $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"};
1341
1342     AddIncludesForTypeInImpl($interfaceName);
1343
1344     @implContent = ();
1345
1346     push(@implContent, "\nusing namespace JSC;\n\n");
1347     push(@implContent, "namespace WebCore {\n\n");
1348
1349     push(@implContent, "ASSERT_CLASS_FITS_IN_CELL($className);\n");
1350     if ($interfaceName ne "DOMWindow" && !$dataNode->extendedAttributes->{"IsWorkerContext"}) {
1351         push(@implContent, "ASSERT_HAS_TRIVIAL_DESTRUCTOR($className);\n\n");
1352     }
1353
1354     my $numAttributes = GenerateAttributesHashTable($object, $dataNode);
1355
1356     my $numConstants = @{$dataNode->constants};
1357     my $numFunctions = @{$dataNode->functions};
1358
1359     # - Add all constants
1360     if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
1361         my $hashSize = $numConstants;
1362         my $hashName = $className . "ConstructorTable";
1363
1364         my @hashKeys = ();
1365         my @hashValue1 = ();
1366         my @hashValue2 = ();
1367         my @hashSpecials = ();
1368         my %conditionals = ();
1369
1370         # FIXME: we should not need a function for every constant.
1371         foreach my $constant (@{$dataNode->constants}) {
1372             my $name = $constant->name;
1373             push(@hashKeys, $name);
1374             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1375             push(@hashValue1, $getter);
1376             push(@hashValue2, "0");
1377             push(@hashSpecials, "DontDelete | ReadOnly");
1378
1379             my $conditional = $constant->extendedAttributes->{"Conditional"};
1380             if ($conditional) {
1381                 $conditionals{$name} = $conditional;
1382             }
1383         }
1384
1385         foreach my $function (@{$dataNode->functions}) {
1386             next unless ($function->isStatic);
1387             next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1388             my $name = $function->signature->name;
1389             push(@hashKeys, $name);
1390
1391             my $functionName = GetFunctionName($className, $function);
1392             push(@hashValue1, $functionName);
1393
1394             my $numParameters = @{$function->parameters};
1395             push(@hashValue2, $numParameters);
1396
1397             my @specials = ();
1398             push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
1399             push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"DontEnum"};
1400             push(@specials, "JSC::Function");
1401             my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1402             push(@hashSpecials, $special);
1403
1404             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1405             if ($conditional) {
1406                 $conditionals{$name} = $conditional;
1407             }
1408         }
1409
1410         $object->GenerateHashTable($hashName, $hashSize,
1411                                    \@hashKeys, \@hashSpecials,
1412                                    \@hashValue1, \@hashValue2,
1413                                    \%conditionals);
1414
1415         push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode));
1416
1417         my $protoClassName = "${className}Prototype";
1418         GenerateConstructorDefinition(\@implContent, $className, $protoClassName, $interfaceName, $visibleClassName, $dataNode);
1419         if ($dataNode->extendedAttributes->{"NamedConstructor"}) {
1420             GenerateConstructorDefinition(\@implContent, $className, $protoClassName, $interfaceName, $dataNode->extendedAttributes->{"NamedConstructor"}, $dataNode, "GeneratingNamedConstructor");
1421         }
1422     }
1423
1424     # - Add functions and constants to a hashtable definition
1425     my $hashSize = $numFunctions + $numConstants;
1426     my $hashName = $className . "PrototypeTable";
1427
1428     my @hashKeys = ();
1429     my @hashValue1 = ();
1430     my @hashValue2 = ();
1431     my @hashSpecials = ();
1432     my %conditionals = ();
1433
1434     # FIXME: we should not need a function for every constant.
1435     foreach my $constant (@{$dataNode->constants}) {
1436         my $name = $constant->name;
1437         push(@hashKeys, $name);
1438         my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($name);
1439         push(@hashValue1, $getter);
1440         push(@hashValue2, "0");
1441         push(@hashSpecials, "DontDelete | ReadOnly");
1442
1443         my $conditional = $constant->extendedAttributes->{"Conditional"};
1444         if ($conditional) {
1445             $conditionals{$name} = $conditional;
1446         }
1447     }
1448
1449     foreach my $function (@{$dataNode->functions}) {
1450         next if ($function->isStatic);
1451         next if $function->{overloadIndex} && $function->{overloadIndex} > 1;
1452         my $name = $function->signature->name;
1453         push(@hashKeys, $name);
1454
1455         my $functionName = GetFunctionName($className, $function);
1456         push(@hashValue1, $functionName);
1457
1458         my $numParameters = @{$function->parameters};
1459         push(@hashValue2, $numParameters);
1460
1461         my @specials = ();
1462         push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
1463         push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"DontEnum"};
1464         push(@specials, "JSC::Function");
1465         my $special = (@specials > 0) ? join(" | ", @specials) : "0";
1466         push(@hashSpecials, $special);
1467
1468         my $conditional = $function->signature->extendedAttributes->{"Conditional"};
1469         if ($conditional) {
1470             $conditionals{$name} = $conditional;
1471         }
1472     }
1473
1474     $object->GenerateHashTable($hashName, $hashSize,
1475                                \@hashKeys, \@hashSpecials,
1476                                \@hashValue1, \@hashValue2,
1477                                \%conditionals);
1478
1479     if ($dataNode->extendedAttributes->{"NoStaticTables"}) {
1480         push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n");
1481         push(@implContent, "{\n");
1482         push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}PrototypeTable);\n");
1483         push(@implContent, "}\n\n");
1484         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &Base::s_info, 0, get${className}PrototypeTable, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1485     } else {
1486         push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &Base::s_info, &${className}PrototypeTable, 0, CREATE_METHOD_TABLE(${className}Prototype) };\n\n");
1487     }
1488     if ($interfaceName ne "DOMWindow" && !$dataNode->extendedAttributes->{"IsWorkerContext"}) {
1489         push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec, JSGlobalObject* globalObject)\n");
1490         push(@implContent, "{\n");
1491         push(@implContent, "    return getDOMPrototype<${className}>(exec, globalObject);\n");
1492         push(@implContent, "}\n\n");
1493     }
1494
1495     if ($numConstants > 0 || $numFunctions > 0) {
1496         push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
1497         push(@implContent, "{\n");
1498         push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
1499
1500         if ($numConstants eq 0 && $numFunctions eq 0) {
1501             push(@implContent, "    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);\n");        
1502         } elsif ($numConstants eq 0) {
1503             push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1504         } elsif ($numFunctions eq 0) {
1505             push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1506         } else {
1507             push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, slot);\n");
1508         }
1509         push(@implContent, "}\n\n");
1510
1511         push(@implContent, "bool ${className}Prototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
1512         push(@implContent, "{\n");
1513         push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(object);\n");
1514
1515         if ($numConstants eq 0 && $numFunctions eq 0) {
1516             push(@implContent, "    return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);\n");        
1517         } elsif ($numConstants eq 0) {
1518             push(@implContent, "    return getStaticFunctionDescriptor<JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1519         } elsif ($numFunctions eq 0) {
1520             push(@implContent, "    return getStaticValueDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1521         } else {
1522             push(@implContent, "    return getStaticPropertyDescriptor<${className}Prototype, JSObject>(exec, " . prototypeHashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, propertyName, descriptor);\n");
1523         }
1524         push(@implContent, "}\n\n");
1525     }
1526
1527     if ($dataNode->extendedAttributes->{"DelegatingPrototypePutFunction"}) {
1528         push(@implContent, "void ${className}Prototype::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)\n");
1529         push(@implContent, "{\n");
1530         push(@implContent, "    ${className}Prototype* thisObject = jsCast<${className}Prototype*>(cell);\n");
1531         push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
1532         push(@implContent, "        return;\n");
1533         push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
1534         push(@implContent, "}\n\n");
1535     }
1536
1537     # - Initialize static ClassInfo object
1538     if ($numAttributes > 0 && $dataNode->extendedAttributes->{"NoStaticTables"}) {
1539         push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n");
1540         push(@implContent, "{\n");
1541         push(@implContent, "    return getHashTableForGlobalData(exec->globalData(), &${className}Table);\n");
1542         push(@implContent, "}\n\n");
1543     }
1544
1545     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleClassName}\", &Base::s_info, ");
1546
1547     if ($numAttributes > 0 && !$dataNode->extendedAttributes->{"NoStaticTables"}) {
1548         push(@implContent, "&${className}Table");
1549     } else {
1550         push(@implContent, "0");
1551     }
1552     if ($numAttributes > 0 && $dataNode->extendedAttributes->{"NoStaticTables"}) {
1553         push(@implContent, ", get${className}Table ");
1554     } else {
1555         push(@implContent, ", 0 ");
1556     }
1557     push(@implContent, ", CREATE_METHOD_TABLE($className) };\n\n");
1558
1559     my $implType = $implClassName;
1560     my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implType);
1561     $implType = $svgNativeType if $svgNativeType;
1562
1563     my $svgPropertyOrListPropertyType;
1564     $svgPropertyOrListPropertyType = $svgPropertyType if $svgPropertyType;
1565     $svgPropertyOrListPropertyType = $svgListPropertyType if $svgListPropertyType;
1566
1567     # Constructor
1568     if ($interfaceName eq "DOMWindow") {
1569         AddIncludesForTypeInImpl("JSDOMWindowShell");
1570         push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
1571         push(@implContent, "    : $parentClassName(globalData, structure, impl, shell)\n");
1572         push(@implContent, "{\n");
1573         push(@implContent, "}\n\n");
1574     } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
1575         AddIncludesForTypeInImpl($interfaceName);
1576         push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl)\n");
1577         push(@implContent, "    : $parentClassName(globalData, structure, impl)\n");
1578         push(@implContent, "{\n");
1579         push(@implContent, "}\n\n");
1580     } else {
1581         push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n");
1582         if ($hasParent) {
1583             push(@implContent, "    : $parentClassName(structure, globalObject, impl)\n");
1584         } else {
1585             push(@implContent, "    : $parentClassName(structure, globalObject)\n");
1586             push(@implContent, "    , m_impl(impl.leakRef())\n");
1587         }
1588         push(@implContent, "{\n");
1589         push(@implContent, "}\n\n");
1590
1591         push(@implContent, "void ${className}::finishCreation(JSGlobalData& globalData)\n");
1592         push(@implContent, "{\n");
1593         push(@implContent, "    Base::finishCreation(globalData);\n");
1594         if (IsTypedArrayType($implType) and ($implType ne "ArrayBufferView") and ($implType ne "ArrayBuffer")) {
1595             push(@implContent, "    TypedArrayDescriptor descriptor(&${className}::s_info, OBJECT_OFFSETOF(${className}, m_storage), OBJECT_OFFSETOF(${className}, m_storageLength));\n");
1596             push(@implContent, "    globalData.registerTypedArrayDescriptor(impl(), descriptor);\n");
1597             push(@implContent, "    m_storage = impl()->data();\n");
1598             push(@implContent, "    m_storageLength = impl()->length();\n");
1599         }
1600         push(@implContent, "    ASSERT(inherits(&s_info));\n");
1601         push(@implContent, "}\n\n");
1602     }
1603
1604     if (!$dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"}) {
1605         push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n");
1606         push(@implContent, "{\n");
1607         if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
1608             push(@implContent, "    return ${className}Prototype::create(exec->globalData(), globalObject, ${className}Prototype::createStructure(exec->globalData(), globalObject, ${parentClassName}Prototype::self(exec, globalObject)));\n");
1609         } else {
1610             push(@implContent, "    return ${className}Prototype::create(exec->globalData(), globalObject, ${className}Prototype::createStructure(globalObject->globalData(), globalObject, globalObject->objectPrototype()));\n");
1611         }
1612         push(@implContent, "}\n\n");
1613     }
1614
1615     if (!$hasParent) {
1616         # FIXME: This destroy function should not be necessary, as 
1617         # a finalizer should be called for each DOM object wrapper.
1618         # However, that seems not to be the case, so this has been
1619         # added back to avoid leaking while we figure out why the
1620         # finalizers are not always getting called. The work tracking
1621         # the finalizer issue is being tracked in http://webkit.org/b/75451
1622         push(@implContent, "void ${className}::destroy(JSC::JSCell* cell)\n");
1623         push(@implContent, "{\n");
1624         push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1625         push(@implContent, "    thisObject->releaseImplIfNotNull();\n");
1626         push(@implContent, "}\n\n");
1627     }
1628
1629     my $hasGetter = $numAttributes > 0 
1630                  || !$dataNode->extendedAttributes->{"OmitConstructor"} 
1631                  || $dataNode->extendedAttributes->{"HasIndexGetter"}
1632                  || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}
1633                  || $dataNode->extendedAttributes->{"DelegatingGetOwnPropertySlot"}
1634                  || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
1635                  || $dataNode->extendedAttributes->{"HasNameGetter"}
1636                  || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
1637
1638     # Attributes
1639     if ($hasGetter) {
1640         if (!$dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"} && !$dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
1641             push(@implContent, "bool ${className}::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
1642             push(@implContent, "{\n");
1643             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1644             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1645             push(@implContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0));
1646             push(@implContent, "}\n\n");
1647             push(@implContent, "bool ${className}::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n");
1648             push(@implContent, "{\n");
1649             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
1650             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1651             push(@implContent, GenerateGetOwnPropertyDescriptorBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0));
1652             push(@implContent, "}\n\n");
1653         }
1654
1655         if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) 
1656                 && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
1657             push(@implContent, "bool ${className}::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)\n");
1658             push(@implContent, "{\n");
1659             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1660             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1661             push(@implContent, "    if (propertyName < static_cast<$implClassName*>(thisObject->impl())->length()) {\n");
1662             if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
1663                 push(@implContent, "        slot.setValue(thisObject->getByIndex(exec, propertyName));\n");
1664             } else {
1665                 push(@implContent, "        slot.setCustomIndex(thisObject, propertyName, thisObject->indexGetter);\n");
1666             }
1667             push(@implContent, "        return true;\n");
1668             push(@implContent, "    }\n");
1669             push(@implContent, "    return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);\n");
1670             push(@implContent, "}\n\n");
1671         }
1672         
1673         if ($numAttributes > 0) {
1674             foreach my $attribute (@{$dataNode->attributes}) {
1675                 my $name = $attribute->signature->name;
1676                 my $type = $codeGenerator->StripModule($attribute->signature->type);
1677                 my $getFunctionName = "js" . $interfaceName .  $codeGenerator->WK_ucfirst($attribute->signature->name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1678                 my $implGetterFunctionName = $codeGenerator->WK_lcfirst($name);
1679
1680                 my $attributeConditionalString = GenerateConditionalString($attribute->signature);
1681                 push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
1682
1683                 push(@implContent, "JSValue ${getFunctionName}(ExecState* exec, JSValue slotBase, const Identifier&)\n");
1684                 push(@implContent, "{\n");
1685                 push(@implContent, "    ${className}* castedThis = static_cast<$className*>(asObject(slotBase));\n");
1686
1687                 if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1688                     $needsMarkChildren = 1;
1689                 }
1690
1691                 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && 
1692                         !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"} &&
1693                         !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurityOnGet"}) {
1694                     push(@implContent, "    if (!castedThis->allowsAccessFrom(exec))\n");
1695                     push(@implContent, "        return jsUndefined();\n");
1696                 }
1697
1698                 if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomGetter"} || $attribute->signature->extendedAttributes->{"JSCCustomGetter"}) {
1699                     push(@implContent, "    return castedThis->$implGetterFunctionName(exec);\n");
1700                 } elsif ($attribute->signature->extendedAttributes->{"CheckAccessToNode"}) {
1701                     $implIncludes{"JSDOMBinding.h"} = 1;
1702                     push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(castedThis->impl());\n");
1703                     push(@implContent, "    return allowAccessToNode(exec, impl->" . $attribute->signature->name . "()) ? " . NativeToJSValue($attribute->signature, 0, $implClassName, "impl->$implGetterFunctionName()", "castedThis") . " : jsUndefined();\n");
1704                 } elsif ($type eq "EventListener") {
1705                     $implIncludes{"EventListener.h"} = 1;
1706                     push(@implContent, "    UNUSED_PARAM(exec);\n");
1707                     push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(castedThis->impl());\n");
1708                     push(@implContent, "    if (EventListener* listener = impl->$implGetterFunctionName()) {\n");
1709                     push(@implContent, "        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {\n");
1710                     if ($implClassName eq "Document" || $implClassName eq "WorkerContext" || $implClassName eq "SharedWorkerContext" || $implClassName eq "DedicatedWorkerContext") {
1711                         push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(impl))\n");
1712                     } else {
1713                         push(@implContent, "            if (JSObject* jsFunction = jsListener->jsFunction(impl->scriptExecutionContext()))\n");
1714                     }
1715                     push(@implContent, "                return jsFunction;\n");
1716                     push(@implContent, "        }\n");
1717                     push(@implContent, "    }\n");
1718                     push(@implContent, "    return jsNull();\n");
1719                 } elsif ($attribute->signature->type =~ /Constructor$/) {
1720                     my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
1721                     $constructorType =~ s/Constructor$//;
1722                     # Constructor attribute is only used by DOMWindow.idl, so it's correct to pass castedThis as the global object
1723                     # Once JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject()
1724                     push(@implContent, "    return JS" . $constructorType . "::getConstructor(exec, castedThis);\n");
1725                 } elsif (!@{$attribute->getterExceptions}) {
1726                     my $callWith = $attribute->signature->extendedAttributes->{"CallWith"};
1727                     my $callWithArg = "";
1728
1729                     push(@implContent, "    UNUSED_PARAM(exec);\n") if (!$callWith);
1730
1731                     my $cacheIndex = 0;
1732                     if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
1733                         $cacheIndex = $currentCachedAttribute;
1734                         $currentCachedAttribute++;
1735                         push(@implContent, "    if (JSValue cachedValue = castedThis->m_" . $attribute->signature->name . ".get())\n");
1736                         push(@implContent, "        return cachedValue;\n");
1737                     }
1738
1739                     if ($callWith) {
1740                         $callWithArg = GenerateCallWith($callWith, \@implContent, "jsUndefined()");
1741                     }
1742
1743                     if ($svgListPropertyType) {
1744                         push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "castedThis->impl()->$implGetterFunctionName($callWithArg)", "castedThis") . ";\n");
1745                     } elsif ($svgPropertyOrListPropertyType) {
1746                         push(@implContent, "    $svgPropertyOrListPropertyType& impl = castedThis->impl()->propertyReference();\n");
1747                         if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
1748                             push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "impl", "castedThis") . ";\n");
1749                         } else {
1750                             push(@implContent, "    JSValue result =  " . NativeToJSValue($attribute->signature, 0, $implClassName, "impl.$implGetterFunctionName($callWithArg)", "castedThis") . ";\n");
1751
1752                         }
1753                     } else {
1754                         my ($functionName, @arguments) = $codeGenerator->GetterExpression(\%implIncludes, $interfaceName, $attribute);
1755                         if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
1756                             my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
1757                             $implIncludes{"${implementedBy}.h"} = 1;
1758                             $functionName = "${implementedBy}::${functionName}";
1759                             unshift(@arguments, "impl");
1760                         } else {
1761                             $functionName = "impl->${functionName}";
1762                         }
1763
1764                         if ($callWith) {
1765                             unshift(@arguments, $callWithArg);
1766                         }
1767
1768                         my $jsType = NativeToJSValue($attribute->signature, 0, $implClassName, "${functionName}(" . join(", ", @arguments) . ")", "castedThis");
1769                         push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(castedThis->impl());\n");
1770                         if ($codeGenerator->IsSVGAnimatedType($type)) {
1771                             push(@implContent, "    RefPtr<$type> obj = $jsType;\n");
1772                             push(@implContent, "    JSValue result =  toJS(exec, castedThis->globalObject(), obj.get());\n");
1773                         } else {
1774                             push(@implContent, "    JSValue result = $jsType;\n");
1775                         }
1776                     }
1777
1778                     push(@implContent, "    castedThis->m_" . $attribute->signature->name . ".set(exec->globalData(), castedThis, result);\n") if ($attribute->signature->extendedAttributes->{"CachedAttribute"});
1779                     push(@implContent, "    return result;\n");
1780
1781                 } else {
1782                     my $callWith = $attribute->signature->extendedAttributes->{"CallWith"};
1783                     my @arguments = ("ec");
1784
1785                     push(@implContent, "    ExceptionCode ec = 0;\n");                    
1786
1787                     if ($callWith) {
1788                         unshift(@arguments, GenerateCallWith($callWith, \@implContent, "jsUndefined()"));
1789                     }
1790
1791                     if ($svgPropertyOrListPropertyType) {
1792                         push(@implContent, "    $svgPropertyOrListPropertyType impl(*castedThis->impl());\n");
1793                         push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $implClassName, "impl.$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
1794                     } else {
1795                         push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(castedThis->impl());\n");
1796                         push(@implContent, "    JSC::JSValue result = " . NativeToJSValue($attribute->signature, 0, $implClassName, "impl->$implGetterFunctionName(" . join(", ", @arguments) . ")", "castedThis") . ";\n");
1797                     }
1798
1799                     push(@implContent, "    setDOMException(exec, ec);\n");
1800                     push(@implContent, "    return result;\n");
1801                 }
1802
1803                 push(@implContent, "}\n\n");
1804
1805                 push(@implContent, "#endif\n") if $attributeConditionalString;
1806
1807                 push(@implContent, "\n");
1808             }
1809
1810             if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
1811                 my $constructorFunctionName = "js" . $interfaceName . "Constructor";
1812
1813                 push(@implContent, "JSValue ${constructorFunctionName}(ExecState* exec, JSValue slotBase, const Identifier&)\n");
1814                 push(@implContent, "{\n");
1815                 push(@implContent, "    ${className}* domObject = static_cast<$className*>(asObject(slotBase));\n");
1816
1817                 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
1818                     push(@implContent, "    if (!domObject->allowsAccessFrom(exec))\n");
1819                     push(@implContent, "        return jsUndefined();\n");
1820                 }
1821
1822                 push(@implContent, "    return ${className}::getConstructor(exec, domObject->globalObject());\n");
1823                 push(@implContent, "}\n\n");
1824             }
1825         }
1826
1827         # Check if we have any writable attributes
1828         my $hasReadWriteProperties = 0;
1829         foreach my $attribute (@{$dataNode->attributes}) {
1830             $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
1831         }
1832
1833         my $hasSetter = $hasReadWriteProperties
1834                      || $dataNode->extendedAttributes->{"DelegatingPutFunction"}
1835                      || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
1836
1837         if ($hasSetter) {
1838             if (!$dataNode->extendedAttributes->{"CustomPutFunction"}) {
1839                 push(@implContent, "void ${className}::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)\n");
1840                 push(@implContent, "{\n");
1841                 push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1842                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1843                 if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1844                     push(@implContent, "    bool ok;\n");
1845                     push(@implContent, "    unsigned index = propertyName.toUInt32(ok);\n");
1846                     push(@implContent, "    if (ok) {\n");
1847                     push(@implContent, "        thisObject->indexSetter(exec, index, value);\n");
1848                     push(@implContent, "        return;\n");
1849                     push(@implContent, "    }\n");
1850                 }
1851                 if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) {
1852                     push(@implContent, "    if (thisObject->putDelegate(exec, propertyName, value, slot))\n");
1853                     push(@implContent, "        return;\n");
1854                 }
1855
1856                 if ($hasReadWriteProperties) {
1857                     push(@implContent, "    lookupPut<$className, Base>(exec, propertyName, value, " . hashTableAccessor($dataNode->extendedAttributes->{"NoStaticTables"}, $className) . ", thisObject, slot);\n");
1858                 } else {
1859                     push(@implContent, "    Base::put(thisObject, exec, propertyName, value, slot);\n");
1860                 }
1861                 push(@implContent, "}\n\n");
1862             }
1863
1864             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1865                 push(@implContent, "void ${className}::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value)\n");
1866                 push(@implContent, "{\n");
1867                 push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
1868                 push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
1869                 push(@implContent, "    thisObject->indexSetter(exec, propertyName, value);\n");
1870                 push(@implContent, "    return;\n");
1871                 push(@implContent, "}\n\n");
1872             }
1873
1874             if ($hasReadWriteProperties) {
1875                 foreach my $attribute (@{$dataNode->attributes}) {
1876                     if ($attribute->type !~ /^readonly/) {
1877                         my $name = $attribute->signature->name;
1878                         my $type = $codeGenerator->StripModule($attribute->signature->type);
1879                         my $putFunctionName = "setJS" . $interfaceName .  $codeGenerator->WK_ucfirst($name) . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "");
1880                         my $implSetterFunctionName = $codeGenerator->WK_ucfirst($name);
1881
1882                         my $attributeConditionalString = GenerateConditionalString($attribute->signature);
1883                         push(@implContent, "#if ${attributeConditionalString}\n") if $attributeConditionalString;
1884
1885                         push(@implContent, "void ${putFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n");
1886                         push(@implContent, "{\n");
1887
1888                         if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1889                             if ($interfaceName eq "DOMWindow") {
1890                                 push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
1891                             } else {
1892                                 push(@implContent, "    if (!allowAccessToFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
1893                             }
1894                             push(@implContent, "        return;\n");
1895                         }
1896
1897                         if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"JSCCustom"} || $attribute->signature->extendedAttributes->{"CustomSetter"} || $attribute->signature->extendedAttributes->{"JSCCustomSetter"}) {
1898                             push(@implContent, "    static_cast<$className*>(thisObject)->set$implSetterFunctionName(exec, value);\n");
1899                         } elsif ($type eq "EventListener") {
1900                             $implIncludes{"JSEventListener.h"} = 1;
1901                             push(@implContent, "    UNUSED_PARAM(exec);\n");
1902                             push(@implContent, "    ${className}* castedThis = static_cast<${className}*>(thisObject);\n");
1903                             my $windowEventListener = $attribute->signature->extendedAttributes->{"WindowEventListener"};
1904                             if ($windowEventListener) {
1905                                 push(@implContent, "    JSDOMGlobalObject* globalObject = castedThis->globalObject();\n");
1906                             }
1907                             push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(castedThis->impl());\n");
1908                             if ((($interfaceName eq "DOMWindow") or ($interfaceName eq "WorkerContext")) and $name eq "onerror") {
1909                                 $implIncludes{"JSErrorHandler.h"} = 1;
1910                                 push(@implContent, "    impl->set$implSetterFunctionName(createJSErrorHandler(exec, value, thisObject));\n");
1911                             } else {
1912                                 push(@implContent, GenerateAttributeEventListenerCall($className, $implSetterFunctionName, $windowEventListener));
1913                             }
1914                         } elsif ($attribute->signature->type =~ /Constructor$/) {
1915                             my $constructorType = $attribute->signature->type;
1916                             $constructorType =~ s/Constructor$//;
1917                             # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor.
1918                             # We do not generate the header file for NamedConstructor of class XXXX,
1919                             # since we generate the NamedConstructor declaration into the header file of class XXXX.
1920                             if ($constructorType ne "DOMObject" and $constructorType !~ /Constructor$/) {
1921                                 AddToImplIncludes("JS" . $constructorType . ".h", $attribute->signature->extendedAttributes->{"Conditional"});
1922                             }
1923                             push(@implContent, "    // Shadowing a built-in constructor\n");
1924                             if ($interfaceName eq "DOMWindow" && $className eq "JSblah") {
1925                                 # FIXME: This branch never executes and should be removed.
1926                                 push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), exec->propertyNames().constructor, value);\n");
1927                             } else {
1928                                 push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
1929                             }
1930                         } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
1931                             push(@implContent, "    // Shadowing a built-in object\n");
1932                             push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n");
1933                         } else {
1934                             push(@implContent, "    $className* castedThis = static_cast<$className*>(thisObject);\n");
1935                             push(@implContent, "    $implType* impl = static_cast<$implType*>(castedThis->impl());\n");
1936                             push(@implContent, "    ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
1937
1938                             # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an
1939                             # interface type, then if the incoming value does not implement that interface, a TypeError
1940                             # is thrown rather than silently passing NULL to the C++ code.
1941                             # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to
1942                             # both strings and numbers, so do not throw TypeError if the attribute is of these types.
1943                             if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) {
1944                                 $implIncludes{"<runtime/Error.h>"} = 1;
1945
1946                                 my $argType = $attribute->signature->type;
1947                                 if (!IsNativeType($argType)) {
1948                                     push(@implContent, "    if (!value.isUndefinedOrNull() && !value.inherits(&JS${argType}::s_info)) {\n");
1949                                     push(@implContent, "        throwVMTypeError(exec);\n");
1950                                     push(@implContent, "        return;\n");
1951                                     push(@implContent, "    };\n");
1952                                 }
1953                             }
1954
1955                             my $nativeValue = JSValueToNative($attribute->signature, "value");
1956                             if ($svgPropertyOrListPropertyType) {
1957                                 if ($svgPropertyType) {
1958                                     push(@implContent, "    if (impl->role() == AnimValRole) {\n");
1959                                     push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
1960                                     push(@implContent, "        return;\n");
1961                                     push(@implContent, "    }\n");
1962                                     $implIncludes{"ExceptionCode.h"} = 1;
1963                                 }
1964                                 push(@implContent, "    $svgPropertyOrListPropertyType& podImpl = impl->propertyReference();\n");
1965                                 if ($svgPropertyOrListPropertyType eq "float") { # Special case for JSSVGNumber
1966                                     push(@implContent, "    podImpl = $nativeValue;\n");
1967                                 } else {
1968                                     push(@implContent, "    podImpl.set$implSetterFunctionName($nativeValue");
1969                                     push(@implContent, ", ec") if @{$attribute->setterExceptions};
1970                                     push(@implContent, ");\n");
1971                                     push(@implContent, "    setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
1972                                 }
1973                                 if ($svgPropertyType) {
1974                                     if (@{$attribute->setterExceptions}) {
1975                                         push(@implContent, "    if (!ec)\n"); 
1976                                         push(@implContent, "        impl->commitChange();\n");
1977                                     } else {
1978                                         push(@implContent, "    impl->commitChange();\n");
1979                                     }
1980                                 }
1981                             } else {
1982                                 my ($functionName, @arguments) = $codeGenerator->SetterExpression(\%implIncludes, $interfaceName, $attribute);
1983                                 push(@arguments, $nativeValue);
1984                                 if ($attribute->signature->extendedAttributes->{"ImplementedBy"}) {
1985                                     my $implementedBy = $attribute->signature->extendedAttributes->{"ImplementedBy"};
1986                                     $implIncludes{"${implementedBy}.h"} = 1;
1987                                     unshift(@arguments, "impl");
1988                                     $functionName = "${implementedBy}::${functionName}";
1989                                 } else {
1990                                     $functionName = "impl->${functionName}";
1991                                 }
1992
1993                                 my $callWith = $attribute->signature->extendedAttributes->{"CallWith"};
1994                                 if ($callWith) {
1995                                     unshift(@arguments, GenerateCallWith($callWith, \@implContent, ""));
1996                                 }
1997
1998                                 push(@arguments, "ec") if @{$attribute->setterExceptions};
1999                                 push(@implContent, "    ${functionName}(" . join(", ", @arguments) . ");\n");
2000                                 push(@implContent, "    setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
2001                             }
2002                         }
2003
2004                         push(@implContent, "}\n\n");
2005                         push(@implContent, "#endif\n") if $attributeConditionalString;
2006                         push(@implContent, "\n");
2007                     }
2008                 }
2009             }
2010
2011             if ($dataNode->extendedAttributes->{"ReplaceableConstructor"}) {
2012                 my $constructorFunctionName = "setJS" . $interfaceName . "Constructor";
2013
2014                 push(@implContent, "void ${constructorFunctionName}(ExecState* exec, JSObject* thisObject, JSValue value)\n");
2015                 push(@implContent, "{\n");
2016                 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) {
2017                     if ($interfaceName eq "DOMWindow") {
2018                         push(@implContent, "    if (!static_cast<$className*>(thisObject)->allowsAccessFrom(exec))\n");
2019                     } else {
2020                         push(@implContent, "    if (!allowAccessToFrame(exec, static_cast<$className*>(thisObject)->impl()->frame()))\n");
2021                     }
2022                     push(@implContent, "        return;\n");
2023                 }
2024
2025                 push(@implContent, "    // Shadowing a built-in constructor\n");
2026
2027                 if ($interfaceName eq "DOMWindow") {
2028                     push(@implContent, "    static_cast<$className*>(thisObject)->putDirect(exec->globalData(), exec->propertyNames().constructor, value);\n");
2029                 } else {
2030                     die "No way to handle interface with ReplaceableConstructor extended attribute: $interfaceName";
2031                 }
2032                 push(@implContent, "}\n\n");
2033             }        
2034         }
2035     }
2036
2037     if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) && !$dataNode->extendedAttributes->{"CustomGetPropertyNames"}) {
2038         push(@implContent, "void ${className}::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)\n");
2039         push(@implContent, "{\n");
2040         push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(object);\n");
2041         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2042         if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
2043             push(@implContent, "    for (unsigned i = 0; i < static_cast<${implClassName}*>(thisObject->impl())->length(); ++i)\n");
2044             push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
2045         }
2046         push(@implContent, "     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);\n");
2047         push(@implContent, "}\n\n");
2048     }
2049
2050     if (!$dataNode->extendedAttributes->{"OmitConstructor"}) {
2051         push(@implContent, "JSValue ${className}::getConstructor(ExecState* exec, JSGlobalObject* globalObject)\n{\n");
2052         push(@implContent, "    return getDOMConstructor<${className}Constructor>(exec, static_cast<JSDOMGlobalObject*>(globalObject));\n");
2053         push(@implContent, "}\n\n");
2054     }
2055
2056     # Functions
2057     if ($numFunctions > 0) {
2058         foreach my $function (@{$dataNode->functions}) {
2059             AddIncludesForTypeInImpl($function->signature->type);
2060
2061             my $isCustom = $function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"JSCCustom"};
2062             my $isOverloaded = $function->{overloads} && @{$function->{overloads}} > 1;
2063
2064             next if $isCustom && $isOverloaded && $function->{overloadIndex} > 1;
2065
2066             my $functionName = GetFunctionName($className, $function);
2067
2068             my $conditional = $function->signature->extendedAttributes->{"Conditional"};
2069             if ($conditional) {
2070                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2071                 push(@implContent, "#if ${conditionalString}\n");
2072             }
2073
2074
2075             if (!$isCustom && $isOverloaded) {
2076                 # Append a number to an overloaded method's name to make it unique:
2077                 $functionName = $functionName . $function->{overloadIndex};
2078                 # Make this function static to avoid compiler warnings, since we
2079                 # don't generate a prototype for it in the header.
2080                 push(@implContent, "static ");
2081             }
2082
2083             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
2084
2085             push(@implContent, "EncodedJSValue JSC_HOST_CALL ${functionName}(ExecState* exec)\n");
2086             push(@implContent, "{\n");
2087
2088             $implIncludes{"<runtime/Error.h>"} = 1;
2089
2090             if ($interfaceName eq "DOMWindow") {
2091                 push(@implContent, "    $className* castedThis = toJSDOMWindow(exec->hostThisValue().toThisObject(exec));\n");
2092                 push(@implContent, "    if (!castedThis)\n");
2093                 push(@implContent, "        return throwVMTypeError(exec);\n");
2094             } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) {
2095                 push(@implContent, "    $className* castedThis = to${className}(exec->hostThisValue().toThisObject(exec));\n");
2096                 push(@implContent, "    if (!castedThis)\n");
2097                 push(@implContent, "        return throwVMTypeError(exec);\n");
2098             } elsif (!$function->isStatic) {
2099                 push(@implContent, "    JSValue thisValue = exec->hostThisValue();\n");
2100                 push(@implContent, "    if (!thisValue.inherits(&${className}::s_info))\n");
2101                 push(@implContent, "        return throwVMTypeError(exec);\n");
2102                 push(@implContent, "    $className* castedThis = static_cast<$className*>(asObject(thisValue));\n");
2103             }
2104
2105             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(castedThis, &${className}::s_info);\n") unless ($function->isStatic);
2106
2107             if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} and
2108                 !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"} and
2109                 !$function->isStatic) {
2110                 push(@implContent, "    if (!castedThis->allowsAccessFrom(exec))\n");
2111                 push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2112             }
2113
2114             if ($isCustom) {
2115                 push(@implContent, "    return JSValue::encode(castedThis->" . $functionImplementationName . "(exec));\n") unless ($function->isStatic);
2116             } else {
2117                 push(@implContent, "    $implType* impl = static_cast<$implType*>(castedThis->impl());\n") unless ($function->isStatic);
2118                 if ($svgPropertyType and !$function->isStatic) {
2119                     push(@implContent, "    if (impl->role() == AnimValRole) {\n");
2120                     push(@implContent, "        setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR);\n");
2121                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2122                     push(@implContent, "    }\n");
2123                     push(@implContent, "    $svgPropertyType& podImpl = impl->propertyReference();\n");
2124                     $implIncludes{"ExceptionCode.h"} = 1;
2125                 }
2126
2127                 GenerateArgumentsCountCheck(\@implContent, $function, $dataNode);
2128
2129                 if (@{$function->raisesExceptions}) {
2130                     push(@implContent, "    ExceptionCode ec = 0;\n");
2131                 }
2132
2133                 if ($function->signature->extendedAttributes->{"CheckAccessToNode"} and !$function->isStatic) {
2134                     push(@implContent, "    if (!allowAccessToNode(exec, impl->" . $function->signature->name . "(" . (@{$function->raisesExceptions} ? "ec" : "") .")))\n");
2135                     push(@implContent, "        return JSValue::encode(jsUndefined());\n");
2136                     $implIncludes{"JSDOMBinding.h"} = 1;
2137                 }
2138
2139                 if ($function->signature->name eq "addEventListener") {
2140                     push(@implContent, GenerateEventListenerCall($className, "add"));
2141                 } elsif ($function->signature->name eq "removeEventListener") {
2142                     push(@implContent, GenerateEventListenerCall($className, "remove"));
2143                 } else {
2144                     my $numParameters = @{$function->parameters};
2145                     my ($functionString, $dummy) = GenerateParametersCheck(\@implContent, $function, $dataNode, $numParameters, $implClassName, $functionImplementationName, $svgPropertyType, $svgPropertyOrListPropertyType, $svgListPropertyType);
2146                     GenerateImplementationFunctionCall($function, $functionString, "    ", $svgPropertyType, $implClassName);
2147                 }
2148             }
2149
2150             push(@implContent, "}\n\n");
2151
2152             if (!$isCustom && $isOverloaded && $function->{overloadIndex} == @{$function->{overloads}}) {
2153                 # Generate a function dispatching call to the rest of the overloads.
2154                 GenerateOverloadedFunction($function, $dataNode, $implClassName);
2155             }
2156
2157             push(@implContent, "#endif\n\n") if $conditional;
2158         }
2159         
2160         if ($needsMarkChildren && !$dataNode->extendedAttributes->{"CustomMarkFunction"}) {
2161             push(@implContent, "void ${className}::visitChildren(JSCell* cell, SlotVisitor& visitor)\n");
2162             push(@implContent, "{\n");
2163             push(@implContent, "    ${className}* thisObject = jsCast<${className}*>(cell);\n");
2164             push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);\n");
2165             push(@implContent, "    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);\n");
2166             push(@implContent, "    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());\n");
2167             push(@implContent, "    Base::visitChildren(thisObject, visitor);\n");
2168             if ($dataNode->extendedAttributes->{"EventTarget"}) {
2169                 push(@implContent, "    thisObject->impl()->visitJSEventListeners(visitor);\n");
2170             }
2171             if ($numCachedAttributes > 0) {
2172                 foreach (@{$dataNode->attributes}) {
2173                     my $attribute = $_;
2174                     if ($attribute->signature->extendedAttributes->{"CachedAttribute"}) {
2175                         push(@implContent, "    if (thisObject->m_" . $attribute->signature->name . ")\n");
2176                         push(@implContent, "        visitor.append(&thisObject->m_" . $attribute->signature->name . ");\n");
2177                     }
2178                 }
2179             }
2180             push(@implContent, "}\n\n");
2181         }
2182         # Cached attributes are indeed allowed when there is a custom mark/visitChildren function.
2183         # The custom function must make sure to account for the cached attribute.
2184         # Uncomment the below line to temporarily enforce generated mark functions when cached attributes are present.
2185         # die "Can't generate binding for class with cached attribute and custom mark." if (($numCachedAttributes > 0) and ($dataNode->extendedAttributes->{"CustomMarkFunction"}));
2186     }
2187
2188     if ($numConstants > 0) {
2189         push(@implContent, "// Constant getters\n\n");
2190
2191         foreach my $constant (@{$dataNode->constants}) {
2192             my $getter = "js" . $interfaceName . $codeGenerator->WK_ucfirst($constant->name);
2193             my $conditional = $constant->extendedAttributes->{"Conditional"};
2194
2195             if ($conditional) {
2196                 my $conditionalString = $codeGenerator->GenerateConditionalStringFromAttributeValue($conditional);
2197                 push(@implContent, "#if ${conditionalString}\n");
2198             }
2199
2200             # FIXME: this casts into int to match our previous behavior which turned 0xFFFFFFFF in -1 for NodeFilter.SHOW_ALL
2201             push(@implContent, "JSValue ${getter}(ExecState* exec, JSValue, const Identifier&)\n");
2202             push(@implContent, "{\n");
2203             if ($constant->type eq "DOMString") {
2204                 push(@implContent, "    return jsStringOrNull(exec, String(" . $constant->value . "));\n");
2205             } else {
2206                 push(@implContent, "    UNUSED_PARAM(exec);\n");
2207                 push(@implContent, "    return jsNumber(static_cast<int>(" . $constant->value . "));\n");
2208             }
2209             push(@implContent, "}\n\n");
2210             push(@implContent, "#endif\n") if $conditional;
2211         }
2212     }
2213
2214     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
2215         push(@implContent, "\nJSValue ${className}::indexGetter(ExecState* exec, JSValue slotBase, unsigned index)\n");
2216         push(@implContent, "{\n");
2217         push(@implContent, "    ${className}* thisObj = static_cast<$className*>(asObject(slotBase));\n");
2218         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(thisObj, &s_info);\n");
2219         if (IndexGetterReturnsStrings($implClassName)) {
2220             $implIncludes{"KURL.h"} = 1;
2221             push(@implContent, "    return jsStringOrNull(exec, thisObj->impl()->item(index));\n");
2222         } else {
2223             push(@implContent, "    return toJS(exec, thisObj->globalObject(), static_cast<$implClassName*>(thisObj->impl())->item(index));\n");
2224         }
2225         push(@implContent, "}\n\n");
2226         if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
2227             $implIncludes{"JSNode.h"} = 1;
2228             $implIncludes{"Node.h"} = 1;
2229         }
2230     }
2231     
2232     if ($dataNode->extendedAttributes->{"HasNumericIndexGetter"}) {
2233         push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n");
2234         push(@implContent, "{\n");
2235         push(@implContent, "    ASSERT_GC_OBJECT_INHERITS(this, &s_info);\n");
2236         push(@implContent, "    double result = static_cast<$implClassName*>(impl())->item(index);\n");
2237         # jsNumber conversion doesn't suppress signalling NaNs, so enforce that here.
2238         push(@implContent, "    if (isnan(result))\n");
2239         push(@implContent, "        return jsNaN();\n");
2240         push(@implContent, "    return JSValue(result);\n");
2241         push(@implContent, "}\n\n");
2242         if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
2243             $implIncludes{"JSNode.h"} = 1;
2244             $implIncludes{"Node.h"} = 1;
2245         }
2246     }
2247
2248     if ((!$hasParent && !$dataNode->extendedAttributes->{"CustomIsReachable"})|| $dataNode->extendedAttributes->{"GenerateIsReachable"} || $dataNode->extendedAttributes->{"ActiveDOMObject"}) {
2249         push(@implContent, "static inline bool isObservable(JS${implClassName}* js${implClassName})\n");
2250         push(@implContent, "{\n");
2251         push(@implContent, "    if (js${implClassName}->hasCustomProperties())\n");
2252         push(@implContent, "        return true;\n");
2253         if ($eventTarget) {
2254             push(@implContent, "    if (js${implClassName}->impl()->hasEventListeners())\n");
2255             push(@implContent, "        return true;\n");
2256         }
2257         push(@implContent, "    return false;\n");
2258         push(@implContent, "}\n\n");
2259
2260         push(@implContent, "bool JS${implClassName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
2261         push(@implContent, "{\n");
2262         push(@implContent, "    JS${implClassName}* js${implClassName} = static_cast<JS${implClassName}*>(handle.get().asCell());\n");
2263         # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
2264         # increment their C++ reference counts when hasPendingActivity() becomes
2265         # true. As a result, ActiveDOMObjects can be prematurely destroyed before
2266         # their pending activities complete. To wallpaper over this bug, JavaScript
2267         # wrappers unconditionally keep ActiveDOMObjects with pending activity alive.
2268         # FIXME: Fix this lifetime issue in the DOM, and move this hasPendingActivity
2269         # check below the isObservable check.
2270         if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
2271             push(@implContent, "    if (js${implClassName}->impl()->hasPendingActivity())\n");
2272             push(@implContent, "        return true;\n");
2273         }
2274         push(@implContent, "    if (!isObservable(js${implClassName}))\n");
2275         push(@implContent, "        return false;\n");
2276         if ($dataNode->extendedAttributes->{"GenerateIsReachable"}) {
2277             my $rootString;
2278             if ($dataNode->extendedAttributes->{"GenerateIsReachable"} eq "Impl") {
2279                 $rootString  = "    ${implType}* root = js${implClassName}->impl();\n";
2280             } elsif ($dataNode->extendedAttributes->{"GenerateIsReachable"} eq "ImplContext") {
2281                 $rootString  = "    WebGLRenderingContext* root = js${implClassName}->impl()->context();\n";
2282             } elsif ($dataNode->extendedAttributes->{"GenerateIsReachable"} eq "ImplFrame") {
2283                 $rootString  = "    Frame* root = js${implClassName}->impl()->frame();\n";
2284                 $rootString .= "    if (!root)\n";
2285                 $rootString .= "        return false;\n";
2286             } elsif ($dataNode->extendedAttributes->{"GenerateIsReachable"} eq "ImplDocument") {
2287                 $rootString  = "    Document* root = js${implClassName}->impl()->document();\n";
2288                 $rootString .= "    if (!root)\n";
2289                 $rootString .= "        return false;\n";
2290             } elsif ($dataNode->extendedAttributes->{"GenerateIsReachable"} eq "ImplElementRoot") {
2291                 $rootString  = "    Element* element = js${implClassName}->impl()->element();\n";
2292                 $rootString .= "    if (!element)\n";
2293                 $rootString .= "        return false;\n";
2294                 $rootString .= "    void* root = WebCore::root(element);\n";
2295             } elsif ($interfaceName eq "CanvasRenderingContext") {
2296                 $rootString  = "    void* root = WebCore::root(js${implClassName}->impl()->canvas());\n";
2297             } elsif ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") {
2298                 $rootString  = "    void* root = WebCore::root(js${implClassName}->impl()->base());\n";
2299             } else {
2300                 $rootString  = "    void* root = WebCore::root(js${implClassName}->impl());\n";
2301             }
2302
2303             push(@implContent, $rootString);
2304             push(@implContent, "    return visitor.containsOpaqueRoot(root);\n");
2305         } else {
2306             push(@implContent, "    UNUSED_PARAM(visitor);\n");
2307             push(@implContent, "    return false;\n");
2308         }
2309         push(@implContent, "}\n\n");
2310     }
2311
2312     if (!$dataNode->extendedAttributes->{"CustomFinalize"} &&
2313         (!$hasParent || 
2314          $dataNode->extendedAttributes->{"GenerateIsReachable"} || 
2315          $dataNode->extendedAttributes->{"CustomIsReachable"} ||
2316          $dataNode->extendedAttributes->{"ActiveDOMObject"})) {
2317         push(@implContent, "void JS${implClassName}Owner::finalize(JSC::Handle<JSC::Unknown> handle, void* context)\n");
2318         push(@implContent, "{\n");
2319         push(@implContent, "    JS${implClassName}* js${implClassName} = static_cast<JS${implClassName}*>(handle.get().asCell());\n");
2320         push(@implContent, "    DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context);\n");
2321         push(@implContent, "    uncacheWrapper(world, js${implClassName}->impl(), js${implClassName});\n");
2322         push(@implContent, "    js${implClassName}->releaseImpl();\n");
2323         push(@implContent, "}\n\n");
2324     }
2325
2326     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) {
2327         push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n");
2328         push(@implContent, "{\n");
2329         if ($svgPropertyType) {
2330             push(@implContent, "    return wrap<$className, $implType>(exec, globalObject, impl);\n");
2331         } else {
2332             push(@implContent, "    return wrap<$className>(exec, globalObject, impl);\n");
2333         }
2334         push(@implContent, "}\n\n");
2335     }
2336
2337     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) {
2338         push(@implContent, "$implType* to${interfaceName}(JSC::JSValue value)\n");
2339         push(@implContent, "{\n");
2340         push(@implContent, "    return value.inherits(&${className}::s_info) ? static_cast<$className*>(asObject(value))->impl() : 0");
2341         push(@implContent, ";\n}\n");
2342     }
2343
2344     push(@implContent, "\n}\n");
2345
2346     my $conditionalString = GenerateConditionalString($dataNode);
2347     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2348 }
2349
2350 sub GenerateCallWith
2351 {
2352     my $callWith = shift;
2353     my $outputArray = shift;
2354     my $returnValue = shift;
2355     my $callWithArg = "COMPILE_ASSERT(false)";
2356
2357     if ($callWith eq "ScriptState") {
2358         $callWithArg = "exec";
2359     } elsif ($callWith eq "ScriptExecutionContext") {
2360         push(@$outputArray, "    ScriptExecutionContext* scriptContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();\n");
2361         push(@$outputArray, "    if (!scriptContext)\n");
2362         push(@$outputArray, "        return" . ($returnValue ? " " . $returnValue : "") . ";\n");
2363         $callWithArg = "scriptContext";
2364     }
2365
2366     return $callWithArg;
2367 }
2368
2369 sub GenerateArgumentsCountCheck
2370 {
2371     my $outputArray = shift;
2372     my $function = shift;
2373     my $dataNode = shift;
2374
2375     my $numMandatoryParams = @{$function->parameters};
2376     foreach my $param (reverse(@{$function->parameters})) {
2377         if ($param->extendedAttributes->{"Optional"}) {
2378             $numMandatoryParams--;
2379         } else {
2380             last;
2381         }
2382     }
2383     if ($numMandatoryParams >= 1)
2384     {
2385         push(@$outputArray, "    if (exec->argumentCount() < $numMandatoryParams)\n");
2386         push(@$outputArray, "        return throwVMError(exec, createTypeError(exec, \"Not enough arguments\"));\n");
2387     }
2388 }
2389
2390 sub GenerateParametersCheck
2391 {
2392     my $outputArray = shift;
2393     my $function = shift;
2394     my $dataNode = shift;
2395     my $numParameters = shift;
2396     my $implClassName = shift;
2397     my $functionImplementationName = shift;
2398     my $svgPropertyType = shift;
2399     my $svgPropertyOrListPropertyType = shift;
2400     my $svgListPropertyType = shift;
2401
2402     my $argsIndex = 0;
2403     my $hasOptionalArguments = 0;
2404
2405     my @arguments;
2406     my $functionName;
2407     if ($function->isStatic) {
2408         $functionName = "${implClassName}::${functionImplementationName}";
2409     } elsif ($function->signature->extendedAttributes->{"ImplementedBy"}) {
2410         my $implementedBy = $function->signature->extendedAttributes->{"ImplementedBy"};
2411         AddToImplIncludes("${implementedBy}.h");
2412         unshift(@arguments, "impl");
2413         $functionName = "${implementedBy}::${functionImplementationName}";
2414     } elsif ($svgPropertyOrListPropertyType and !$svgListPropertyType) {
2415         $functionName = "podImpl.${functionImplementationName}";
2416     } else {
2417         $functionName = "impl->${functionImplementationName}";
2418     }
2419
2420     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"} and !$function->isStatic) {
2421         push(@$outputArray, "    RefPtr<ScriptArguments> scriptArguments(createScriptArguments(exec, $numParameters));\n");
2422         push(@$outputArray, "    RefPtr<ScriptCallStack> callStack(createScriptCallStackForInspector(exec));\n");
2423         $implIncludes{"ScriptArguments.h"} = 1;
2424         $implIncludes{"ScriptCallStack.h"} = 1;
2425         $implIncludes{"ScriptCallStackFactory.h"} = 1;
2426     }
2427
2428     my $callWith = $function->signature->extendedAttributes->{"CallWith"};
2429     if ($callWith and !$function->signature->extendedAttributes->{"Constructor"}) {
2430         push(@arguments, GenerateCallWith($callWith, \@$outputArray, "JSValue::encode(jsUndefined())"));
2431     }
2432
2433     $implIncludes{"ExceptionCode.h"} = 1;
2434     $implIncludes{"JSDOMBinding.h"} = 1;
2435
2436     foreach my $parameter (@{$function->parameters}) {
2437         # Optional callbacks should be treated differently, because they always have a default value (0),
2438         # and we can reduce the number of overloaded functions that take a different number of parameters.
2439         # Optional arguments with [Optional=CallWithDefaultValue] or [Optional=CallWithNullValue]
2440         # should not generate an early call.
2441         my $optional = $parameter->extendedAttributes->{"Optional"};
2442         if ($optional && $optional ne "CallWithDefaultValue" && $optional ne "CallWithNullValue" && !$parameter->extendedAttributes->{"Callback"}) {
2443             # Generate early call if there are enough parameters.
2444             if (!$hasOptionalArguments) {
2445                 push(@$outputArray, "\n    size_t argsCount = exec->argumentCount();\n");
2446                 $hasOptionalArguments = 1;
2447             }
2448             push(@$outputArray, "    if (argsCount <= $argsIndex) {\n");
2449
2450             my @optionalCallbackArguments = @arguments;
2451             if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
2452                 push @optionalCallbackArguments, "scriptArguments, callStack";
2453             }
2454             if (@{$function->raisesExceptions}) {
2455                 push @optionalCallbackArguments, "ec";
2456             }
2457             my $functionString = "$functionName(" . join(", ", @optionalCallbackArguments) . ")";
2458             GenerateImplementationFunctionCall($function, $functionString, "    " x 2, $svgPropertyType, $implClassName);
2459             push(@$outputArray, "    }\n\n");
2460         }
2461
2462         my $name = $parameter->name;
2463         my $argType = $codeGenerator->StripModule($parameter->type);
2464
2465         if ($argType eq "XPathNSResolver") {
2466             push(@$outputArray, "    RefPtr<XPathNSResolver> customResolver;\n");
2467             push(@$outputArray, "    XPathNSResolver* resolver = toXPathNSResolver(exec->argument($argsIndex));\n");
2468             push(@$outputArray, "    if (!resolver) {\n");
2469             push(@$outputArray, "        customResolver = JSCustomXPathNSResolver::create(exec, exec->argument($argsIndex));\n");
2470             push(@$outputArray, "        if (exec->hadException())\n");
2471             push(@$outputArray, "            return JSValue::encode(jsUndefined());\n");
2472             push(@$outputArray, "        resolver = customResolver.get();\n");
2473             push(@$outputArray, "    }\n");
2474         } elsif ($parameter->extendedAttributes->{"Callback"}) {
2475             my $callbackClassName = GetCallbackClassName($argType);
2476             $implIncludes{"$callbackClassName.h"} = 1;
2477             if ($parameter->extendedAttributes->{"Optional"}) {
2478                 push(@$outputArray, "    RefPtr<$argType> $name;\n");
2479                 push(@$outputArray, "    if (exec->argumentCount() > $argsIndex && !exec->argument($argsIndex).isUndefinedOrNull()) {\n");
2480                 push(@$outputArray, "        if (!exec->argument($argsIndex).isObject()) {\n");
2481                 push(@$outputArray, "            setDOMException(exec, TYPE_MISMATCH_ERR);\n");
2482                 push(@$outputArray, "            return JSValue::encode(jsUndefined());\n");
2483                 push(@$outputArray, "        }\n");
2484                 push(@$outputArray, "        $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
2485                 push(@$outputArray, "    }\n");
2486             } else {
2487                 push(@$outputArray, "    if (exec->argumentCount() <= $argsIndex || !exec->argument($argsIndex).isObject()) {\n");
2488                 push(@$outputArray, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
2489                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
2490                 push(@$outputArray, "    }\n");
2491                 push(@$outputArray, "    RefPtr<$argType> $name = ${callbackClassName}::create(asObject(exec->argument($argsIndex)), castedThis->globalObject());\n");
2492             }
2493         } else {
2494             # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an
2495             # interface type, then if the incoming value does not implement that interface, a TypeError
2496             # is thrown rather than silently passing NULL to the C++ code.
2497             # Per the Web IDL and ECMAScript semantics, incoming values can always be converted to both
2498             # strings and numbers, so do not throw TypeError if the argument is of these types.
2499             if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) {
2500                 $implIncludes{"<runtime/Error.h>"} = 1;
2501
2502                 my $argValue = "exec->argument($argsIndex)";
2503                 if (!IsNativeType($argType)) {
2504                     push(@$outputArray, "    if (exec->argumentCount() > $argsIndex && !${argValue}.isUndefinedOrNull() && !${argValue}.inherits(&JS${argType}::s_info))\n");
2505                     push(@$outputArray, "        return throwVMTypeError(exec);\n");
2506                 }
2507             }
2508
2509             my $optional = $parameter->extendedAttributes->{"Optional"};
2510             my $parameterMissingPolicy = "MissingIsUndefined";
2511             if ($optional && $optional eq "CallWithNullValue") {
2512                 $parameterMissingPolicy = "MissingIsEmpty";
2513             }
2514
2515             push(@$outputArray, "    " . GetNativeTypeFromSignature($parameter) . " $name(" . JSValueToNative($parameter, "MAYBE_MISSING_PARAMETER(exec, $argsIndex, $parameterMissingPolicy)") . ");\n");
2516
2517             # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
2518             # But this needs to be done in the bindings, because the type is unsigned and the fact that it
2519             # was negative will be lost by the time we're inside the DOM.
2520             if ($parameter->extendedAttributes->{"IsIndex"}) {
2521                 push(@$outputArray, "    if ($name < 0) {\n");
2522                 push(@$outputArray, "        setDOMException(exec, INDEX_SIZE_ERR);\n");
2523                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
2524                 push(@$outputArray, "    }\n");
2525             }
2526
2527             # Check if the type conversion succeeded.
2528             push(@$outputArray, "    if (exec->hadException())\n");
2529             push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
2530
2531             if ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $implClassName =~ /List$/) {
2532                 push(@$outputArray, "    if (!$name) {\n");
2533                 push(@$outputArray, "        setDOMException(exec, TYPE_MISMATCH_ERR);\n");
2534                 push(@$outputArray, "        return JSValue::encode(jsUndefined());\n");
2535                 push(@$outputArray, "    }\n");
2536             }
2537         }
2538
2539         if ($argType eq "NodeFilter") {
2540             push @arguments, "$name.get()";
2541         } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($argType) and not $implClassName =~ /List$/) {
2542             push @arguments, "$name->propertyReference()";
2543         } else {
2544             push @arguments, $name;
2545         }
2546         $argsIndex++;
2547     }
2548
2549     if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
2550         push @arguments, "scriptArguments, callStack";
2551     }
2552     if (@{$function->raisesExceptions}) {
2553         push @arguments, "ec";
2554     }
2555     return ("$functionName(" . join(", ", @arguments) . ")", scalar @arguments);
2556 }
2557
2558 sub GenerateCallbackHeader
2559 {
2560     my $object = shift;
2561     my $dataNode = shift;
2562
2563     my $interfaceName = $dataNode->name;
2564     my $className = "JS$interfaceName";
2565
2566     # - Add default header template and header protection
2567     push(@headerContentHeader, GenerateHeaderContentHeader($dataNode));
2568
2569     $headerIncludes{"ActiveDOMCallback.h"} = 1;
2570     $headerIncludes{"$interfaceName.h"} = 1;
2571     $headerIncludes{"JSCallbackData.h"} = 1;
2572     $headerIncludes{"<wtf/Forward.h>"} = 1;
2573
2574     push(@headerContent, "\nnamespace WebCore {\n\n");
2575     push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n");
2576     push(@headerContent, "public:\n");
2577
2578     # The static create() method.
2579     push(@headerContent, "    static PassRefPtr<$className> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject)\n");
2580     push(@headerContent, "    {\n");
2581     push(@headerContent, "        return adoptRef(new $className(callback, globalObject));\n");
2582     push(@headerContent, "    }\n\n");
2583
2584     # Destructor
2585     push(@headerContent, "    virtual ~$className();\n");
2586
2587     # Functions
2588     my $numFunctions = @{$dataNode->functions};
2589     if ($numFunctions > 0) {
2590         push(@headerContent, "\n    // Functions\n");
2591         foreach my $function (@{$dataNode->functions}) {
2592             my @params = @{$function->parameters};
2593             if (!$function->signature->extendedAttributes->{"Custom"} &&
2594                 !(GetNativeType($function->signature->type) eq "bool")) {
2595                 push(@headerContent, "    COMPILE_ASSERT(false)");
2596             }
2597
2598             push(@headerContent, "    virtual " . GetNativeType($function->signature->type) . " " . $function->signature->name . "(");
2599
2600             my @args = ();
2601             foreach my $param (@params) {
2602                 push(@args, GetNativeType($param->type) . " " . $param->name);
2603             }
2604             push(@headerContent, join(", ", @args));
2605
2606             push(@headerContent, ");\n");
2607         }
2608     }
2609
2610     push(@headerContent, "\nprivate:\n");
2611
2612     # Constructor
2613     push(@headerContent, "    $className(JSC::JSObject* callback, JSDOMGlobalObject*);\n\n");
2614
2615     # Private members
2616     push(@headerContent, "    JSCallbackData* m_data;\n");
2617     push(@headerContent, "};\n\n");
2618
2619     push(@headerContent, "} // namespace WebCore\n\n");
2620     my $conditionalString = GenerateConditionalString($dataNode);
2621     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString;
2622     push(@headerContent, "#endif\n");
2623 }
2624
2625 sub GenerateCallbackImplementation
2626 {
2627     my ($object, $dataNode) = @_;
2628
2629     my $interfaceName = $dataNode->name;
2630     my $className = "JS$interfaceName";
2631
2632     # - Add default header template
2633     push(@implContentHeader, GenerateImplementationContentHeader($dataNode));
2634
2635     $implIncludes{"ScriptExecutionContext.h"} = 1;
2636     $implIncludes{"<runtime/JSLock.h>"} = 1;
2637
2638     @implContent = ();
2639
2640     push(@implContent, "\nusing namespace JSC;\n\n");
2641     push(@implContent, "namespace WebCore {\n\n");
2642
2643     # Constructor
2644     push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
2645     push(@implContent, "    : ActiveDOMCallback(globalObject->scriptExecutionContext())\n");
2646     push(@implContent, "    , m_data(new JSCallbackData(callback, globalObject))\n");
2647     push(@implContent, "{\n");
2648     push(@implContent, "}\n\n");
2649
2650     # Destructor
2651     push(@implContent, "${className}::~${className}()\n");
2652     push(@implContent, "{\n");
2653     push(@implContent, "    ScriptExecutionContext* context = scriptExecutionContext();\n");
2654     push(@implContent, "    // When the context is destroyed, all tasks with a reference to a callback\n");
2655     push(@implContent, "    // should be deleted. So if the context is 0, we are on the context thread.\n");
2656     push(@implContent, "    if (!context || context->isContextThread())\n");
2657     push(@implContent, "        delete m_data;\n");
2658     push(@implContent, "    else\n");
2659     push(@implContent, "        context->postTask(DeleteCallbackDataTask::create(m_data));\n");
2660     push(@implContent, "#ifndef NDEBUG\n");
2661     push(@implContent, "    m_data = 0;\n");
2662     push(@implContent, "#endif\n");
2663     push(@implContent, "}\n");
2664
2665     # Functions
2666     my $numFunctions = @{$dataNode->functions};
2667     if ($numFunctions > 0) {
2668         push(@implContent, "\n// Functions\n");
2669         foreach my $function (@{$dataNode->functions}) {
2670             my @params = @{$function->parameters};
2671             if ($function->signature->extendedAttributes->{"Custom"} ||
2672                 !(GetNativeType($function->signature->type) eq "bool")) {
2673                 next;
2674             }
2675
2676             AddIncludesForTypeInImpl($function->signature->type);
2677             push(@implContent, "\n" . GetNativeType($function->signature->type) . " ${className}::" . $function->signature->name . "(");
2678
2679             my @args = ();
2680             foreach my $param (@params) {
2681                 AddIncludesForTypeInImpl($param->type, 1);
2682                 push(@args, GetNativeType($param->type) . " " . $param->name);
2683             }
2684             push(@implContent, join(", ", @args));
2685             push(@implContent, ")\n");
2686
2687             push(@implContent, "{\n");
2688             push(@implContent, "    if (!canInvokeCallback())\n");
2689             push(@implContent, "        return true;\n\n");
2690             push(@implContent, "    RefPtr<$className> protect(this);\n\n");
2691             push(@implContent, "    JSLock lock(SilenceAssertionsOnly);\n\n");
2692             push(@implContent, "    ExecState* exec = m_data->globalObject()->globalExec();\n");
2693             push(@implContent, "    MarkedArgumentBuffer args;\n");
2694
2695             foreach my $param (@params) {
2696                 my $paramName = $param->name;
2697                 if ($param->type eq "DOMString") {
2698                     push(@implContent, "    args.append(jsString(exec, ${paramName}));\n");
2699                 } else {
2700                     push(@implContent, "    args.append(toJS(exec, m_data->globalObject(), ${paramName}));\n");
2701                 }
2702             }
2703
2704             push(@implContent, "\n    bool raisedException = false;\n");
2705             push(@implContent, "    m_data->invokeCallback(args, &raisedException);\n");
2706             push(@implContent, "    return !raisedException;\n");
2707             push(@implContent, "}\n");
2708         }
2709     }
2710
2711     push(@implContent, "\n}\n");
2712     my $conditionalString = GenerateConditionalString($dataNode);
2713     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
2714 }
2715
2716 sub GenerateImplementationFunctionCall()
2717 {
2718     my $function = shift;
2719     my $functionString = shift;
2720     my $indent = shift;
2721     my $svgPropertyType = shift;
2722     my $implClassName = shift;
2723
2724     if ($function->signature->type eq "void") {
2725         push(@implContent, $indent . "$functionString;\n");
2726         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
2727
2728         if ($svgPropertyType and !$function->isStatic) {
2729             if (@{$function->raisesExceptions}) {
2730                 push(@implContent, $indent . "if (!ec)\n"); 
2731                 push(@implContent, $indent . "    impl->commitChange();\n");
2732             } else {
2733                 push(@implContent, $indent . "impl->commitChange();\n");
2734             }
2735         }
2736
2737         push(@implContent, $indent . "return JSValue::encode(jsUndefined());\n");
2738     } else {
2739         push(@implContent, "\n" . $indent . "JSC::JSValue result = " . NativeToJSValue($function->signature, 1, $implClassName, $functionString, "castedThis") . ";\n");
2740         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
2741
2742         my $callWith = $function->signature->extendedAttributes->{"CallWith"};
2743         if ($callWith and $callWith eq "ScriptState") {
2744             push(@implContent, $indent . "if (exec->hadException())\n");
2745             push(@implContent, $indent . "    return JSValue::encode(jsUndefined());\n");
2746         }
2747
2748         push(@implContent, $indent . "return JSValue::encode(result);\n");
2749     }
2750 }
2751
2752 sub GetNativeTypeFromSignature
2753 {
2754     my $signature = shift;
2755     my $type = $codeGenerator->StripModule($signature->type);
2756
2757     if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
2758         # Special-case index arguments because we need to check that they aren't < 0.
2759         return "int";
2760     }
2761
2762     return GetNativeType($type);
2763 }
2764
2765 my %nativeType = (
2766     "CompareHow" => "Range::CompareHow",
2767     "DOMString" => "const String&",
2768     # FIXME: Add proper support for T[], T[]?, sequence<T>
2769     "DOMString[]" => "DOMStringList*",
2770     "DOMObject" => "ScriptValue",
2771     "NodeFilter" => "RefPtr<NodeFilter>",
2772     "SerializedScriptValue" => "RefPtr<SerializedScriptValue>",
2773     "IDBKey" => "RefPtr<IDBKey>",
2774     "boolean" => "bool",
2775     "double" => "double",
2776     "float" => "float",
2777     "short" => "short",
2778     "long" => "int",
2779     "unsigned long" => "unsigned",
2780     "unsigned short" => "unsigned short",
2781     "long long" => "long long",
2782     "unsigned long long" => "unsigned long long",
2783     "MediaQueryListListener" => "RefPtr<MediaQueryListListener>",
2784     "DOMTimeStamp" => "DOMTimeStamp"
2785 );
2786
2787 sub GetNativeType
2788 {
2789     my $type = shift;
2790
2791     my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type);
2792     return "${svgNativeType}*" if $svgNativeType;
2793     return $nativeType{$type} if exists $nativeType{$type};
2794
2795     # For all other types, the native type is a pointer with same type name as the IDL type.
2796     return "${type}*";
2797 }
2798
2799 sub GetSVGPropertyTypes
2800 {
2801     my $implType = shift;
2802
2803     my $svgPropertyType;
2804     my $svgListPropertyType;
2805     my $svgNativeType;
2806
2807     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/;
2808     
2809     $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType);
2810     return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType;
2811
2812     # Append space to avoid compilation errors when using  PassRefPtr<$svgNativeType>
2813     $svgNativeType = "$svgNativeType ";
2814
2815     my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType);
2816     if ($svgNativeType =~ /SVGPropertyTearOff/) {
2817         $svgPropertyType = $svgWrappedNativeType;
2818         $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2819         $headerIncludes{"SVGAnimatedPropertyTearOff.h"} = 1;
2820     } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) {
2821         $svgListPropertyType = $svgWrappedNativeType;
2822         $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2823         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2824     } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) {
2825         $svgListPropertyType = $svgWrappedNativeType;
2826         $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2827         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2828         $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1;
2829     } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) {
2830         $svgListPropertyType = $svgWrappedNativeType;
2831         $headerIncludes{"$svgWrappedNativeType.h"} = 1;
2832         $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1;
2833         $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1;
2834     }
2835
2836     return ($svgPropertyType, $svgListPropertyType, $svgNativeType);
2837 }
2838
2839 sub IsNativeType
2840 {
2841     my $type = shift;
2842     return exists $nativeType{$type};
2843 }
2844
2845 sub IsArrayType
2846 {
2847     my $type = shift;
2848     # FIXME: Add proper support for T[], T[]?, sequence<T>.
2849     return $type =~ m/\[\]$/;
2850 }
2851
2852 sub JSValueToNative
2853 {
2854     my $signature = shift;
2855     my $value = shift;
2856
2857     my $conditional = $signature->extendedAttributes->{"Conditional"};
2858     my $type = $codeGenerator->StripModule($signature->type);
2859
2860     return "$value.toBoolean(exec)" if $type eq "boolean";
2861     return "$value.toNumber(exec)" if $type eq "double";
2862     return "$value.toFloat(exec)" if $type eq "float";
2863     return "$value.toInt32(exec)" if $type eq "long" or $type eq "short";
2864     return "$value.toUInt32(exec)" if $type eq "unsigned long" or $type eq "unsigned short";
2865     return "static_cast<$type>($value.toInteger(exec))" if $type eq "long long" or $type eq "unsigned long long";
2866
2867     return "valueToDate(exec, $value)" if $type eq "Date";
2868     return "static_cast<Range::CompareHow>($value.toInt32(exec))" if $type eq "CompareHow";
2869
2870     if ($type eq "DOMString") {
2871         if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "EmptyString") and ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "EmptyString")) {
2872             return "valueToStringWithUndefinedOrNullCheck(exec, $value)"
2873         }
2874         if (($signature->extendedAttributes->{"TreatNullAs"} and $signature->extendedAttributes->{"TreatNullAs"} eq "EmptyString") or $signature->extendedAttributes->{"Reflect"}) {
2875             return "valueToStringWithNullCheck(exec, $value)"
2876         }
2877         # FIXME: Add the case for 'if ($signature->extendedAttributes->{"TreatUndefinedAs"} and $signature->extendedAttributes->{"TreatUndefinedAs"} eq "EmptyString"))'.
2878         return "ustringToString($value.isEmpty() ? UString() : $value.toString(exec)->value(exec))";
2879     }
2880
2881     if ($type eq "DOMObject") {
2882         return "exec->globalData(), $value";
2883     }
2884
2885     if ($type eq "NodeFilter") {
2886         AddToImplIncludes("JS$type.h", $conditional);
2887         return "to$type(exec->globalData(), $value)";
2888     }
2889
2890     if ($type eq "MediaQueryListListener") {
2891         AddToImplIncludes("MediaQueryListListener.h", $conditional);
2892         return "MediaQueryListListener::create(ScriptValue(exec->globalData(), " . $value ."))";
2893     }
2894
2895     if ($type eq "SerializedScriptValue" or $type eq "any") {
2896         AddToImplIncludes("SerializedScriptValue.h", $conditional);
2897         return "SerializedScriptValue::create(exec, $value)";
2898     }
2899
2900     if ($type eq "IDBKey") {
2901         AddToImplIncludes("IDBBindingUtilities.h", $conditional);
2902         AddToImplIncludes("IDBKey.h", $conditional);
2903         return "createIDBKeyFromValue(exec, $value)";
2904     }
2905
2906     if ($type eq "DOMString[]") {
2907         AddToImplIncludes("JSDOMStringList.h", $conditional);
2908         return "toDOMStringList($value)";
2909     }
2910
2911     AddToImplIncludes("HTMLOptionElement.h", $conditional) if $type eq "HTMLOptionElement";
2912     AddToImplIncludes("JSCustomVoidCallback.h", $conditional) if $type eq "VoidCallback";
2913     AddToImplIncludes("Event.h", $conditional) if $type eq "Event";
2914
2915     # Default, assume autogenerated type conversion routines
2916     AddToImplIncludes("JS$type.h", $conditional);
2917     return "to$type($value)";
2918 }
2919
2920 sub NativeToJSValue
2921 {