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