2008-09-22 Darin Adler <darin@apple.com>
[WebKit-https.git] / 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 Apple Inc. All rights reserved.
7
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Library General Public License for more details.
17 #
18 # You should have received a copy of the GNU Library General Public License
19 # aint with this library; see the file COPYING.LIB.  If not, write to
20 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 # Boston, MA 02110-1301, USA.
22
23 package CodeGeneratorJS;
24
25 use File::stat;
26
27 my $module = "";
28 my $outputDir = "";
29
30 my @headerContentHeader = ();
31 my @headerContent = ();
32 my %headerIncludes = ();
33
34 my @implContentHeader = ();
35 my @implContent = ();
36 my %implIncludes = ();
37 my %implKJSIncludes = ();
38
39 # Default .h template
40 my $headerTemplate = << "EOF";
41 /*
42     This file is part of the WebKit open source project.
43     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
44
45     This library is free software; you can redistribute it and/or
46     modify it under the terms of the GNU Library General Public
47     License as published by the Free Software Foundation; either
48     version 2 of the License, or (at your option) any later version.
49
50     This library is distributed in the hope that it will be useful,
51     but WITHOUT ANY WARRANTY; without even the implied warranty of
52     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
53     Library General Public License for more details.
54
55     You should have received a copy of the GNU Library General Public License
56     along with this library; see the file COPYING.LIB.  If not, write to
57     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
58     Boston, MA 02110-1301, USA.
59 */
60 EOF
61
62 # Default constructor
63 sub new
64 {
65     my $object = shift;
66     my $reference = { };
67
68     $codeGenerator = shift;
69     $outputDir = shift;
70
71     bless($reference, $object);
72     return $reference;
73 }
74
75 sub finish
76 {
77     my $object = shift;
78
79     # Commit changes!
80     $object->WriteData();
81 }
82
83 sub leftShift($$) {
84     my ($value, $distance) = @_;
85     return (($value << $distance) & 0xFFFFFFFF);
86 }
87
88 # Params: 'domClass' struct
89 sub GenerateInterface
90 {
91     my $object = shift;
92     my $dataNode = shift;
93     my $defines = shift;
94
95     # Start actual generation
96     $object->GenerateHeader($dataNode);
97     $object->GenerateImplementation($dataNode);
98
99     my $name = $dataNode->name;
100
101     # Open files for writing
102     my $headerFileName = "$outputDir/JS$name.h";
103     my $implFileName = "$outputDir/JS$name.cpp";
104
105     open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
106     open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
107 }
108
109 # Params: 'idlDocument' struct
110 sub GenerateModule
111 {
112     my $object = shift;
113     my $dataNode = shift;
114
115     $module = $dataNode->module;
116 }
117
118 sub GetParentClassName
119 {
120     my $dataNode = shift;
121
122     return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
123     return "DOMObject" if @{$dataNode->parents} eq 0;
124     return "JS" . $codeGenerator->StripModule($dataNode->parents(0));
125 }
126
127 sub GetVisibleClassName
128 {
129     my $className = shift;
130
131     return "DOMException" if $className eq "DOMCoreException";
132     return $className;
133 }
134
135 sub AvoidInclusionOfType
136 {
137     my $type = shift;
138
139     # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist.
140     return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix";
141     return 0;
142 }
143
144 sub UsesManualToJSImplementation
145 {
146     my $type = shift;
147
148     return 1 if $type eq "Node" or $type eq "Document" or $type eq "HTMLCollection" or $type eq "SVGPathSeg" or $type eq "StyleSheet" or $type eq "CSSRule" or $type eq "CSSValue" or $type eq "Event" or $type eq "CanvasPixelArray" or $type eq "Element" or $type eq "Text";
149     return 0;
150 }
151
152 sub IndexGetterReturnsStrings
153 {
154     my $type = shift;
155
156     return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList" or $type eq "CSSVariablesDeclaration";
157     return 0;
158 }
159
160 sub CreateSVGContextInterfaceName
161 {
162     my $type = shift;
163
164     return $type if $codeGenerator->IsSVGAnimatedType($type);
165     return "SVGPathSeg" if $type =~ /^SVGPathSeg/ and $type ne "SVGPathSegList";
166
167     return "";
168 }
169
170 sub AddIncludesForType
171 {
172     my $type = $codeGenerator->StripModule(shift);
173
174     # When we're finished with the one-file-per-class
175     # reorganization, we won't need these special cases.
176     if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type)
177         or $type eq "DOMString" or $type eq "DOMObject" or $type eq "RGBColor") {
178     } elsif ($type =~ /SVGPathSeg/) {
179         $joinedName = $type;
180         $joinedName =~ s/Abs|Rel//;
181         $implIncludes{"${joinedName}.h"} = 1;
182     } elsif ($type eq "XPathNSResolver") {
183         $implIncludes{"JSXPathNSResolver.h"} = 1;
184         $implIncludes{"JSCustomXPathNSResolver.h"} = 1;
185     } else {
186         # default, include the same named file
187         $implIncludes{"${type}.h"} = 1;
188     }
189
190     # additional includes (things needed to compile the bindings but not the header)
191
192     if ($type eq "CanvasRenderingContext2D") {
193         $implIncludes{"CanvasGradient.h"} = 1;
194         $implIncludes{"CanvasPattern.h"} = 1;
195         $implIncludes{"CanvasStyle.h"} = 1;
196     }
197
198     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
199         $implIncludes{"PlatformString.h"} = 1;
200     }
201
202     if ($type eq "Document") {
203         $implIncludes{"NodeFilter.h"} = 1;
204     }
205 }
206
207 sub AddIncludesForSVGAnimatedType
208 {
209     my $type = shift;
210     $type =~ s/SVGAnimated//;
211
212     if ($type eq "Point" or $type eq "Rect") {
213         $implIncludes{"Float$type.h"} = 1;
214     } elsif ($type eq "String") {
215         $implIncludes{"PlatformString.h"} = 1;
216     }
217 }
218
219 sub AddClassForwardIfNeeded
220 {
221     my $implClassName = shift;
222
223     # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them!
224     push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName);
225 }
226
227 sub IsSVGTypeNeedingContextParameter
228 {
229     my $implClassName = shift;
230
231     if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) {
232         return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/;
233     }
234
235     return 0;
236 }
237
238 sub HashValueForClassAndName
239 {
240     my $class = shift;
241     my $name = shift;
242
243     # SVG Filter enums live in WebCore namespace (platform/graphics/)
244     if ($class =~ /^SVGFE*/ or $class =~ /^SVGComponentTransferFunctionElement$/) {
245         return "WebCore::$name";
246     }
247
248     return "${class}::$name";
249 }
250
251 sub GenerateGetOwnPropertySlotBody
252 {
253     my ($dataNode, $interfaceName, $className, $implClassName, $hasAttributes, $inlined) = @_;
254
255     my $namespaceMaybe = ($inlined ? "JSC::" : "");
256
257     my @getOwnPropertySlotImpl = ();
258
259     if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection") {
260         push(@getOwnPropertySlotImpl, "    ${namespaceMaybe}JSValue* proto = prototype();\n");
261         push(@getOwnPropertySlotImpl, "    if (proto->isObject() && static_cast<${namespaceMaybe}JSObject*>(proto)->hasProperty(exec, propertyName))\n");
262         push(@getOwnPropertySlotImpl, "        return false;\n\n");
263     }
264
265     my $hasNameGetterGeneration = sub {
266         push(@getOwnPropertySlotImpl, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
267         push(@getOwnPropertySlotImpl, "        slot.setCustom(this, nameGetter);\n");
268         push(@getOwnPropertySlotImpl, "        return true;\n");
269         push(@getOwnPropertySlotImpl, "    }\n");
270         if ($inlined) {
271             $headerIncludes{"AtomicString.h"} = 1;
272         } else {
273             $implIncludes{"AtomicString.h"} = 1;
274         }
275     };
276
277     if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
278         &$hasNameGetterGeneration();
279     }
280
281     my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
282     if ($requiresManualLookup) {
283         push(@getOwnPropertySlotImpl, "    const ${namespaceMaybe}HashEntry* entry = ${className}Table.entry(exec, propertyName);\n");
284         push(@getOwnPropertySlotImpl, "    if (entry) {\n");
285         push(@getOwnPropertySlotImpl, "        slot.setStaticEntry(this, entry, staticValueGetter<$className>);\n");
286         push(@getOwnPropertySlotImpl, "        return true;\n");
287         push(@getOwnPropertySlotImpl, "    }\n");
288     }
289
290     if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
291         push(@getOwnPropertySlotImpl, "    bool ok;\n");
292         push(@getOwnPropertySlotImpl, "    unsigned index = propertyName.toUInt32(&ok, false);\n");
293         push(@getOwnPropertySlotImpl, "    if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n");
294         if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
295             push(@getOwnPropertySlotImpl, "        slot.setValue(getByIndex(exec, index));\n");
296         } else {
297             push(@getOwnPropertySlotImpl, "        slot.setCustomIndex(this, index, indexGetter);\n");
298         }
299         push(@getOwnPropertySlotImpl, "        return true;\n");
300         push(@getOwnPropertySlotImpl, "    }\n");
301     }
302
303     if ($dataNode->extendedAttributes->{"HasNameGetter"}) {
304         &$hasNameGetterGeneration();
305     }
306
307     if ($dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
308         push(@getOwnPropertySlotImpl, "    if (customGetOwnPropertySlot(exec, propertyName, slot))\n");
309         push(@getOwnPropertySlotImpl, "        return true;\n");
310     }
311
312     if ($hasAttributes) {
313         if ($inlined) {
314             push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, s_info.staticPropHashTable, this, propertyName, slot);\n");
315         } else {
316            push(@getOwnPropertySlotImpl, "    return ${namespaceMaybe}getStaticValueSlot<$className, Base>(exec, &${className}Table, this, propertyName, slot);\n");
317         }
318     } else {
319         push(@getOwnPropertySlotImpl, "    return Base::getOwnPropertySlot(exec, propertyName, slot);\n");
320     }
321
322     return @getOwnPropertySlotImpl;
323 }
324
325 sub GenerateHeader
326 {
327     my $object = shift;
328     my $dataNode = shift;
329
330     my $interfaceName = $dataNode->name;
331     my $className = "JS$interfaceName";
332     my $implClassName = $interfaceName;
333
334     # We only support multiple parents with SVG (for now).
335     if (@{$dataNode->parents} > 1) {
336         die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
337         $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode);
338     }
339
340     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
341     my $hasRealParent = @{$dataNode->parents} > 0;
342     my $hasParent = $hasLegacyParent || $hasRealParent;
343     my $parentClassName = GetParentClassName($dataNode);
344     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
345
346     # - Add default header template
347     @headerContentHeader = split("\r", $headerTemplate);
348
349     # - Add header protection
350     push(@headerContentHeader, "\n#ifndef $className" . "_h");
351     push(@headerContentHeader, "\n#define $className" . "_h\n\n");
352
353     my $conditionalString;
354     if ($conditional) {
355         $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
356         push(@headerContentHeader, "\n#if ${conditionalString}\n\n");
357     }
358
359     if ($hasParent) {
360         push(@headerContentHeader, "#include \"$parentClassName.h\"\n");
361     } else {
362         push(@headerContentHeader, "#include \"JSDOMBinding.h\"\n");
363         push(@headerContentHeader, "#include <kjs/JSGlobalObject.h>\n");
364         push(@headerContentHeader, "#include <kjs/ObjectPrototype.h>\n");
365     }
366     if ($interfaceName eq "Node") {
367         push(@headerContentHeader, "#include \"EventTargetNode.h\"\n");
368     }
369
370     if ($dataNode->extendedAttributes->{"CustomCall"}) {
371         push(@headerContentHeader, "#include <kjs/CallData.h>\n");
372     }
373
374     if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"}) {
375         push(@headerContentHeader, "#include <kjs/lookup.h>\n");
376         push(@headerContentHeader, "#include <wtf/AlwaysInline.h>\n");
377     }
378
379     if ($hasParent && $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
380         push(@headerContentHeader, "#include \"${implClassName}.h\"");
381     }
382
383     # Get correct pass/store types respecting PODType flag
384     my $podType = $dataNode->extendedAttributes->{"PODType"};
385     my $implType = $podType ? "JSSVGPODTypeWrapper<$podType> " : $implClassName;
386     push(@headerContentHeader, "#include \"$podType.h\"\n") if $podType and $podType ne "float";
387
388     push(@headerContentHeader, "#include \"JSSVGPODTypeWrapper.h\"\n") if $podType;
389
390     my $numConstants = @{$dataNode->constants};
391     my $numAttributes = @{$dataNode->attributes};
392     my $numFunctions = @{$dataNode->functions};
393
394     push(@headerContent, "\nnamespace WebCore {\n\n");
395
396     # Implementation class forward declaration
397     AddClassForwardIfNeeded($implClassName) unless $podType;
398     AddClassForwardIfNeeded("JSDOMWindowShell") if $interfaceName eq "DOMWindow";
399
400     # Class declaration
401     push(@headerContent, "class $className : public $parentClassName {\n");
402     push(@headerContent, "    typedef $parentClassName Base;\n");
403     push(@headerContent, "public:\n");
404
405     # Constructor
406     if ($interfaceName eq "DOMWindow") {
407         push(@headerContent, "    $className(PassRefPtr<JSC::StructureID>, PassRefPtr<$implType>, JSDOMWindowShell*);\n");
408     } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
409         push(@headerContent, "    $className(PassRefPtr<JSC::StructureID>, PassRefPtr<$implType>, SVGElement* context);\n");
410     } else {
411         push(@headerContent, "    $className(PassRefPtr<JSC::StructureID>, PassRefPtr<$implType>);\n");
412     }
413
414     # Destructor
415     push(@headerContent, "    virtual ~$className();\n") if (!$hasParent or $interfaceName eq "Document");
416
417     # Prototype
418     push(@headerContent, "    static JSC::JSObject* createPrototype(JSC::ExecState*);\n") if $interfaceName ne "DOMWindow";
419
420     $implIncludes{"${className}Custom.h"} = 1 if $dataNode->extendedAttributes->{"CustomHeader"} || $dataNode->extendedAttributes->{"CustomPutFunction"};
421
422     my $hasGetter = $numAttributes > 0 
423                  || $dataNode->extendedAttributes->{"GenerateConstructor"} 
424                  || $dataNode->extendedAttributes->{"HasIndexGetter"}
425                  || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}
426                  || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
427                  || $dataNode->extendedAttributes->{"HasNameGetter"}
428                  || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
429
430     # Getters
431     if ($hasGetter) {
432         push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);\n");
433         push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);\n") if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"};
434         push(@headerContent, "    JSC::JSValue* getValueProperty(JSC::ExecState*, int token) const;\n") if $numAttributes > 0 || $dataNode->extendedAttributes->{"GenerateConstructor"};
435         push(@headerContent, "    bool customGetOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n") if $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
436     }
437
438     # Check if we have any writable properties
439     my $hasReadWriteProperties = 0;
440     foreach (@{$dataNode->attributes}) {
441         if ($_->type !~ /^readonly\ attribute$/) {
442             $hasReadWriteProperties = 1;
443         }
444     }
445
446     my $hasSetter = $hasReadWriteProperties
447                  || $dataNode->extendedAttributes->{"CustomPutFunction"}
448                  || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
449
450     # Getters
451     if ($hasSetter) {
452         push(@headerContent, "    virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue*, JSC::PutPropertySlot&);\n");
453         push(@headerContent, "    virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue*);\n") if $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
454         push(@headerContent, "    void putValueProperty(JSC::ExecState*, int, JSC::JSValue*);\n") if $hasReadWriteProperties;
455         push(@headerContent, "    bool customPut(JSC::ExecState*, const JSC::Identifier&, JSC::JSValue*, JSC::PutPropertySlot&);\n") if $dataNode->extendedAttributes->{"CustomPutFunction"};
456     }
457
458     # Class info
459     push(@headerContent, "    virtual const JSC::ClassInfo* classInfo() const { return &s_info; }\n");
460     push(@headerContent, "    static const JSC::ClassInfo s_info;\n\n");
461
462     # Custom mark function
463     push(@headerContent, "    virtual void mark();\n\n") if $dataNode->extendedAttributes->{"CustomMarkFunction"};
464
465     # Custom pushEventHandlerScope function
466     push(@headerContent, "    virtual void pushEventHandlerScope(JSC::ExecState*, JSC::ScopeChain&) const;\n\n") if $dataNode->extendedAttributes->{"CustomPushEventHandlerScope"};
467
468     # Custom call functions
469     push(@headerContent, "    virtual JSC::CallType getCallData(JSC::CallData&);\n\n") if $dataNode->extendedAttributes->{"CustomCall"};
470
471     # Custom deleteProperty function
472     push(@headerContent, "    virtual bool deleteProperty(JSC::ExecState*, const JSC::Identifier&);\n") if $dataNode->extendedAttributes->{"CustomDeleteProperty"};
473
474     # Custom getPropertyNames function
475     push(@headerContent, "    virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);\n") if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"});
476     push(@headerContent, "    bool customGetPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&);\n") if $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
477
478     # Custom getPropertyAttributes function
479     push(@headerContent, "    virtual bool getPropertyAttributes(JSC::ExecState*, const JSC::Identifier&, unsigned& attributes) const;\n") if $dataNode->extendedAttributes->{"CustomGetPropertyAttributes"};
480
481     # Custom defineGetter function
482     push(@headerContent, "    virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction);\n") if $dataNode->extendedAttributes->{"CustomDefineGetter"};
483
484     # Custom defineSetter function
485     push(@headerContent, "    virtual void defineSetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* setterFunction);\n") if $dataNode->extendedAttributes->{"CustomDefineSetter"};
486
487     # Custom lookupGetter function
488     push(@headerContent, "    virtual JSC::JSValue* lookupGetter(JSC::ExecState*, const JSC::Identifier& propertyName);\n") if $dataNode->extendedAttributes->{"CustomLookupGetter"};
489
490     # Custom lookupSetter function
491     push(@headerContent, "    virtual JSC::JSValue* lookupSetter(JSC::ExecState*, const JSC::Identifier& propertyName);\n") if $dataNode->extendedAttributes->{"CustomLookupSetter"};
492
493     # Constructor object getter
494     push(@headerContent, "    static JSC::JSValue* getConstructor(JSC::ExecState*);\n") if $dataNode->extendedAttributes->{"GenerateConstructor"};
495
496     my $numCustomFunctions = 0;
497     my $numCustomAttributes = 0;
498
499     # Attribute and function enums
500     my $hasAttrEnum = ($numAttributes > 0) || $dataNode->extendedAttributes->{"GenerateConstructor"};
501     push(@headerContent, "    enum {\n") if ($hasAttrEnum);
502
503     if ($numAttributes > 0) {
504         push(@headerContent, "        // Attributes\n        ");
505
506         my $i = -1;
507         foreach (@{$dataNode->attributes}) {
508             my $attribute = $_;
509
510             $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"};
511             $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomGetter"};
512             $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomSetter"};
513
514             $i++;
515             if ((($i % 4) eq 0) and ($i ne 0)) {
516                 push(@headerContent, "\n        ");
517             }
518
519             my $value = $codeGenerator->WK_ucfirst($attribute->signature->name)
520                 . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
521                 . "AttrNum";
522             $value .= ", " if (($i < $numAttributes - 1) or (($i eq $numAttributes - 1) and (($numFunctions ne 0) or $dataNode->extendedAttributes->{"GenerateConstructor"})));
523             push(@headerContent, $value);
524         }
525     }
526
527     if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
528         push(@headerContent, "\n\n") if $numAttributes > 0;
529         push(@headerContent, "        // The Constructor Attribute\n");
530         push(@headerContent, "        ConstructorAttrNum");
531     }
532
533     push(@headerContent, "\n    };\n") if ($hasAttrEnum);
534
535     if ($numCustomAttributes > 0) {
536         push(@headerContent, "\n    // Custom attributes\n");
537
538         foreach my $attribute (@{$dataNode->attributes}) {
539             if ($attribute->signature->extendedAttributes->{"Custom"}) {
540                 push(@headerContent, "    JSC::JSValue* " . $codeGenerator->WK_lcfirst($attribute->signature->name) . "(JSC::ExecState*) const;\n");
541                 if ($attribute->type !~ /^readonly/) {
542                     push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue*);\n");
543                 }
544             } elsif ($attribute->signature->extendedAttributes->{"CustomGetter"}) {
545                 push(@headerContent, "    JSC::JSValue* " . $codeGenerator->WK_lcfirst($attribute->signature->name) . "(JSC::ExecState*) const;\n");
546             } elsif ($attribute->signature->extendedAttributes->{"CustomSetter"}) {
547                 if ($attribute->type !~ /^readonly/) {
548                     push(@headerContent, "    void set" . $codeGenerator->WK_ucfirst($attribute->signature->name) . "(JSC::ExecState*, JSC::JSValue*);\n");
549                 }
550             }
551         }
552     }
553
554     foreach my $function (@{$dataNode->functions}) {
555         $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"};
556     }
557
558     if ($numCustomFunctions > 0) {
559         push(@headerContent, "\n    // Custom functions\n");
560         foreach my $function (@{$dataNode->functions}) {
561             if ($function->signature->extendedAttributes->{"Custom"}) {
562                 my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
563                 push(@headerContent, "    JSC::JSValue* " . $functionImplementationName . "(JSC::ExecState*, const JSC::ArgList&);\n");
564             }
565         }
566     }
567
568     if (!$hasParent) {
569         if ($podType) {
570             push(@headerContent, "    JSSVGPODTypeWrapper<$podType>* impl() const { return m_impl.get(); }\n");
571             push(@headerContent, "    SVGElement* context() const { return m_context.get(); }\n\n");
572             push(@headerContent, "private:\n");
573             push(@headerContent, "    RefPtr<SVGElement> m_context;\n");
574             push(@headerContent, "    RefPtr<JSSVGPODTypeWrapper<$podType> > m_impl;\n");
575         } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
576             push(@headerContent, "    $implClassName* impl() const { return m_impl.get(); }\n");
577             push(@headerContent, "    SVGElement* context() const { return m_context.get(); }\n\n");
578             push(@headerContent, "private:\n");
579             push(@headerContent, "    RefPtr<SVGElement> m_context;\n");
580             push(@headerContent, "    RefPtr<$implClassName > m_impl;\n");
581         } else {
582             push(@headerContent, "    $implClassName* impl() const { return m_impl.get(); }\n\n");
583             push(@headerContent, "private:\n");
584             push(@headerContent, "    RefPtr<$implClassName> m_impl;\n");
585         }
586     } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
587         push(@headerContent, "    $implClassName* impl() const\n");
588         push(@headerContent, "    {\n");
589         push(@headerContent, "        return static_cast<$implClassName*>(Base::impl());\n");
590         push(@headerContent, "    }\n");
591     }
592
593     # Index getter
594     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
595         push(@headerContent, "    static JSC::JSValue* indexGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&);\n");
596     }
597     if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
598         push(@headerContent, "    JSC::JSValue* getByIndex(JSC::ExecState*, unsigned index);\n");
599     }
600     
601     # Index setter
602     if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
603         push(@headerContent, "    void indexSetter(JSC::ExecState*, unsigned index, JSC::JSValue*);\n");
604     }
605     # Name getter
606     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
607         push(@headerContent, "private:\n");
608         push(@headerContent, "    static bool canGetItemsForName(JSC::ExecState*, $implClassName*, const JSC::Identifier&);\n");
609         push(@headerContent, "    static JSC::JSValue* nameGetter(JSC::ExecState*, const JSC::Identifier&, const JSC::PropertySlot&);\n");
610     }
611
612     push(@headerContent, "};\n\n");
613
614     if ($dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"}) {
615         push(@headerContent, "ALWAYS_INLINE bool ${className}::getOwnPropertySlot(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertySlot& slot)\n");
616         push(@headerContent, "{\n");
617         push(@headerContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 1));
618         push(@headerContent, "}\n\n");
619     }
620
621     if (!$hasParent || $dataNode->extendedAttributes->{"GenerateToJS"}) {
622         if ($podType) {
623             push(@headerContent, "JSC::JSValue* toJS(JSC::ExecState*, JSSVGPODTypeWrapper<$podType>*, SVGElement* context);\n");
624         } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
625             push(@headerContent, "JSC::JSValue* toJS(JSC::ExecState*, $implType*, SVGElement* context);\n");
626         } else {
627             push(@headerContent, "JSC::JSValue* toJS(JSC::ExecState*, $implType*);\n");
628         }
629         if ($interfaceName eq "Node") {
630             # Resolve ambiguity with EventTarget that otherwise exists.
631             push(@headerContent, "inline JSC::JSValue* toJS(JSC::ExecState* exec, EventTargetNode* node) { return toJS(exec, static_cast<Node*>(node)); }\n");
632         }
633     }
634     if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
635         if ($podType) {
636             push(@headerContent, "$podType to${interfaceName}(JSC::JSValue*);\n");
637         } elsif ($interfaceName eq "NodeFilter") {
638             push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::JSValue*);\n");
639         } else {
640             push(@headerContent, "$implClassName* to${interfaceName}(JSC::JSValue*);\n");
641         }
642         if ($interfaceName eq "Node" or $interfaceName eq "Element" or $interfaceName eq "Text") {
643             push(@headerContent, "JSC::JSValue* toJSNewlyCreated(JSC::ExecState*, $interfaceName*);\n");
644         }
645     }
646     push(@headerContent, "\n");
647
648     # Add prototype declaration.
649     push(@headerContent, "class ${className}Prototype : public JSC::JSObject {\n");
650     push(@headerContent, "public:\n");
651     if ($interfaceName eq "DOMWindow") {
652         push(@headerContent, "    void* operator new(size_t);\n");
653     } else {
654         push(@headerContent, "    static JSC::JSObject* self(JSC::ExecState*);\n");
655     }
656     push(@headerContent, "    virtual const JSC::ClassInfo* classInfo() const { return &s_info; }\n");
657     push(@headerContent, "    static const JSC::ClassInfo s_info;\n");
658     if ($numFunctions > 0 || $numConstants > 0) {
659         push(@headerContent, "    virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier&, JSC::PropertySlot&);\n");
660     }
661     if ($numConstants ne 0) {
662         push(@headerContent, "    JSC::JSValue* getValueProperty(JSC::ExecState*, int token) const;\n");
663     }
664     push(@headerContent, "    ${className}Prototype(PassRefPtr<JSC::StructureID> structure) : JSC::JSObject(structure) { }\n");
665
666     push(@headerContent, "};\n\n");
667
668     if ($numFunctions > 0) {
669         push(@headerContent,"// Functions\n\n");
670         foreach my $function (@{$dataNode->functions}) {
671             my $functionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($function->signature->name);
672             push(@headerContent, "JSC::JSValue* ${functionName}(JSC::ExecState*, JSC::JSObject*, JSC::JSValue*, const JSC::ArgList&);\n");
673         }
674     }
675
676     push(@headerContent, "\n} // namespace WebCore\n\n");
677     push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditional;
678     push(@headerContent, "#endif\n");
679 }
680
681 sub GenerateImplementation
682 {
683     my ($object, $dataNode) = @_;
684
685     my $interfaceName = $dataNode->name;
686     my $className = "JS$interfaceName";
687     my $implClassName = $interfaceName;
688
689     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
690     my $hasRealParent = @{$dataNode->parents} > 0;
691     my $hasParent = $hasLegacyParent || $hasRealParent;
692     my $parentClassName = GetParentClassName($dataNode);
693     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
694     my $visibleClassName = GetVisibleClassName($interfaceName);
695
696     # - Add default header template
697     @implContentHeader = split("\r", $headerTemplate);
698     push(@implContentHeader, "\n#include \"config.h\"\n\n");
699     my $conditionalString;
700     if ($conditional) {
701         $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
702         push(@implContentHeader, "\n#if ${conditionalString}\n\n");
703     }
704
705     if ($className =~ /^JSSVG/) {
706         push(@implContentHeader, "#include \"SVGElement.h\"\n");
707
708         if ($className =~ /^JSSVGAnimated/) {
709             AddIncludesForSVGAnimatedType($interfaceName);
710         }
711     }
712
713     push(@implContentHeader, "#include \"$className.h\"\n\n");
714     push(@implContentHeader, "#include <wtf/GetPtr.h>\n\n");
715
716     push(@implContentHeader, "#include <kjs/PropertyNameArray.h>\n") if $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"};
717
718     AddIncludesForType($interfaceName);
719
720     @implContent = ();
721
722     push(@implContent, "\nusing namespace JSC;\n\n");
723     push(@implContent, "namespace WebCore {\n\n");
724
725     push(@implContent, "ASSERT_CLASS_FITS_IN_CELL($className)\n\n");
726
727     # - Add all attributes in a hashtable definition
728     my $numAttributes = @{$dataNode->attributes};
729     $numAttributes++ if $dataNode->extendedAttributes->{"GenerateConstructor"};
730
731     if ($numAttributes > 0) {
732         my $hashName = $className . "Table";
733
734         my @hashKeys = ();      # ie. 'insertBefore'
735         my @hashValues = ();    # ie. 'JSNode::InsertBefore'
736         my @hashSpecials = ();    # ie. 'DontDelete|Function'
737         my @hashParameters = ();  # ie. '2'
738
739         foreach my $attribute (@{$dataNode->attributes}) {
740             my $name = $attribute->signature->name;
741             push(@hashKeys, $name);
742
743             my $value = $className . "::" . $codeGenerator->WK_ucfirst($attribute->signature->name)
744                 . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
745                 . "AttrNum";
746             push(@hashValues, $value);
747
748             my @specials = ();
749             push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
750             push(@specials, "DontEnum") if $attribute->signature->extendedAttributes->{"DontEnum"};
751             push(@specials, "ReadOnly") if $attribute->type =~ /readonly/;
752             my $special = (@specials > 0) ? join("|", @specials) : "0";
753             push(@hashSpecials, $special);
754
755             my $numParameters = "0";
756             push(@hashParameters, $numParameters);
757         }
758
759         if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
760             push(@hashKeys, "constructor");
761             push(@hashValues, $className . "::ConstructorAttrNum");
762             push(@hashSpecials, "DontEnum");
763             push(@hashParameters, "0");
764         }
765
766         $object->GenerateHashTable($hashName,
767                                    \@hashKeys, \@hashValues,
768                                    \@hashSpecials, \@hashParameters);
769     }
770
771     my $numConstants = @{$dataNode->constants};
772     my $numFunctions = @{$dataNode->functions};
773
774     # - Add all constants
775     if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
776         $hashName = $className . "ConstructorTable";
777
778         @hashKeys = ();
779         @hashValues = ();
780         @hashSpecials = ();
781         @hashParameters = ();
782
783         foreach my $constant (@{$dataNode->constants}) {
784             my $name = $constant->name;
785             push(@hashKeys, $name);
786
787             my $value = $constant->value;
788             push(@hashValues, $value);
789
790             my $special = "DontDelete|ReadOnly";
791             push(@hashSpecials, $special);
792
793             my $numParameters = 0;
794             push(@hashParameters, $numParameters);
795         }
796
797         $object->GenerateHashTable($hashName,
798                                    \@hashKeys, \@hashValues,
799                                    \@hashSpecials, \@hashParameters);
800
801         my $protoClassName;
802         $protoClassName = "${className}Prototype";
803
804         push(@implContent, constructorFor($className, $protoClassName, $interfaceName, $visibleClassName, $dataNode->extendedAttributes->{"CanBeConstructed"}));
805     }
806
807     # - Add functions and constants to a hashtable definition
808     $hashName = $className . "PrototypeTable";
809
810     @hashKeys = ();
811     @hashValues = ();
812     @hashSpecials = ();
813     @hashParameters = ();
814
815     foreach my $constant (@{$dataNode->constants}) {
816         my $name = $constant->name;
817         push(@hashKeys, $name);
818
819         my $value = $constant->value;
820         push(@hashValues, $value);
821
822         my $special = "DontDelete|ReadOnly";
823         push(@hashSpecials, $special);
824
825         my $numParameters = 0;
826         push(@hashParameters, $numParameters);
827     }
828
829     foreach my $function (@{$dataNode->functions}) {
830         my $name = $function->signature->name;
831         push(@hashKeys, $name);
832
833         my $value = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($name);
834         push(@hashValues, $value);
835
836         my @specials = ();
837         push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
838         push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"DontEnum"};
839         push(@specials, "Function");        
840         my $special = (@specials > 0) ? join("|", @specials) : "0";
841         push(@hashSpecials, $special);
842
843         my $numParameters = @{$function->parameters};
844         push(@hashParameters, $numParameters);
845     }
846
847     $object->GenerateHashTable($hashName,
848                                \@hashKeys, \@hashValues,
849                                \@hashSpecials, \@hashParameters);
850
851     push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", 0, &${className}PrototypeTable, 0 };\n\n");
852     if ($interfaceName ne "DOMWindow") {
853         push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec)\n");
854         push(@implContent, "{\n");
855         push(@implContent, "    return getDOMPrototype<${className}>(exec);\n");
856         push(@implContent, "}\n\n");
857     }
858     if ($interfaceName eq "DOMWindow") {
859         push(@implContent, "void* ${className}Prototype::operator new(size_t size)\n");
860         push(@implContent, "{\n");
861         push(@implContent, "    return JSDOMWindow::commonJSGlobalData()->heap->allocate(size);\n");
862         push(@implContent, "}\n\n");
863     }
864     if ($numConstants > 0 || $numFunctions > 0) {
865         push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
866         push(@implContent, "{\n");
867         if ($numConstants eq 0) {
868             push(@implContent, "    return getStaticFunctionSlot<JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
869         } elsif ($numFunctions eq 0) {
870             push(@implContent, "    return getStaticValueSlot<${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
871         } else {
872             push(@implContent, "    return getStaticPropertySlot<${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
873         }
874         push(@implContent, "}\n\n");
875     }
876     if ($numConstants ne 0) {
877         $implKJSInclude{"JSNumberCell.h"} = 1;
878         push(@implContent, "JSValue* ${className}Prototype::getValueProperty(ExecState* exec, int token) const\n{\n");
879         push(@implContent, "    // The token is the numeric value of its associated constant\n");
880         push(@implContent, "    return jsNumber(exec, token);\n}\n\n");
881     }
882
883     # - Initialize static ClassInfo object
884     push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleClassName}\", ");
885     if ($hasParent) {
886         push(@implContent, "&" . $parentClassName . "::s_info, ");
887     } else {
888         push(@implContent, "0, ");
889     }
890
891     if ($numAttributes > 0) {
892         push(@implContent, "&${className}Table ");
893     } else {
894         push(@implContent, "0 ");
895     }
896     push(@implContent, ", 0 ");
897     push(@implContent, "};\n\n");
898
899     # Get correct pass/store types respecting PODType flag
900     my $podType = $dataNode->extendedAttributes->{"PODType"};
901     my $implType = $podType ? "JSSVGPODTypeWrapper<$podType> " : $implClassName;
902
903     my $needsSVGContext = IsSVGTypeNeedingContextParameter($implClassName);
904     my $parentNeedsSVGContext = ($needsSVGContext and $parentClassName =~ /SVG/);
905
906     # Constructor
907     if ($interfaceName eq "DOMWindow") {
908         AddIncludesForType("JSDOMWindowShell");
909         push(@implContent, "${className}::$className(PassRefPtr<StructureID> structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n");
910         push(@implContent, "    : $parentClassName(structure, impl, shell)\n");
911     } else {
912         push(@implContent, "${className}::$className(PassRefPtr<StructureID> structure, PassRefPtr<$implType> impl" . ($needsSVGContext ? ", SVGElement* context" : "") . ")\n");
913         if ($hasParent) {
914             push(@implContent, "    : $parentClassName(structure, impl" . ($parentNeedsSVGContext ? ", context" : "") . ")\n");
915         } else {
916             push(@implContent, "    : $parentClassName(structure)\n");
917             push(@implContent, "    , m_context(context)\n") if $needsSVGContext;
918             push(@implContent, "    , m_impl(impl)\n");  
919         }
920     }
921     push(@implContent, "{\n");
922     push(@implContent, "}\n\n");
923
924     # Destructor
925     if (!$hasParent) {
926         push(@implContent, "${className}::~$className()\n");
927         push(@implContent, "{\n");
928
929         if ($interfaceName eq "Node") {
930             push(@implContent, "    forgetDOMNode(m_impl->document(), m_impl.get());\n");
931         } else {
932             if ($podType) {
933                 my $animatedType = $implClassName;
934                 $animatedType =~ s/SVG/SVGAnimated/;
935
936                 # Special case for JSSVGNumber
937                 if ($codeGenerator->IsSVGAnimatedType($animatedType) and $podType ne "float") {
938                     push(@implContent, "    JSSVGDynamicPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n");
939                 }
940             }
941             push(@implContent, "    forgetDOMObject(m_impl.get());\n");
942         }
943
944         push(@implContent, "\n}\n\n");
945     }
946
947     # Document needs a special destructor because it's a special case for caching. It needs
948     # its own special handling rather than relying on the caching that Node normally does.
949     if ($interfaceName eq "Document") {
950         push(@implContent, "${className}::~$className()\n");
951         push(@implContent, "{\n    forgetDOMObject(static_cast<${implClassName}*>(impl()));\n}\n\n");
952     }
953
954     if ($interfaceName ne "DOMWindow") {
955         push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec)\n");
956         push(@implContent, "{\n");
957         if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") {
958             push(@implContent, "    return new (exec) ${className}Prototype(${className}Prototype::createStructureID(${parentClassName}Prototype::self(exec)));\n");
959         } else {
960             push(@implContent, "    return new (exec) ${className}Prototype(${className}Prototype::createStructureID(exec->lexicalGlobalObject()->objectPrototype()));\n");
961         }
962         push(@implContent, "}\n\n");
963     }
964
965     my $hasGetter = $numAttributes > 0 
966                  || $dataNode->extendedAttributes->{"GenerateConstructor"} 
967                  || $dataNode->extendedAttributes->{"HasIndexGetter"}
968                  || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}
969                  || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}
970                  || $dataNode->extendedAttributes->{"HasNameGetter"}
971                  || $dataNode->extendedAttributes->{"HasOverridingNameGetter"};
972
973     # Attributes
974     if ($hasGetter) {
975         if (!$dataNode->extendedAttributes->{"InlineGetOwnPropertySlot"}) {
976             push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
977             push(@implContent, "{\n");
978             push(@implContent, GenerateGetOwnPropertySlotBody($dataNode, $interfaceName, $className, $implClassName, $numAttributes > 0, 0));
979             push(@implContent, "}\n\n");
980         }
981
982         if (($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) 
983                 && !$dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
984             push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)\n");
985             push(@implContent, "{\n");
986             push(@implContent, "    if (propertyName < static_cast<$implClassName*>(impl())->length()) {\n");
987             if ($dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
988                 push(@implContent, "        slot.setValue(getByIndex(exec, propertyName));\n");
989             } else {
990                 push(@implContent, "        slot.setCustomIndex(this, propertyName, indexGetter);\n");
991             }
992             push(@implContent, "        return true;\n");
993             push(@implContent, "    }\n");
994             push(@implContent, "    return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);\n");
995             push(@implContent, "}\n\n");
996         }
997         
998         if ($numAttributes > 0) {
999             push(@implContent, "JSValue* ${className}::getValueProperty(ExecState* exec, int token) const\n");
1000             push(@implContent, "{\n");
1001
1002             push(@implContent, "    switch (token) {\n");
1003
1004             foreach my $attribute (@{$dataNode->attributes}) {
1005                 my $getterFunctionName = $codeGenerator->WK_lcfirst($attribute->signature->name);
1006
1007                 my $implClassNameForValueConversion = "";
1008                 if (!$podType and ($codeGenerator->IsSVGAnimatedType($implClassName) or $attribute->type !~ /^readonly/)) {
1009                     $implClassNameForValueConversion = $implClassName;
1010                 }
1011
1012                 push(@implContent, "    case " . $codeGenerator->WK_ucfirst($attribute->signature->name)
1013                     . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
1014                     . "AttrNum: {\n");
1015
1016                 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && 
1017                     !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"} &&
1018                     !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurityOnGet"}) {
1019                     push(@implContent, "        if (!allowsAccessFrom(exec))\n");
1020                     push(@implContent, "            return jsUndefined();\n");
1021                 }
1022
1023                 if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomGetter"}) {
1024                     push(@implContent, "        return $getterFunctionName(exec);\n");
1025                 } elsif ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
1026                     $implIncludes{"JSDOMBinding.h"} = 1;
1027                     push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
1028                     push(@implContent, "        return checkNodeSecurity(exec, imp->$getterFunctionName()) ? " . NativeToJSValue($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$getterFunctionName()") . " : jsUndefined();\n");
1029                 } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
1030                     $implIncludes{"Document.h"} = 1;
1031                     $implIncludes{"JSDOMBinding.h"} = 1;
1032                     push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
1033                     push(@implContent, "        return checkNodeSecurity(exec, imp->contentDocument()) ? " . NativeToJSValue($attribute->signature,  0, $implClassName, $implClassNameForValueConversion, "imp->$getterFunctionName()") . " : jsUndefined();\n");
1034                 } elsif ($attribute->signature->type =~ /Constructor$/) {
1035                     my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
1036                     $constructorType =~ s/Constructor$//;
1037                     push(@implContent, "        return JS" . $constructorType . "::getConstructor(exec);\n");
1038                 } elsif (!@{$attribute->getterExceptions}) {
1039                     if ($podType) {
1040                         push(@implContent, "        $podType imp(*impl());\n");
1041                         if ($podType eq "float") { # Special case for JSSVGNumber
1042                             push(@implContent, "        return " . NativeToJSValue($attribute->signature, 0, $implClassName, "", "imp") . ";\n");
1043                         } else {
1044                             push(@implContent, "        return " . NativeToJSValue($attribute->signature, 0, $implClassName, "", "imp.$getterFunctionName()") . ";\n");
1045                         }
1046                     } else {
1047                         push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
1048                         my $type = $codeGenerator->StripModule($attribute->signature->type);
1049                         my $jsType = NativeToJSValue($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$getterFunctionName()");
1050                         if ($codeGenerator->IsSVGAnimatedType($type)) {
1051                             push(@implContent, "        RefPtr<$type> obj = $jsType;\n");
1052                             push(@implContent, "        return toJS(exec, obj.get(), imp);\n");
1053                         } else {
1054                             push(@implContent, "        return $jsType;\n");
1055                         }
1056                     }
1057                 } else {
1058                     push(@implContent, "        ExceptionCode ec = 0;\n");
1059
1060                     if ($podType) {
1061                         push(@implContent, "        $podType imp(*impl());\n");
1062                         push(@implContent, "        JSC::JSValue* result = " . NativeToJSValue($attribute->signature, 0, $implClassName, "", "imp.$getterFunctionName(ec)") . ";\n");
1063                     } else {
1064                         push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
1065                         push(@implContent, "        JSC::JSValue* result = " . NativeToJSValue($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$getterFunctionName(ec)") . ";\n");
1066                     }
1067
1068                     push(@implContent, "        setDOMException(exec, ec);\n");
1069                     push(@implContent, "        return result;\n");
1070                 }
1071                 push(@implContent, "    }\n");
1072             }
1073
1074             if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
1075                 push(@implContent, "    case ConstructorAttrNum:\n");
1076                 push(@implContent, "        return getConstructor(exec);\n");
1077             }
1078
1079             push(@implContent, "    }\n");
1080             push(@implContent, "    return 0;\n");
1081             push(@implContent, "}\n\n");
1082         }
1083
1084         # Check if we have any writable attributes
1085         my $hasReadWriteProperties = 0;
1086         foreach my $attribute (@{$dataNode->attributes}) {
1087             $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
1088         }
1089
1090         my $hasSetter = $hasReadWriteProperties
1091                      || $dataNode->extendedAttributes->{"CustomPutFunction"}
1092                      || $dataNode->extendedAttributes->{"HasCustomIndexSetter"};
1093
1094         if ($hasSetter) {
1095             push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)\n");
1096             push(@implContent, "{\n");
1097             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1098                 push(@implContent, "    bool ok;\n");
1099                 push(@implContent, "    unsigned index = propertyName.toUInt32(&ok, false);\n");
1100                 push(@implContent, "    if (ok) {\n");
1101                 push(@implContent, "        indexSetter(exec, index, value);\n");
1102                 push(@implContent, "        return;\n");
1103                 push(@implContent, "    }\n");
1104             }
1105             if ($dataNode->extendedAttributes->{"CustomPutFunction"}) {
1106                 push(@implContent, "    if (customPut(exec, propertyName, value, slot))\n");
1107                 push(@implContent, "        return;\n");
1108             }
1109
1110             if ($hasReadWriteProperties) {
1111                 push(@implContent, "    lookupPut<$className, Base>(exec, propertyName, value, &${className}Table, this, slot);\n");
1112             } else {
1113                 push(@implContent, "    Base::put(exec, propertyName, value, slot);\n");
1114             }
1115             push(@implContent, "}\n\n");
1116
1117             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1118                 push(@implContent, "void ${className}::put(ExecState* exec, unsigned propertyName, JSValue* value)\n");
1119                 push(@implContent, "{\n");
1120                 push(@implContent, "    indexSetter(exec, propertyName, value);\n");
1121                 push(@implContent, "    return;\n");
1122                 push(@implContent, "}\n\n");
1123             }
1124
1125             if ($hasReadWriteProperties) {
1126                 push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value)\n");
1127                 push(@implContent, "{\n");
1128
1129                 push(@implContent, "    switch (token) {\n");
1130
1131                 foreach my $attribute (@{$dataNode->attributes}) {
1132                     if ($attribute->type !~ /^readonly/) {
1133                         my $name = $attribute->signature->name;
1134                         my $setterFunctionName = $codeGenerator->WK_ucfirst($name);
1135
1136                         push(@implContent, "    case " . $codeGenerator->WK_ucfirst($attribute->signature->name)
1137                             . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
1138                             . "AttrNum: {\n");
1139
1140                         if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1141                             if ($interfaceName eq "DOMWindow") {
1142                                 push(@implContent, "        if (!allowsAccessFrom(exec))\n");
1143                             } else {
1144                                 push(@implContent, "        if (!allowsAccessFromFrame(exec, impl()->frame()))\n");
1145                             }
1146                             push(@implContent, "            return;\n");
1147                         }
1148
1149                         if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomSetter"}) {
1150                             push(@implContent, "        set$setterFunctionName(exec, value);\n");
1151                         } elsif ($attribute->signature->type =~ /Constructor$/) {
1152                             my $constructorType = $attribute->signature->type;
1153                             $constructorType =~ s/Constructor$//;
1154                             $implIncludes{"JS" . $constructorType . ".h"} = 1;
1155                             push(@implContent, "        // Shadowing a built-in constructor\n");
1156                             push(@implContent, "        putDirect(Identifier(exec, \"$name\"), value);\n");
1157                         } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
1158                             push(@implContent, "        putDirect(Identifier(exec, \"$name\"), value);\n");
1159                         } else {
1160                             if ($podType) {
1161                                 push(@implContent, "        $podType imp(*impl());\n");
1162                                 if ($podType eq "float") { # Special case for JSSVGNumber
1163                                     push(@implContent, "        imp = " . JSValueToNative($attribute->signature, "value") . ";\n");
1164                                 } else {
1165                                     push(@implContent, "        imp.set$setterFunctionName(" . JSValueToNative($attribute->signature, "value") . ");\n");
1166                                 }
1167                                 push(@implContent, "        m_impl->commitChange(imp, context());\n");
1168                             } else {
1169                                 push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
1170                                 push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
1171                                 push(@implContent, "        imp->set$setterFunctionName(" . JSValueToNative($attribute->signature, "value"));
1172                                 push(@implContent, ", ec") if @{$attribute->setterExceptions};
1173                                 push(@implContent, ");\n");
1174                                 push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
1175
1176                                 if (IsSVGTypeNeedingContextParameter($implClassName)) {
1177                                     push(@implContent, "        if (context())\n");
1178                                     push(@implContent, "            context()->svgAttributeChanged(impl()->associatedAttributeName());\n");
1179                                 }
1180                             }
1181                         }
1182                         push(@implContent, "        break;\n");
1183                         push(@implContent, "    }\n");
1184                     }
1185                 }
1186                 push(@implContent, "    }\n"); # end switch
1187                 push(@implContent, "}\n\n"); # end function
1188             }
1189         }
1190     }
1191
1192     if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"} || $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
1193         push(@implContent, "void ${className}::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)\n");
1194         push(@implContent, "{\n");
1195         if ($dataNode->extendedAttributes->{"CustomGetPropertyNames"}) {
1196             push(@implContent, "    if (customGetPropertyNames(exec, propertyNames))\n");
1197             push(@implContent, "        return;\n");
1198         }
1199         if ($dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasCustomIndexGetter"}) {
1200             push(@implContent, "    for (unsigned i = 0; i < static_cast<${implClassName}*>(impl())->length(); ++i)\n");
1201             push(@implContent, "        propertyNames.add(Identifier::from(exec, i));\n");
1202         }
1203         push(@implContent, "     Base::getPropertyNames(exec, propertyNames);\n");
1204         push(@implContent, "}\n\n");
1205     }
1206
1207     if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
1208         push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
1209         push(@implContent, "    return getDOMConstructor<${className}Constructor>(exec);\n");
1210         push(@implContent, "}\n\n");
1211     }
1212
1213     # Functions
1214     if ($numFunctions > 0) {
1215         foreach my $function (@{$dataNode->functions}) {
1216             AddIncludesForType($function->signature->type);
1217
1218             my $functionName = $codeGenerator->WK_lcfirst($className) . "PrototypeFunction" . $codeGenerator->WK_ucfirst($function->signature->name);
1219             my $functionImplementationName = $function->signature->extendedAttributes->{"ImplementationFunction"} || $codeGenerator->WK_lcfirst($function->signature->name);
1220
1221             push(@implContent, "JSValue* ${functionName}(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)\n");
1222             push(@implContent, "{\n");
1223
1224             $implKJSInclude{"Error.h"} = 1;
1225
1226             if ($interfaceName eq "DOMWindow") {
1227                 push(@implContent, "    $className* castedThisObj = toJSDOMWindow(thisValue);\n");
1228                 push(@implContent, "    if (!castedThisObj)\n");
1229                 push(@implContent, "        return throwError(exec, TypeError);\n");
1230             } else {
1231                 push(@implContent, "    if (!thisValue->isObject(&${className}::s_info))\n");
1232                 push(@implContent, "        return throwError(exec, TypeError);\n");
1233                 push(@implContent, "    $className* castedThisObj = static_cast<$className*>(thisValue);\n");
1234             }
1235
1236             if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && 
1237                 !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1238                 push(@implContent, "    if (!castedThisObj->allowsAccessFrom(exec))\n");
1239                 push(@implContent, "        return jsUndefined();\n");
1240             }
1241
1242             if ($function->signature->extendedAttributes->{"Custom"}) {
1243                 push(@implContent, "    return castedThisObj->" . $functionImplementationName . "(exec, args);\n");
1244             } else {
1245                 if ($podType) {
1246                     push(@implContent, "    JSSVGPODTypeWrapper<$podType>* wrapper = castedThisObj->impl();\n");
1247                     push(@implContent, "    $podType imp(*wrapper);\n");
1248                 } else {
1249                     push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(castedThisObj->impl());\n");
1250                 }
1251
1252                 my $numParameters = @{$function->parameters};
1253
1254                 if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) {
1255                         push(@implContent, "    if (args.size() < $numParameters)\n");
1256                         push(@implContent, "        return jsUndefined();\n");
1257                 }
1258
1259                 if (@{$function->raisesExceptions}) {
1260                     push(@implContent, "    ExceptionCode ec = 0;\n");
1261                 }
1262
1263                 if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
1264                     push(@implContent, "    if (!checkNodeSecurity(exec, imp->getSVGDocument(" . (@{$function->raisesExceptions} ? "ec" : "") .")))\n");
1265                     push(@implContent, "        return jsUndefined();\n");
1266                     $implIncludes{"JSDOMBinding.h"} = 1;
1267                 }
1268
1269                 my $paramIndex = 0;
1270                 my $functionString = "imp" . ($podType ? "." : "->") . $functionImplementationName . "(";
1271
1272                 my $hasOptionalArguments = 0;
1273
1274                 foreach my $parameter (@{$function->parameters}) {
1275                     if (!$hasOptionalArguments && $parameter->extendedAttributes->{"Optional"}) {
1276                         push(@implContent, "\n    int argsCount = args.size();\n");
1277                         $hasOptionalArguments = 1;
1278                     }
1279
1280                     if ($hasOptionalArguments) {
1281                         push(@implContent, "    if (argsCount < " . ($paramIndex + 1) . ") {\n");
1282                         GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 2, $podType, $implClassName);
1283                         push(@implContent, "    }\n\n");
1284                     }
1285
1286                     my $name = $parameter->name;
1287                     
1288                     if ($parameter->type eq "XPathNSResolver") {
1289                         push(@implContent, "    RefPtr<XPathNSResolver> customResolver;\n");
1290                         push(@implContent, "    XPathNSResolver* resolver = toXPathNSResolver(args.at(exec, $paramIndex));\n");
1291                         push(@implContent, "    if (!resolver) {\n");
1292                         push(@implContent, "        customResolver = JSCustomXPathNSResolver::create(exec, args.at(exec, $paramIndex));\n");
1293                         push(@implContent, "        if (exec->hadException())\n");
1294                         push(@implContent, "            return jsUndefined();\n");
1295                         push(@implContent, "        resolver = customResolver.get();\n");
1296                         push(@implContent, "    }\n");
1297                     } else {
1298                         push(@implContent, "    " . GetNativeTypeFromSignature($parameter) . " $name = " . JSValueToNative($parameter, "args.at(exec, $paramIndex)") . ";\n");
1299
1300                         # If a parameter is "an index" and it's negative it should throw an INDEX_SIZE_ERR exception.
1301                         # But this needs to be done in the bindings, because the type is unsigned and the fact that it
1302                         # was negative will be lost by the time we're inside the DOM.
1303                         if ($parameter->extendedAttributes->{"IsIndex"}) {
1304                             $implIncludes{"ExceptionCode.h"} = 1;
1305                             push(@implContent, "    if ($name < 0) {\n");
1306                             push(@implContent, "        setDOMException(exec, INDEX_SIZE_ERR);\n");
1307                             push(@implContent, "        return jsUndefined();\n");
1308                             push(@implContent, "    }\n");
1309                         }
1310                     }
1311
1312                     $functionString .= ", " if $paramIndex;
1313
1314                     if ($parameter->type eq "NodeFilter") {
1315                         $functionString .= "$name.get()";
1316                     } else {
1317                         $functionString .= $name;
1318                     }
1319
1320                     $paramIndex++;
1321                 }
1322
1323                 push(@implContent, "\n");
1324                 GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    ", $podType, $implClassName);
1325             }
1326             push(@implContent, "}\n\n");
1327         }
1328     }
1329
1330     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
1331         push(@implContent, "\nJSValue* ${className}::indexGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)\n");
1332         push(@implContent, "{\n");
1333         push(@implContent, "    ${className}* thisObj = static_cast<$className*>(slot.slotBase());\n");
1334         if (IndexGetterReturnsStrings($implClassName)) {
1335             $implIncludes{"KURL.h"} = 1;
1336             push(@implContent, "    return jsStringOrNull(exec, thisObj->impl()->item(slot.index()));\n");
1337         } else {
1338             push(@implContent, "    return toJS(exec, static_cast<$implClassName*>(thisObj->impl())->item(slot.index()));\n");
1339         }
1340         push(@implContent, "}\n");
1341         if ($interfaceName eq "HTMLCollection") {
1342             $implIncludes{"JSNode.h"} = 1;
1343             $implIncludes{"Node.h"} = 1;
1344         }
1345     }
1346
1347     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !UsesManualToJSImplementation($implClassName)) {
1348         if ($podType) {
1349             push(@implContent, "JSC::JSValue* toJS(JSC::ExecState* exec, JSSVGPODTypeWrapper<$podType>* object, SVGElement* context)\n");
1350         } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
1351              push(@implContent, "JSC::JSValue* toJS(JSC::ExecState* exec, $implType* object, SVGElement* context)\n");
1352         } else {
1353             push(@implContent, "JSC::JSValue* toJS(JSC::ExecState* exec, $implType* object)\n");
1354         }
1355
1356         push(@implContent, "{\n");
1357         if ($podType) {
1358             push(@implContent, "    return getDOMObjectWrapper<$className, JSSVGPODTypeWrapper<$podType> >(exec, object, context);\n");
1359         } elsif (IsSVGTypeNeedingContextParameter($implClassName)) {
1360             push(@implContent, "    return getDOMObjectWrapper<$className>(exec, object, context);\n");
1361         } else {
1362             push(@implContent, "    return getDOMObjectWrapper<$className>(exec, object);\n");
1363         }
1364         push(@implContent, "}\n");
1365     }
1366
1367     if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) {
1368         if ($podType) {
1369             push(@implContent, "$podType to${interfaceName}(JSC::JSValue* val)\n");
1370         } else {
1371             push(@implContent, "$implClassName* to${interfaceName}(JSC::JSValue* val)\n");
1372         }
1373
1374         push(@implContent, "{\n");
1375
1376         push(@implContent, "    return val->isObject(&${className}::s_info) ? " . ($podType ? "($podType) *" : "") . "static_cast<$className*>(val)->impl() : ");
1377         if ($podType and $podType ne "float") {
1378             push(@implContent, "$podType();\n}\n");
1379         } else {
1380             push(@implContent, "0;\n}\n");
1381         }
1382     }
1383
1384     push(@implContent, "\n}\n");
1385
1386     push(@implContent, "\n#endif // ${conditionalString}\n") if $conditional;
1387 }
1388
1389 sub GenerateImplementationFunctionCall()
1390 {
1391     my $function = shift;
1392     my $functionString = shift;
1393     my $paramIndex = shift;
1394     my $indent = shift;
1395     my $podType = shift;
1396     my $implClassName = shift;
1397
1398     if (@{$function->raisesExceptions}) {
1399         $functionString .= ", " if $paramIndex;
1400         $functionString .= "ec";
1401     }
1402     $functionString .= ")";
1403
1404     if ($function->signature->type eq "void") {
1405         push(@implContent, $indent . "$functionString;\n");
1406         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
1407
1408         if ($podType) {
1409             push(@implContent, $indent . "wrapper->commitChange(imp, castedThisObj->context());\n");
1410         }
1411
1412         push(@implContent, $indent . "return jsUndefined();\n");
1413     } else {
1414         push(@implContent, "\n" . $indent . "JSC::JSValue* result = " . NativeToJSValue($function->signature, 1, $implClassName, "", $functionString) . ";\n");
1415         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
1416
1417         if ($podType) {
1418             push(@implContent, $indent . "wrapper->commitChange(imp, castedThisObj->context());\n");
1419         }
1420
1421         push(@implContent, $indent . "return result;\n");
1422     }
1423 }
1424
1425 sub GetNativeTypeFromSignature
1426 {
1427     my $signature = shift;
1428     my $type = $codeGenerator->StripModule($signature->type);
1429
1430     if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
1431         # Special-case index arguments because we need to check that they aren't < 0.
1432         return "int";
1433     }
1434
1435     return GetNativeType($type);
1436 }
1437
1438 my %nativeType = (
1439     "CompareHow" => "Range::CompareHow",
1440     "DOMString" => "const UString&",
1441     "EventTarget" => "EventTargetNode*",
1442     "NodeFilter" => "RefPtr<NodeFilter>",
1443     "SVGLength" => "SVGLength",
1444     "SVGMatrix" => "AffineTransform",
1445     "SVGNumber" => "float",
1446     "SVGPaintType" => "SVGPaint::SVGPaintType",
1447     "SVGPoint" => "FloatPoint",
1448     "SVGRect" => "FloatRect",
1449     "SVGTransform" => "SVGTransform",
1450     "boolean" => "bool",
1451     "double" => "double",
1452     "float" => "float",
1453     "long" => "int",
1454     "unsigned long" => "unsigned",
1455     "unsigned short" => "unsigned short",
1456 );
1457
1458 sub GetNativeType
1459 {
1460     my $type = shift;
1461
1462     return $nativeType{$type} if exists $nativeType{$type};
1463
1464     # For all other types, the native type is a pointer with same type name as the IDL type.
1465     return "${type}*";
1466 }
1467
1468 sub JSValueToNative
1469 {
1470     my $signature = shift;
1471     my $value = shift;
1472
1473     my $type = $codeGenerator->StripModule($signature->type);
1474
1475     return "$value->toBoolean(exec)" if $type eq "boolean";
1476     return "$value->toNumber(exec)" if $type eq "double";
1477     return "$value->toFloat(exec)" if $type eq "float" or $type eq "SVGNumber";
1478     return "$value->toInt32(exec)" if $type eq "unsigned long" or $type eq "long" or $type eq "unsigned short";
1479
1480     return "static_cast<Range::CompareHow>($value->toInt32(exec))" if $type eq "CompareHow";
1481     return "static_cast<SVGPaint::SVGPaintType>($value->toInt32(exec))" if $type eq "SVGPaintType";
1482
1483     if ($type eq "DOMString") {
1484         return "valueToStringWithNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
1485         return "valueToStringWithUndefinedOrNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"};
1486         return "$value->toString(exec)";
1487     }
1488
1489     if ($type eq "EventTarget") {
1490         $implIncludes{"JSEventTargetNode.h"} = 1;
1491         return "toEventTargetNode($value)";
1492     }
1493
1494     $implIncludes{"FloatPoint.h"} = 1 if $type eq "SVGPoint";
1495     $implIncludes{"FloatRect.h"} = 1 if $type eq "SVGRect";
1496     $implIncludes{"HTMLOptionElement.h"} = 1 if $type eq "HTMLOptionElement";
1497     $implIncludes{"JSCustomVoidCallback.h"} = 1 if $type eq "VoidCallback";
1498
1499     # Default, assume autogenerated type conversion routines
1500     $implIncludes{"JS$type.h"} = 1;
1501     return "to$type($value)";
1502 }
1503
1504 sub NativeToJSValue
1505 {
1506     my $signature = shift;
1507     my $inFunctionCall = shift;
1508     my $implClassName = shift;
1509     my $implClassNameForValueConversion = shift;
1510     my $value = shift;
1511
1512     my $type = $codeGenerator->StripModule($signature->type);
1513
1514     return "jsBoolean($value)" if $type eq "boolean";
1515     
1516     if ($codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType" or $type eq "DOMTimeStamp") {
1517         $implKJSInclude{"JSNumberCell.h"} = 1;
1518         return "jsNumber(exec, $value)";
1519     }
1520
1521     if ($codeGenerator->IsStringType($type)) {
1522         $implIncludes{"KURL.h"} = 1;
1523         my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1524         if (defined $conv) {
1525             return "jsStringOrNull(exec, $value)" if $conv eq "Null";
1526             return "jsStringOrUndefined(exec, $value)" if $conv eq "Undefined";
1527             return "jsStringOrFalse(exec, $value)" if $conv eq "False";
1528
1529             die "Unknown value for ConvertNullStringTo extended attribute";
1530         }
1531         $implKJSInclude{"JSString.h"} = 1;
1532         return "jsString(exec, $value)";
1533     }
1534
1535     if ($type eq "RGBColor") {
1536         $implIncludes{"JS$type.h"} = 1;
1537         return "getJSRGBColor(exec, $value)";
1538     }
1539
1540     if ($codeGenerator->IsPodType($type)) {
1541         $implIncludes{"JS$type.h"} = 1;
1542
1543         my $nativeType = GetNativeType($type);
1544
1545         my $getter = $value;
1546         $getter =~ s/imp->//;
1547         $getter =~ s/\(\)//;
1548
1549         my $setter = "set" . $codeGenerator->WK_ucfirst($getter);
1550
1551         # Function calls will never return 'modifyable' POD types (ie. SVGRect getBBox()) - no need to keep track changes to the returned SVGRect
1552         if ($inFunctionCall eq 0
1553             and not $codeGenerator->IsSVGAnimatedType($implClassName)
1554             and $codeGenerator->IsPodTypeWithWriteableProperties($type)
1555             and not defined $signature->extendedAttributes->{"Immutable"}) {
1556             if ($codeGenerator->IsPodType($implClassName)) {
1557                 return "toJS(exec, JSSVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>::create($value, impl()).get(), context())";
1558             } else {
1559                 return "toJS(exec, JSSVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>::create(imp, &${implClassName}::$getter, &${implClassName}::$setter).get(), imp)";
1560             }
1561         }
1562
1563         if ($implClassNameForValueConversion eq "") {
1564             if (IsSVGTypeNeedingContextParameter($implClassName)) {
1565                 return "toJS(exec, JSSVGStaticPODTypeWrapper<$nativeType>::create($value).get(), castedThisObj->context())" if $inFunctionCall eq 1;
1566
1567                 # Special case: SVGZoomEvent - it doesn't have a context, but it's no problem, as there are no readwrite props
1568                 return "toJS(exec, JSSVGStaticPODTypeWrapper<$nativeType>::create($value).get(), 0)" if $implClassName eq "SVGZoomEvent";
1569                 return "toJS(exec, JSSVGStaticPODTypeWrapper<$nativeType>::create($value).get(), context())";
1570             } else {
1571                 return "toJS(exec, JSSVGStaticPODTypeWrapper<$nativeType>::create($value).get(), imp)";
1572             }
1573         } else { # These classes, always have a m_context pointer!
1574             return "toJS(exec, JSSVGDynamicPODTypeWrapperCache<$nativeType, $implClassNameForValueConversion>::lookupOrCreateWrapper(imp, &${implClassNameForValueConversion}::$getter, &${implClassNameForValueConversion}::$setter).get(), context())";
1575         }
1576     }
1577
1578     if ($codeGenerator->IsSVGAnimatedType($type)) {
1579         $value =~ s/\(\)//;
1580         $value .= "Animated()";
1581     }
1582
1583     if ($type eq "CSSStyleDeclaration") {
1584         $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
1585     }
1586
1587     if ($type eq "NamedNodeMap") {
1588         $implIncludes{"NamedAttrMap.h"} = 1;
1589     }
1590
1591     if ($type eq "NodeList") {
1592         $implIncludes{"NameNodeList.h"} = 1;
1593     }
1594
1595     if ($type eq "EventTarget") {
1596         $implIncludes{"EventTargetNode.h"} = 1;
1597         $implIncludes{"JSEventTargetNode.h"} = 1;
1598     } elsif ($type eq "DOMObject") {
1599         $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
1600     } elsif ($type =~ /SVGPathSeg/) {
1601         $implIncludes{"JS$type.h"} = 1;
1602         $joinedName = $type;
1603         $joinedName =~ s/Abs|Rel//;
1604         $implIncludes{"$joinedName.h"} = 1;
1605     } else {
1606         # Default, include header with same name.
1607         $implIncludes{"JS$type.h"} = 1;
1608         $implIncludes{"$type.h"} = 1;
1609     }
1610
1611     return $value if $codeGenerator->IsSVGAnimatedType($type);
1612
1613     if (IsSVGTypeNeedingContextParameter($type)) {
1614         if (IsSVGTypeNeedingContextParameter($implClassName)) {
1615             if ($inFunctionCall eq 1) {
1616                 return "toJS(exec, WTF::getPtr($value), castedThisObj->context())";
1617             } else {
1618                 return "toJS(exec, WTF::getPtr($value), context())";
1619             }
1620         } else {
1621             return "toJS(exec, WTF::getPtr($value), imp)";
1622         }
1623     }
1624
1625     if ($signature->extendedAttributes->{"ReturnsNew"}) {        
1626         return "toJSNewlyCreated(exec, WTF::getPtr($value))";
1627     }
1628
1629     return "toJS(exec, WTF::getPtr($value))";
1630 }
1631
1632 sub ceilingToPowerOf2
1633 {
1634     my ($size) = @_;
1635
1636     my $powerOf2 = 1;
1637     while ($size > $powerOf2) {
1638         $powerOf2 <<= 1;
1639     }
1640
1641     return $powerOf2;
1642 }
1643
1644 # Internal Helper
1645 sub GenerateHashTable
1646 {
1647     my $object = shift;
1648
1649     my $name = shift;
1650     my $keys = shift;
1651     my $values = shift;
1652     my $specials = shift;
1653     my $parameters = shift;
1654
1655     my @hashes = ();
1656     foreach my $key (@{$keys}) {
1657         push @hashes, $object->GenerateHashValue($key);
1658     }
1659
1660     # Collect hashtable information
1661     my $size;
1662 tableSizeLoop:
1663     for ($size = ceilingToPowerOf2(scalar @{$keys}); ; $size += $size) {
1664         my @table = ();
1665         my $i = 0;
1666         foreach my $hash (@hashes) {
1667             my $h = $hash % $size;
1668             next tableSizeLoop if defined $table[$h];
1669             $table[$h] = $i++;
1670         }
1671         last;
1672     }
1673
1674     # Start outputing the hashtables
1675     my $nameEntries = "${name}Values";
1676     $nameEntries =~ s/:/_/g;
1677
1678     if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
1679         my $type = $name;
1680         my $implClass;
1681
1682         if ($name =~ /Prototype/) {
1683             $type =~ s/Prototype.*//;
1684             $implClass = $type; $implClass =~ s/Wrapper$//;
1685             push(@implContent, "/* Hash table for prototype */\n");
1686         } else {
1687             $type =~ s/Constructor.*//;
1688             $implClass = $type; $implClass =~ s/Constructor$//;
1689             push(@implContent, "/* Hash table for constructor */\n");
1690         }
1691     } else {
1692         push(@implContent, "/* Hash table */\n");
1693     }
1694
1695     # Dump the hash table
1696     my $count = scalar @{$keys} + 1;
1697     push(@implContent, "\nstatic const HashTableValue $nameEntries\[$count\] =\n\{\n");
1698     my $i = 0;
1699     foreach my $key (@{$keys}) {
1700         push(@implContent, "    { \"$key\", (intptr_t)@$values[$i], @$specials[$i], @$parameters[$i] },\n");
1701         ++$i;
1702     }
1703     push(@implContent, "    { 0, 0, 0, 0 }\n");
1704     push(@implContent, "};\n\n");
1705     my $sizeMask = $size - 1;
1706     push(@implContent, "static const HashTable $name = { $sizeMask, $nameEntries, 0 };\n\n");
1707 }
1708
1709 # Internal helper
1710 sub GenerateHashValue
1711 {
1712     my $object = shift;
1713
1714     @chars = split(/ */, $_[0]);
1715
1716     # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1717     # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1718     # were 16-bit chunks, which should give matching results
1719
1720     my $EXP2_32 = 4294967296;
1721
1722     my $hash = 0x9e3779b9;
1723     my $l    = scalar @chars; #I wish this was in Ruby --- Maks
1724     my $rem  = $l & 1;
1725     $l = $l >> 1;
1726
1727     my $s = 0;
1728
1729     # Main loop
1730     for (; $l > 0; $l--) {
1731         $hash   += ord($chars[$s]);
1732         my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
1733         $hash   = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
1734         $s += 2;
1735         $hash += $hash >> 11;
1736         $hash %= $EXP2_32;
1737     }
1738
1739     # Handle end case
1740     if ($rem != 0) {
1741         $hash += ord($chars[$s]);
1742         $hash ^= (leftShift($hash, 11)% $EXP2_32);
1743         $hash += $hash >> 17;
1744     }
1745
1746     # Force "avalanching" of final 127 bits
1747     $hash ^= leftShift($hash, 3);
1748     $hash += ($hash >> 5);
1749     $hash = ($hash% $EXP2_32);
1750     $hash ^= (leftShift($hash, 2)% $EXP2_32);
1751     $hash += ($hash >> 15);
1752     $hash = $hash% $EXP2_32;
1753     $hash ^= (leftShift($hash, 10)% $EXP2_32);
1754
1755     # this avoids ever returning a hash code of 0, since that is used to
1756     # signal "hash not computed yet", using a value that is likely to be
1757     # effectively the same as 0 when the low bits are masked
1758     $hash = 0x80000000 if ($hash == 0);
1759
1760     return $hash;
1761 }
1762
1763 # Internal helper
1764 sub WriteData
1765 {
1766     if (defined($IMPL)) {
1767         # Write content to file.
1768         print $IMPL @implContentHeader;
1769
1770         foreach my $implInclude (sort keys(%implIncludes)) {
1771             my $checkType = $implInclude;
1772             $checkType =~ s/\.h//;
1773
1774             print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
1775         }
1776         
1777         print $IMPL "\n";
1778
1779         foreach my $implKJSInclude (sort keys(%implKJSInclude)) {
1780             print $IMPL "#include <kjs/$implKJSInclude>\n";
1781         }
1782
1783         print $IMPL @implContent;
1784         close($IMPL);
1785         undef($IMPL);
1786
1787         @implContentHeader = ();
1788         @implContent = ();
1789         %implIncludes = ();
1790         %implKJSIncludes = ();
1791     }
1792
1793     if (defined($HEADER)) {
1794         # Write content to file.
1795         print $HEADER @headerContentHeader;
1796
1797         foreach my $headerInclude (sort keys(%headerIncludes)) {
1798             print $HEADER "#include \"$headerInclude\"\n";
1799         }
1800
1801         print $HEADER @headerContent;
1802         close($HEADER);
1803         undef($HEADER);
1804
1805         @headerContentHeader = ();
1806         @headerContent = ();
1807         %headerIncludes = ();
1808     }
1809 }
1810
1811 sub constructorFor
1812 {
1813     my $className = shift;
1814     my $protoClassName = shift;
1815     my $interfaceName = shift;
1816     my $visibleClassName = shift;
1817     my $canConstruct = shift;
1818
1819 my $implContent = << "EOF";
1820 class ${className}Constructor : public DOMObject {
1821 public:
1822     ${className}Constructor(ExecState* exec)
1823         : DOMObject(${className}Constructor::createStructureID(exec->lexicalGlobalObject()->objectPrototype()))
1824     {
1825         putDirect(exec->propertyNames().prototype, ${protoClassName}::self(exec), None);
1826     }
1827     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
1828     JSValue* getValueProperty(ExecState*, int token) const;
1829     virtual const ClassInfo* classInfo() const { return &s_info; }
1830     static const ClassInfo s_info;
1831
1832     static PassRefPtr<StructureID> createStructureID(JSValue* proto) 
1833     { 
1834         return StructureID::create(proto, TypeInfo(ObjectType, ImplementsHasInstance)); 
1835     }
1836 EOF
1837
1838     if ($canConstruct) {
1839 $implContent .= << "EOF";
1840     static JSObject* construct(ExecState* exec, JSObject*, const ArgList&)
1841     {
1842         return static_cast<JSObject*>(toJS(exec, ${interfaceName}::create()));
1843     }
1844     virtual ConstructType getConstructData(ConstructData& constructData)
1845     {
1846         constructData.native.function = construct;
1847         return ConstructTypeHost;
1848     }
1849 EOF
1850     }
1851
1852 $implContent .= << "EOF";
1853 };
1854
1855 const ClassInfo ${className}Constructor::s_info = { "${visibleClassName}Constructor", 0, &${className}ConstructorTable, 0 };
1856
1857 bool ${className}Constructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1858 {
1859     return getStaticValueSlot<${className}Constructor, DOMObject>(exec, &${className}ConstructorTable, this, propertyName, slot);
1860 }
1861
1862 JSValue* ${className}Constructor::getValueProperty(ExecState* exec, int token) const
1863 {
1864     // The token is the numeric value of its associated constant
1865     return jsNumber(exec, token);
1866 }
1867
1868 EOF
1869
1870     $implKJSInclude{"JSNumberCell.h"} = 1;
1871
1872     return $implContent;
1873 }
1874
1875 1;