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