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