2 # Copyright (C) 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
4 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
5 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
6 # Copyright (C) 2006 Apple Computer, Inc.
8 # This file is part of the KDE project
10 # This library is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Library General Public
12 # License as published by the Free Software Foundation; either
13 # version 2 of the License, or (at your option) any later version.
15 # This library is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 # Library General Public License for more details.
20 # You should have received a copy of the GNU Library General Public License
21 # aint with this library; see the file COPYING.LIB. If not, write to
22 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 # Boston, MA 02111-1307, USA.
26 package CodeGeneratorJS;
33 my @headerContent = ();
34 my @implContentHeader = ();
36 my %implIncludes = ();
39 my $headerTemplate = << "EOF";
41 This file is part of the WebKit open source project.
42 This file has been generated by generate-bindings.pl. DO NOT MODIFY!
44 This library is free software; you can redistribute it and/or
45 modify it under the terms of the GNU Library General Public
46 License as published by the Free Software Foundation; either
47 version 2 of the License, or (at your option) any later version.
49 This library is distributed in the hope that it will be useful,
50 but WITHOUT ANY WARRANTY; without even the implied warranty of
51 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
52 Library General Public License for more details.
54 You should have received a copy of the GNU Library General Public License
55 along with this library; see the file COPYING.LIB. If not, write to
56 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
57 Boston, MA 02111-1307, USA.
67 $codeGenerator = shift;
70 bless($reference, $object);
83 my ($value, $distance) = @_;
84 return (($value << $distance) & 0xFFFFFFFF);
87 # Uppercase the first letter, while respecting WebKit style guidelines.
88 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
92 my $ret = ucfirst($param);
93 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
97 # Params: 'domClass' struct
101 my $dataNode = shift;
104 # Start actual generation
105 $object->GenerateHeader($dataNode);
106 $object->GenerateImplementation($dataNode);
108 my $name = $dataNode->name;
110 # Open files for writing
111 my $headerFileName = "$outputDir/JS$name.h";
112 my $implFileName = "$outputDir/JS$name.cpp";
114 open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
115 open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
118 # Params: 'idlDocument' struct
122 my $dataNode = shift;
124 $module = $dataNode->module;
127 sub GetParentClassName
129 my $dataNode = shift;
131 return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
132 return "KJS::DOMObject" if @{$dataNode->parents} eq 0;
133 return "JS" . $codeGenerator->StripModule($dataNode->parents(0));
136 sub GetLegacyHeaderIncludes
138 my $legacyParent = shift;
140 return "#include \"JSHTMLInputElementBase.h\"\n\n" if $legacyParent eq "JSHTMLInputElementBase";
141 return "#include \"kjs_window.h\"\n\n" if $legacyParent eq "KJS::Window";
142 return "#include \"kjs_domnode.h\"\n\n" if $legacyParent eq "KJS::DOMNode";
143 return "#include \"kjs_events.h\"\n\n" if $module eq "events";
144 return "#include \"kjs_dom.h\"\n\n" if $module eq "core";
145 return "#include \"kjs_css.h\"\n\n" if $module eq "css";
146 return "#include \"kjs_html.h\"\n\n" if $module eq "html";
147 return "#include \"kjs_traversal.h\"\n\n" if $module eq "traversal";
149 die "Don't know what headers to include for module $module";
152 sub AvoidInclusionOfType
156 # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist.
157 return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix";
161 sub UsesManualToJSImplementation
165 return 1 if $type eq "SVGPathSeg";
169 sub CreateSVGContextInterfaceName
173 return $type if $codeGenerator->IsSVGAnimatedType($type);
174 return "SVGPathSeg" if $type =~ /^SVGPathSeg/ and $type ne "SVGPathSegList";
179 sub AddIncludesForType
181 my $type = $codeGenerator->StripModule(shift);
183 # When we're finished with the one-file-per-class
184 # reorganization, we won't need these special cases.
185 if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type)
186 or $type eq "DOMString" or $type eq "DOMObject" or $type eq "RGBColor" or $type eq "Rect") {
187 } elsif ($type =~ /SVGPathSeg/) {
189 $joinedName =~ s/Abs|Rel//;
190 $implIncludes{"${joinedName}.h"} = 1;
191 } elsif ($type eq "XPathNSResolver") {
192 $implIncludes{"JSXPathNSResolver.h"} = 1;
193 $implIncludes{"JSCustomXPathNSResolver.h"} = 1;
195 # default, include the same named file
196 $implIncludes{"${type}.h"} = 1;
199 # additional includes (things needed to compile the bindings but not the header)
201 if ($type eq "CanvasRenderingContext2D") {
202 $implIncludes{"CanvasGradient.h"} = 1;
203 $implIncludes{"CanvasPattern.h"} = 1;
204 $implIncludes{"CanvasStyle.h"} = 1;
207 if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
208 $implIncludes{"PlatformString.h"} = 1;
212 sub AddIncludesForSVGAnimatedType
215 $type =~ s/SVGAnimated//;
217 if ($type eq "Point" or $type eq "Rect") {
218 $implIncludes{"Float$type.h"} = 1;
219 } elsif ($type eq "String") {
220 $implIncludes{"PlatformString.h"} = 1;
224 sub AddClassForwardIfNeeded
226 my $implClassName = shift;
228 # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them!
229 push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName);
232 sub HashValueForClassAndName
237 # SVG Filter enums live in WebCore namespace (platform/graphics/)
238 if ($class =~ /^SVGFE*/ or $class =~ /^SVGComponentTransferFunctionElement$/) {
239 return "WebCore::$name";
242 return "${class}::$name";
248 my $dataNode = shift;
250 my $interfaceName = $dataNode->name;
251 my $className = "JS$interfaceName";
252 my $implClassName = $interfaceName;
254 # We only support multiple parents with SVG (for now).
255 if (@{$dataNode->parents} > 1) {
256 die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
257 $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode);
260 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
261 my $hasRealParent = @{$dataNode->parents} > 0;
262 my $hasParent = $hasLegacyParent || $hasRealParent;
263 my $parentClassName = GetParentClassName($dataNode);
264 my $conditional = $dataNode->extendedAttributes->{"Conditional"};
266 # - Add default header template
267 @headerContent = split("\r", $headerTemplate);
269 # - Add header protection
270 push(@headerContent, "\n#ifndef $className" . "_H");
271 push(@headerContent, "\n#define $className" . "_H\n\n");
273 my $conditionalString;
275 $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
276 push(@headerContent, "\n#if ${conditionalString}\n\n");
279 if (exists $dataNode->extendedAttributes->{"LegacyParent"}) {
280 push(@headerContent, GetLegacyHeaderIncludes($dataNode->extendedAttributes->{"LegacyParent"}));
283 push(@headerContent, "#include \"$parentClassName.h\"\n");
285 push(@headerContent, "#include \"kjs_binding.h\"\n");
289 # Get correct pass/store types respecting PODType flag
290 my $podType = $dataNode->extendedAttributes->{"PODType"};
291 my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*";
293 push(@headerContent, "#include \"$podType.h\"\n") if $podType and $podType ne "double";
294 push(@headerContent, "#include \"JSSVGPODTypeWrapper.h\"\n") if $podType;
296 my $numConstants = @{$dataNode->constants};
297 my $numAttributes = @{$dataNode->attributes};
298 my $numFunctions = @{$dataNode->functions};
300 push(@headerContent, "\nnamespace WebCore {\n\n");
302 # Implementation class forward declaration
303 AddClassForwardIfNeeded($implClassName) unless $podType;
306 push(@headerContent, "class $className : public $parentClassName {\n");
307 push(@headerContent, "public:\n");
310 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
311 push(@headerContent, " $className($passType);\n");
313 push(@headerContent, " $className(KJS::ExecState*, $passType);\n");
317 if (!$hasParent or $interfaceName eq "Document") {
318 push(@headerContent, " virtual ~$className();\n");
322 if ($numAttributes > 0) {
323 push(@headerContent, " virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
324 push(@headerContent, " KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
327 # Check if we have any writable properties
328 my $hasReadWriteProperties = 0;
329 foreach (@{$dataNode->attributes}) {
330 if ($_->type !~ /^readonly\ attribute$/) {
331 $hasReadWriteProperties = 1;
335 if ($hasReadWriteProperties) {
336 push(@headerContent, " virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n");
337 push(@headerContent, " void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n");
341 push(@headerContent, " virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
342 push(@headerContent, " static const KJS::ClassInfo info;\n");
344 # Custom mark function
345 if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
346 push(@headerContent, "\n virtual void mark();\n\n");
349 # Constructor object getter
350 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
351 push(@headerContent, " static KJS::JSValue* getConstructor(KJS::ExecState*);\n")
354 my $numCustomFunctions = 0;
355 my $numCustomAttributes = 0;
357 # Attribute and function enums
358 if ($numAttributes + $numFunctions > 0) {
359 push(@headerContent, " enum {\n")
362 if ($numAttributes > 0) {
363 push(@headerContent, " // Attributes\n ");
366 foreach (@{$dataNode->attributes}) {
369 $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"};
372 if ((($i % 4) eq 0) and ($i ne 0)) {
373 push(@headerContent, "\n ");
376 my $value = $attribute->signature->type =~ /Constructor$/
377 ? $attribute->signature->name . "ConstructorAttrNum"
378 : WK_ucfirst($attribute->signature->name) . "AttrNum";
379 $value .= ", " if (($i < $numAttributes - 1));
380 $value .= ", " if (($i eq $numAttributes - 1) and ($numFunctions ne 0));
381 push(@headerContent, $value);
385 if ($numFunctions > 0) {
386 push(@headerContent, "\n\n") if $numAttributes > 0;
387 push(@headerContent," // Functions\n ");
390 foreach my $function (@{$dataNode->functions}) {
393 push(@headerContent, "\n ") if ((($i % 4) eq 0) and ($i ne 0));
395 $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"};
397 my $value = WK_ucfirst($function->signature->name) . "FuncNum";
398 $value .= ", " if ($i < $numFunctions - 1);
399 push(@headerContent, $value);
403 push(@headerContent, "\n };\n") if ($numAttributes + $numFunctions > 0);
405 if ($numCustomAttributes > 0) {
406 push(@headerContent, "\n // Custom attributes\n");
408 foreach my $attribute (@{$dataNode->attributes}) {
409 if ($attribute->signature->extendedAttributes->{"Custom"}) {
410 push(@headerContent, " KJS::JSValue* " . $attribute->signature->name . "(KJS::ExecState*) const;\n");
411 if ($attribute->type !~ /^readonly/) {
412 push(@headerContent, " void set" . WK_ucfirst($attribute->signature->name) . "(KJS::ExecState*, KJS::JSValue*);\n");
418 if ($numCustomFunctions > 0) {
419 push(@headerContent, "\n // Custom functions\n");
420 foreach my $function (@{$dataNode->functions}) {
421 if ($function->signature->extendedAttributes->{"Custom"}) {
422 push(@headerContent, " KJS::JSValue* " . $function->signature->name . "(KJS::ExecState*, const KJS::List&);\n");
428 if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
429 push(@headerContent, " void indexSetter(KJS::ExecState*, unsigned index, KJS::JSValue*, int attr);\n");
434 push(@headerContent, " JSSVGPODTypeWrapper<$podType>* impl() const { return m_impl.get(); }\n");
435 push(@headerContent, "private:\n");
436 push(@headerContent, " RefPtr<JSSVGPODTypeWrapper<$podType> > m_impl;\n");
438 push(@headerContent, " $implClassName* impl() const { return m_impl.get(); }\n");
439 push(@headerContent, "private:\n");
440 push(@headerContent, " RefPtr<$implClassName> m_impl;\n");
442 } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
443 push(@headerContent, " $implClassName* impl() const;\n");
447 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
448 push(@headerContent, "private:\n");
449 push(@headerContent, " static KJS::JSValue* indexGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
452 if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
453 push(@headerContent, "private:\n");
454 push(@headerContent, " static KJS::JSValue* nameGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
455 push(@headerContent, " static bool canGetItemsForName(KJS::ExecState*, $implClassName*, const AtomicString&);\n")
458 push(@headerContent, "};\n\n");
462 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, JSSVGPODTypeWrapper<$podType>*);\n");
464 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, $passType);\n");
467 if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
469 push(@headerContent, "$podType to${interfaceName}(KJS::JSValue*);\n");
471 push(@headerContent, "$implClassName* to${interfaceName}(KJS::JSValue*);\n");
474 push(@headerContent, "\n");
476 # Add prototype declaration -- code adopted from the KJS_DEFINE_PROTOTYPE and KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE macros
477 push(@headerContent, "class ${className}Prototype : public KJS::JSObject {\n");
478 push(@headerContent, "public:\n");
479 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
480 push(@headerContent, " static KJS::JSObject* self();\n");
482 push(@headerContent, " static KJS::JSObject* self(KJS::ExecState* exec);\n");
484 push(@headerContent, " virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
485 push(@headerContent, " static const KJS::ClassInfo info;\n");
486 if ($numFunctions > 0 || $numConstants > 0) {
487 push(@headerContent, " bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
489 if ($numConstants ne 0) {
490 push(@headerContent, " KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
492 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
493 push(@headerContent, " ${className}Prototype() { }\n");
495 push(@headerContent, " ${className}Prototype(KJS::ExecState* exec)\n");
496 if ($hasParent && $parentClassName ne "KJS::DOMCSSRule" && $parentClassName ne "KJS::DOMNodeFilter") {
497 push(@headerContent, " : KJS::JSObject(${parentClassName}Prototype::self(exec)) { }\n");
499 push(@headerContent, " : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { }\n");
503 push(@headerContent, "};\n\n");
504 push(@headerContent, "}\n\n");
505 push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditional;
506 push(@headerContent, "#endif\n");
509 sub GenerateImplementation
512 my $dataNode = shift;
514 my $interfaceName = $dataNode->name;
515 my $className = "JS$interfaceName";
516 my $implClassName = $interfaceName;
518 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
519 my $hasRealParent = @{$dataNode->parents} > 0;
520 my $hasParent = $hasLegacyParent || $hasRealParent;
521 my $parentClassName = GetParentClassName($dataNode);
522 my $conditional = $dataNode->extendedAttributes->{"Conditional"};
524 # - Add default header template
525 @implContentHeader = split("\r", $headerTemplate);
526 push(@implContentHeader, "\n#include \"config.h\"\n\n");
527 my $conditionalString;
529 $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
530 push(@implContentHeader, "\n#if ${conditionalString}\n\n");
533 if ($className =~ /^JSSVG/) {
534 push(@implContentHeader, "#include \"Document.h\"\n");
535 push(@implContentHeader, "#include \"Frame.h\"\n");
536 push(@implContentHeader, "#include \"SVGDocumentExtensions.h\"\n");
537 push(@implContentHeader, "#include \"SVGElement.h\"\n");
538 push(@implContentHeader, "#include \"SVGAnimatedTemplate.h\"\n");
540 if ($className =~ /^JSSVGAnimated/) {
541 AddIncludesForSVGAnimatedType($interfaceName);
545 push(@implContentHeader, "#include \"$className.h\"\n\n");
546 push(@implContentHeader, "#include <wtf/GetPtr.h>\n\n");
548 AddIncludesForType($interfaceName);
552 push(@implContent, "\nusing namespace KJS;\n\n");
553 push(@implContent, "namespace WebCore {\n\n");
555 # - Add all attributes in a hashtable definition
556 my $numAttributes = @{$dataNode->attributes};
557 if ($numAttributes > 0) {
558 my $hashSize = $numAttributes;
559 my $hashName = $className . "Table";
561 my @hashKeys = (); # ie. 'insertBefore'
562 my @hashValues = (); # ie. 'JSNode::InsertBefore'
563 my @hashSpecials = (); # ie. 'DontDelete|Function'
564 my @hashParameters = (); # ie. '2'
566 foreach my $attribute (@{$dataNode->attributes}) {
567 my $name = $attribute->signature->name;
568 push(@hashKeys, $name);
570 my $value = $className . "::" . ($attribute->signature->type =~ /Constructor$/
571 ? $attribute->signature->name . "ConstructorAttrNum"
572 : WK_ucfirst($attribute->signature->name) . "AttrNum");
573 push(@hashValues, $value);
575 my $special = "DontDelete";
576 $special .= "|ReadOnly" if ($attribute->type =~ /readonly/);
577 push(@hashSpecials, $special);
579 my $numParameters = "0";
580 push(@hashParameters, $numParameters);
583 $object->GenerateHashTable($hashName, $hashSize,
584 \@hashKeys, \@hashValues,
585 \@hashSpecials, \@hashParameters);
588 my $numConstants = @{$dataNode->constants};
589 my $numFunctions = @{$dataNode->functions};
591 # - Add all constants
592 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
593 $hashSize = $numConstants;
594 $hashName = $className . "ConstructorTable";
599 @hashParameters = ();
601 foreach my $constant (@{$dataNode->constants}) {
602 my $name = $constant->name;
603 push(@hashKeys, $name);
605 my $value = HashValueForClassAndName($implClassName, $name);
606 push(@hashValues, $value);
608 my $special = "DontDelete|ReadOnly";
609 push(@hashSpecials, $special);
611 my $numParameters = 0;
612 push(@hashParameters, $numParameters);
615 $object->GenerateHashTable($hashName, $hashSize,
616 \@hashKeys, \@hashValues,
617 \@hashSpecials, \@hashParameters);
620 $protoClassName = "${className}Prototype";
622 push(@implContent, constructorFor($className, $protoClassName, $interfaceName, $dataNode->extendedAttributes->{"CanBeConstructed"}));
625 # - Add functions and constants to a hashtable definition
626 $hashSize = $numFunctions + $numConstants;
627 $hashName = $className . "PrototypeTable";
632 @hashParameters = ();
634 foreach my $constant (@{$dataNode->constants}) {
635 my $name = $constant->name;
636 push(@hashKeys, $name);
638 my $value = HashValueForClassAndName($implClassName, $name);
639 push(@hashValues, $value);
641 my $special = "DontDelete|ReadOnly";
642 push(@hashSpecials, $special);
644 my $numParameters = 0;
645 push(@hashParameters, $numParameters);
648 foreach my $function (@{$dataNode->functions}) {
649 my $name = $function->signature->name;
650 push(@hashKeys, $name);
652 my $value = $className . "::" . WK_ucfirst($name) . "FuncNum";
653 push(@hashValues, $value);
655 my $special = "DontDelete|Function";
656 push(@hashSpecials, $special);
658 my $numParameters = @{$function->parameters};
659 push(@hashParameters, $numParameters);
662 $object->GenerateHashTable($hashName, $hashSize,
663 \@hashKeys, \@hashValues,
664 \@hashSpecials, \@hashParameters);
666 if ($numFunctions > 0) {
667 push(@implContent, prototypeFunctionFor($className));
670 push(@implContent, "const ClassInfo ${className}Prototype::info = { \"${interfaceName}Prototype\", 0, &${className}PrototypeTable, 0 };\n\n");
671 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
672 push(@implContent, "JSObject* ${className}Prototype::self()\n");
673 push(@implContent, "{\n");
674 push(@implContent, " return new ${className}Prototype();\n");
675 push(@implContent, "}\n\n");
677 push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec)\n");
678 push(@implContent, "{\n");
679 push(@implContent, " return KJS::cacheGlobalObject<${className}Prototype>(exec, \"[[${className}.prototype]]\");\n");
680 push(@implContent, "}\n\n");
682 if ($numConstants > 0 || $numFunctions > 0) {
683 push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
684 push(@implContent, "{\n");
685 if ($numConstants eq 0) {
686 push(@implContent, " return getStaticFunctionSlot<${className}PrototypeFunction, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
687 } elsif ($numFunctions eq 0) {
688 push(@implContent, " return getStaticValueSlot<${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
690 push(@implContent, " return getStaticPropertySlot<${className}PrototypeFunction, ${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
692 push(@implContent, "}\n\n");
694 if ($numConstants ne 0) {
695 push(@implContent, "JSValue* ${className}Prototype::getValueProperty(ExecState*, int token) const\n{\n");
696 push(@implContent, " // The token is the numeric value of its associated constant\n");
697 push(@implContent, " return jsNumber(token);\n}\n\n");
700 # - Initialize static ClassInfo object
701 push(@implContent, "const ClassInfo $className" . "::info = { \"$interfaceName\", ");
703 push(@implContent, "&" .$parentClassName . "::info, ");
705 push(@implContent, "0, ");
708 if ($numAttributes > 0) {
709 push(@implContent, "&${className}Table, ");
711 push(@implContent, "0, ")
713 push(@implContent, "0 };\n\n");
715 # Get correct pass/store types respecting PODType flag
716 my $podType = $dataNode->extendedAttributes->{"PODType"};
717 my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*";
720 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
721 push(@implContent, "${className}::$className($passType impl)\n");
722 push(@implContent, " : $parentClassName(impl)\n");
724 push(@implContent, "${className}::$className(ExecState* exec, $passType impl)\n");
726 push(@implContent, " : $parentClassName(exec, impl)\n");
728 push(@implContent, " : m_impl(impl)\n");
732 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
733 push(@implContent, "{\n setPrototype(${className}Prototype::self());\n}\n\n");
735 push(@implContent, "{\n setPrototype(${className}Prototype::self(exec));\n}\n\n");
740 push(@implContent, "${className}::~$className()\n");
742 my $contextInterfaceName = CreateSVGContextInterfaceName($interfaceName);
743 if ($contextInterfaceName ne "") {
744 push(@implContent, "{\n SVGDocumentExtensions::forgetGenericContext<$contextInterfaceName>(m_impl.get());\n");
745 push(@implContent, " ScriptInterpreter::forgetDOMObject(m_impl.get());\n}\n\n");
747 push(@implContent, "{\n ScriptInterpreter::forgetDOMObject(m_impl.get());\n}\n\n");
751 # Document needs a special destructor because it's a special case for caching. It needs
752 # its own special handling rather than relying on the caching that Node normally does.
753 if ($interfaceName eq "Document") {
754 push(@implContent, "${className}::~$className()\n");
755 push(@implContent, "{\n ScriptInterpreter::forgetDOMObject(static_cast<${implClassName}*>(m_impl.get()));\n}\n\n");
759 if ($numAttributes ne 0) {
760 push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
761 push(@implContent, "{\n");
762 # FIXME: We need to provide scalable hooks/attributes for this kind of extension
763 if ($interfaceName eq "DOMWindow") {
764 push(@implContent, " if (getOverridePropertySlot(exec, propertyName, slot))\n");
765 push(@implContent, " return true;\n");
768 my $hasNameGetterGeneration = sub {
769 push(@implContent, " if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
770 push(@implContent, " slot.setCustom(this, nameGetter);\n");
771 push(@implContent, " return true;\n");
772 push(@implContent, " }\n");
775 if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
776 &$hasNameGetterGeneration();
779 my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
780 if ($requiresManualLookup) {
781 push(@implContent, " const HashEntry* entry = Lookup::findEntry(&${className}Table, propertyName);\n");
782 push(@implContent, " if (entry) {\n");
783 push(@implContent, " slot.setStaticEntry(this, entry, staticValueGetter<$className>);\n");
784 push(@implContent, " return true;\n");
785 push(@implContent, " }\n");
788 if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
789 # if it has a prototype, we need to check that first too
790 push(@implContent, " if (prototype()->isObject() && static_cast<JSObject*>(prototype())->hasProperty(exec, propertyName))\n");
791 push(@implContent, " return false;\n");
794 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
795 push(@implContent, " bool ok;\n");
796 push(@implContent, " unsigned u = propertyName.toUInt32(&ok);\n");
797 push(@implContent, " if (ok && u < static_cast<$implClassName*>(impl())->length()) {\n");
798 push(@implContent, " slot.setCustomIndex(this, u, indexGetter);\n");
799 push(@implContent, " return true;\n");
800 push(@implContent, " }\n");
803 if ($dataNode->extendedAttributes->{"HasNameGetter"}) {
804 &$hasNameGetterGeneration();
807 if ($requiresManualLookup) {
808 push(@implContent, " return ${parentClassName}::getOwnPropertySlot(exec, propertyName, slot);\n");
810 push(@implContent, " return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
812 push(@implContent, "}\n\n");
814 push(@implContent, "JSValue* ${className}::getValueProperty(ExecState* exec, int token) const\n{\n");
817 push(@implContent, " $podType& imp(*impl());\n\n");
819 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
822 push(@implContent, " switch (token) {\n");
824 foreach my $attribute (@{$dataNode->attributes}) {
825 my $name = $attribute->signature->name;
827 my $implClassNameForValueConversion = "";
828 if (!$podType and ($codeGenerator->IsSVGAnimatedType($implClassName) or $attribute->type !~ /^readonly/)) {
829 $implClassNameForValueConversion = $implClassName;
832 if ($attribute->signature->extendedAttributes->{"Custom"}) {
833 push(@implContent, " case " . WK_ucfirst($name) . "AttrNum:\n");
834 push(@implContent, " return $name(exec);\n");
835 } elsif ($attribute->signature->type =~ /Constructor$/) {
836 my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
837 $constructorType =~ s/Constructor$//;
839 push(@implContent, " case " . $name . "ConstructorAttrNum:\n");
840 push(@implContent, " return JS" . $constructorType . "::getConstructor(exec);\n");
841 } elsif (!@{$attribute->getterExceptions}) {
842 push(@implContent, " case " . WK_ucfirst($name) . "AttrNum:\n");
845 if ($podType eq "double") { # Special case for JSSVGNumber
846 push(@implContent, " return " . NativeToJSValue($attribute->signature, "", "imp") . ";\n");
848 push(@implContent, " return " . NativeToJSValue($attribute->signature, "", "imp.$name()") . ";\n");
851 my $type = $codeGenerator->StripModule($attribute->signature->type);
852 my $jsType = NativeToJSValue($attribute->signature, $implClassNameForValueConversion, "imp->$name()");
854 if ($codeGenerator->IsSVGAnimatedType($type)) {
855 push(@implContent, " {\n");
856 push(@implContent, " ASSERT(exec && exec->dynamicInterpreter());\n\n");
857 push(@implContent, " RefPtr<$type> obj = $jsType;\n");
858 push(@implContent, " Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();\n");
859 push(@implContent, " if (activeFrame) {\n");
860 push(@implContent, " SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);\n");
861 push(@implContent, " if (extensions) {\n");
862 push(@implContent, " if (extensions->hasGenericContext<$type>(obj.get()))\n");
863 push(@implContent, " ASSERT(extensions->genericContext<$type>(obj.get()) == imp);\n");
864 push(@implContent, " else\n");
865 push(@implContent, " extensions->setGenericContext<$type>(obj.get(), imp);\n");
866 push(@implContent, " }\n");
867 push(@implContent, " }\n\n");
868 push(@implContent, " return toJS(exec, obj.get());\n");
869 push(@implContent, " }\n");
871 push(@implContent, " return $jsType;\n");
875 push(@implContent, " case " . WK_ucfirst($name) . "AttrNum: {\n");
876 push(@implContent, " ExceptionCode ec = 0;\n");
879 push(@implContent, " KJS::JSValue* result = " . NativeToJSValue($attribute->signature, "", "imp.$name(ec)") . ";\n");
881 push(@implContent, " KJS::JSValue* result = " . NativeToJSValue($attribute->signature, $implClassNameForValueConversion, "imp->$name(ec)") . ";\n");
884 push(@implContent, " setDOMException(exec, ec);\n");
885 push(@implContent, " return result;\n");
886 push(@implContent, " }\n");
889 push(@implContent, " }\n return 0;\n}\n\n");
891 # Check if we have any writable attributes
892 my $hasReadWriteProperties = 0;
893 foreach my $attribute (@{$dataNode->attributes}) {
894 $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
896 if ($hasReadWriteProperties) {
897 push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
898 push(@implContent, "{\n");
899 if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
900 push(@implContent, " bool ok;\n");
901 push(@implContent, " unsigned index = propertyName.toUInt32(&ok);\n");
902 push(@implContent, " if (ok) {\n");
903 push(@implContent, " indexSetter(exec, index, value, attr);\n");
904 push(@implContent, " return;\n");
905 push(@implContent, " }\n");
907 push(@implContent, " lookupPut<$className, $parentClassName>(exec, propertyName, value, attr, &${className}Table, this);\n");
908 push(@implContent, "}\n\n");
910 push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
911 push(@implContent, "{\n");
914 push(@implContent, " $podType& imp(*impl());\n\n");
916 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
919 push(@implContent, " switch (token) {\n");
921 foreach my $attribute (@{$dataNode->attributes}) {
922 if ($attribute->type !~ /^readonly/) {
923 my $name = $attribute->signature->name;
925 if ($attribute->signature->extendedAttributes->{"Custom"}) {
926 push(@implContent, " case " . WK_ucfirst($name) . "AttrNum: {\n");
927 push(@implContent, " set" . WK_ucfirst($name) . "(exec, value);\n");
928 } elsif ($attribute->signature->type =~ /Constructor$/) {
929 my $constructorType = $attribute->signature->type;
930 $constructorType =~ s/Constructor$//;
932 $implIncludes{"JS" . $constructorType . ".h"} = 1;
933 push(@implContent, " case " . $name ."ConstructorAttrNum: {\n");
934 push(@implContent, " // Shadowing a built-in constructor\n");
936 # FIXME: We need to provide scalable hooks/attributes for this kind of extension
937 push(@implContent, " if (isSafeScript(exec))\n");
938 push(@implContent, " JSObject::put(exec, \"$name\", value);\n");
940 push(@implContent, " case " . WK_ucfirst($name) ."AttrNum: {\n");
942 if ($podType eq "double") { # Special case for JSSVGNumber
943 push(@implContent, " imp = " . JSValueToNative($attribute->signature, "value") . ";\n");
945 push(@implContent, " imp.set" . WK_ucfirst($name) . "(" . JSValueToNative($attribute->signature, "value") . ");\n");
947 push(@implContent, " m_impl->commitChange(exec);\n");
949 push(@implContent, " ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
950 push(@implContent, " imp->set" . WK_ucfirst($name) . "(" . JSValueToNative($attribute->signature, "value"));
951 push(@implContent, ", ec") if @{$attribute->setterExceptions};
952 push(@implContent, ");\n");
953 push(@implContent, " setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
956 push(@implContent, " break;\n");
957 push(@implContent, " }\n");
960 push(@implContent, " }\n"); # end switch
962 my $contextInterfaceName = CreateSVGContextInterfaceName($interfaceName);
963 if ($interfaceName eq "DOMWindow") {
964 push(@implContent, " // FIXME: Hack to prevent unused variable warning -- remove once DOMWindow includes a settable property\n");
965 push(@implContent, " (void)imp;\n");
966 } elsif ($contextInterfaceName ne "") {
967 push(@implContent, " ASSERT(exec && exec->dynamicInterpreter());\n");
968 push(@implContent, " Frame* activeFrame = static_cast<ScriptInterpreter*>(exec->dynamicInterpreter())->frame();\n");
969 push(@implContent, " if (!activeFrame)\n return;\n\n");
970 push(@implContent, " SVGDocumentExtensions* extensions = (activeFrame->document() ? activeFrame->document()->accessSVGExtensions() : 0);\n");
971 push(@implContent, " if (extensions && extensions->hasGenericContext<$contextInterfaceName>(imp)) {\n");
972 push(@implContent, " const SVGElement* context = extensions->genericContext<$contextInterfaceName>(imp);\n");
973 push(@implContent, " ASSERT(context);\n\n");
974 push(@implContent, " context->notifyAttributeChange();\n");
975 push(@implContent, " }\n\n");
978 push(@implContent, "}\n\n"); # end function
982 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
983 push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
984 push(@implContent, " return KJS::cacheGlobalObject<${className}Constructor>(exec, \"[[${interfaceName}.constructor]]\");\n");
985 push(@implContent, "}\n");
989 if ($numFunctions ne 0) {
990 push(@implContent, "JSValue* ${className}PrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)\n{\n");
991 push(@implContent, " if (!thisObj->inherits(&${className}::info))\n");
992 push(@implContent, " return throwError(exec, TypeError);\n\n");
995 push(@implContent, " JSSVGPODTypeWrapper<$podType>* wrapper = static_cast<$className*>(thisObj)->impl();\n");
996 push(@implContent, " $podType& imp(*wrapper);\n\n");
998 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(thisObj)->impl());\n\n");
1001 push(@implContent, " switch (id) {\n");
1003 my $hasCustomFunctionsOnly = 1;
1005 foreach my $function (@{$dataNode->functions}) {
1006 push(@implContent, " case ${className}::" . WK_ucfirst($function->signature->name) . "FuncNum: {\n");
1008 if ($function->signature->extendedAttributes->{"Custom"}) {
1009 push(@implContent, " return static_cast<${className}*>(thisObj)->" . $function->signature->name . "(exec, args);\n }\n");
1013 $hasCustomFunctionsOnly = 0;
1014 AddIncludesForType($function->signature->type);
1016 if (@{$function->raisesExceptions}) {
1017 push(@implContent, " ExceptionCode ec = 0;\n");
1021 my $functionString = "imp" . ($podType ? "." : "->") . $function->signature->name . "(";
1023 my $numParameters = @{$function->parameters};
1024 my $hasOptionalArguments = 0;
1026 foreach my $parameter (@{$function->parameters}) {
1027 if (!$hasOptionalArguments && $parameter->extendedAttributes->{"Optional"}) {
1028 push(@implContent, "\n int argsCount = args.size();\n");
1029 $hasOptionalArguments = 1;
1032 if ($hasOptionalArguments) {
1033 push(@implContent, " if (argsCount < " . ($paramIndex + 1) . ") {\n");
1034 GenerateImplementationFunctionCall($function, $functionString, $paramIndex, " " x 3, $podType);
1035 push(@implContent, " }\n\n");
1038 my $name = $parameter->name;
1040 if ($parameter->type eq "XPathNSResolver") {
1041 push(@implContent, " RefPtr<XPathNSResolver> customResolver;\n");
1042 push(@implContent, " XPathNSResolver* resolver = toXPathNSResolver(args[$paramIndex]);\n");
1043 push(@implContent, " if (!resolver) {\n");
1044 push(@implContent, " customResolver = JSCustomXPathNSResolver::create(exec, args[$paramIndex]);\n");
1045 push(@implContent, " if (exec->hadException())\n");
1046 push(@implContent, " return jsUndefined();\n");
1047 push(@implContent, " resolver = customResolver.get();\n");
1048 push(@implContent, " }\n");
1050 push(@implContent, " bool ${name}Ok;\n") if TypeCanFailConversion($parameter);
1051 push(@implContent, " " . GetNativeTypeFromSignature($parameter) . " $name = " . JSValueToNative($parameter, "args[$paramIndex]", TypeCanFailConversion($parameter) ? "${name}Ok" : undef) . ";\n");
1052 if (TypeCanFailConversion($parameter)) {
1053 push(@implContent, " if (!${name}Ok) {\n");
1054 push(@implContent, " setDOMException(exec, TYPE_MISMATCH_ERR);\n");
1055 push(@implContent, " return jsUndefined();\n }\n");
1058 # If a parameter is "an index", it should throw an INDEX_SIZE_ERR
1060 if ($parameter->extendedAttributes->{"IsIndex"}) {
1061 $implIncludes{"ExceptionCode.h"} = 1;
1062 push(@implContent, " if ($name < 0) {\n");
1063 push(@implContent, " setDOMException(exec, INDEX_SIZE_ERR);\n");
1064 push(@implContent, " return jsUndefined();\n }\n");
1068 $functionString .= ", " if $paramIndex;
1069 $functionString .= $name;
1074 push(@implContent, "\n");
1075 GenerateImplementationFunctionCall($function, $functionString, $paramIndex, " " x 2, $podType);
1077 push(@implContent, " }\n"); # end case
1079 push(@implContent, " }\n"); # end switch
1080 push(@implContent, " (void)imp;\n") if $hasCustomFunctionsOnly;
1081 push(@implContent, " return 0;\n");
1082 push(@implContent, "}\n");
1085 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
1086 push(@implContent, "\nJSValue* ${className}::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot)\n");
1087 push(@implContent, "{\n");
1088 push(@implContent, " ${className}* thisObj = static_cast<$className*>(slot.slotBase());\n");
1089 push(@implContent, " return toJS(exec, static_cast<$implClassName*>(thisObj->impl())->item(slot.index()));\n");
1090 push(@implContent, "}\n");
1093 if (!$hasParent and !UsesManualToJSImplementation($implClassName)) {
1095 push(@implContent, "KJS::JSValue* toJS(KJS::ExecState* exec, JSSVGPODTypeWrapper<$podType>* obj)\n");
1097 push(@implContent, "KJS::JSValue* toJS(KJS::ExecState* exec, $passType obj)\n");
1100 push(@implContent, "{\n");
1102 # This cache facility is not really working for POD types, we'd need to pass around pointers instead of POD
1103 # types to be able to reuse the JSSVGFooBar classes. What's happening right now, is that we just create a new
1104 # JSSVGPODTypeWrapper, once toJS is called. A follow up call, doing the same, would also create a new JSSVGPODTypeWrapper.
1105 # So if we'd use pointers for POD types like SVGPoint, SVGRect, we could easily reuse the JSSVGPoint/JSSVGRect classes.
1106 # Though we do NOT want to pass primitive pointer around in SVG, that's why we have to create these "smart wrappers"
1107 # around POD types in the bindings. This approach is still way better than using pointers all over SVG codebase.
1108 push(@implContent, " return KJS::cacheDOMObject<JSSVGPODTypeWrapper<$podType>, $className>(exec, obj);\n");
1110 push(@implContent, " return KJS::cacheDOMObject<$implClassName, $className>(exec, obj);\n");
1112 push(@implContent, "}\n");
1115 if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
1117 push(@implContent, "$podType to${interfaceName}(KJS::JSValue* val)\n");
1119 push(@implContent, "$implClassName* to${interfaceName}(KJS::JSValue* val)\n");
1122 push(@implContent, "{\n");
1124 push(@implContent, " return val->isObject(&${className}::info) ? " . ($podType ? "($podType) *" : "") . "static_cast<$className*>(val)->impl() : ");
1125 if ($podType and $podType ne "double") {
1126 push(@implContent, "$podType();\n}\n");
1128 push(@implContent, "0;\n}\n");
1132 if ($dataNode->extendedAttributes->{"GenerateNativeConverter"} && $hasParent) {
1133 push(@implContent, "\n$implClassName* ${className}::impl() const\n");
1134 push(@implContent, "{\n");
1135 push(@implContent, " return static_cast<$implClassName*>(${parentClassName}::impl());\n");
1136 push(@implContent, "}\n");
1139 push(@implContent, "\n}\n");
1141 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditional;
1144 sub GenerateImplementationFunctionCall()
1146 my $function = shift;
1147 my $functionString = shift;
1148 my $paramIndex = shift;
1150 my $podType = shift;
1152 if (@{$function->raisesExceptions}) {
1153 $functionString .= ", " if $paramIndex;
1154 $functionString .= "ec";
1156 $functionString .= ")";
1158 if ($function->signature->type eq "void") {
1159 push(@implContent, $indent . "$functionString;\n");
1160 push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
1161 push(@implContent, $indent . "wrapper->commitChange(exec);\n") if $podType;
1162 push(@implContent, $indent . "return jsUndefined();\n");
1164 push(@implContent, "\n" . $indent . "KJS::JSValue* result = " . NativeToJSValue($function->signature, "", $functionString) . ";\n");
1165 push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
1166 push(@implContent, $indent . "wrapper->commitChange(exec);\n") if $podType;
1167 push(@implContent, $indent . "return result;\n");
1171 sub GetNativeTypeFromSignature
1173 my $signature = shift;
1174 my $type = $codeGenerator->StripModule($signature->type);
1176 if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
1177 # Special-case index arguments because we need to check that they aren't < 0.
1181 return GetNativeType($type);
1188 return "unsigned" if $type eq "unsigned long";
1189 return $type if $type eq "unsigned short" or $type eq "float" or $type eq "AtomicString";
1190 return "bool" if $type eq "boolean";
1191 return "int" if $type eq "long";
1192 return "String" if $type eq "DOMString";
1193 return "PassRefPtr<${type}>" if $type eq "NodeFilter";
1194 return "Range::CompareHow" if $type eq "CompareHow";
1195 return "EventTargetNode*" if $type eq "EventTarget";
1196 return "FloatRect" if $type eq "SVGRect";
1197 return "FloatPoint" if $type eq "SVGPoint";
1198 return "AffineTransform" if $type eq "SVGMatrix";
1199 return "SVGTransform" if $type eq "SVGTransform";
1200 return "SVGLength" if $type eq "SVGLength";
1201 return "double" if $type eq "SVGNumber";
1202 return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType";
1204 # Default, assume native type is a pointer with same type name as idl type
1208 sub TypeCanFailConversion
1210 my $signature = shift;
1212 my $type = $codeGenerator->StripModule($signature->type);
1214 # FIXME: convert to use a hash
1216 return 0 if $type eq "boolean" or
1218 $type eq "AtomicString" or
1219 $type eq "DOMString" or
1221 $type eq "Element" or
1222 $type eq "DocumentType" or
1224 $type eq "EventListener" or
1225 $type eq "EventTarget" or
1227 $type eq "NodeFilter" or
1228 $type eq "DOMWindow" or
1229 $type eq "XPathEvaluator" or
1230 $type eq "XPathNSResolver" or
1231 $type eq "XPathResult" or
1232 $type eq "SVGAngle" or
1233 $type eq "SVGLength" or
1234 $type eq "SVGNumber" or
1235 $type eq "SVGPoint" or
1236 $type eq "SVGTransform" or
1237 $type eq "SVGPathSeg" or
1238 $type eq "SVGMatrix" or
1239 $type eq "SVGRect" or
1240 $type eq "SVGElement" or
1241 $type eq "HTMLElement" or
1242 $type eq "HTMLOptionElement" or
1243 $type eq "unsigned short" or # or can it?
1244 $type eq "CompareHow" or # or can it?
1245 $type eq "SVGPaintType"; # or can it?
1247 if ($type eq "unsigned long" or $type eq "long" or $type eq "Attr") {
1248 $implIncludes{"ExceptionCode.h"} = 1;
1252 die "Don't know whether a JS value can fail conversion to type $type."
1257 my $signature = shift;
1259 my $okParam = shift;
1260 my $maybeOkParam = $okParam ? ", ${okParam}" : "";
1262 my $type = $codeGenerator->StripModule($signature->type);
1264 return "$value->toBoolean(exec)" if $type eq "boolean";
1265 return "$value->toNumber(exec)" if $type eq "float" or $type eq "SVGNumber";
1266 return "$value->toInt32(exec${maybeOkParam})" if $type eq "unsigned long" or $type eq "long" or $type eq "unsigned short";
1268 return "static_cast<Range::CompareHow>($value->toInt32(exec))" if $type eq "CompareHow";
1269 return "static_cast<SVGPaint::SVGPaintType>($value->toInt32(exec))" if $type eq "SVGPaintType";
1271 return "$value->toString(exec)" if $type eq "AtomicString";
1272 if ($type eq "DOMString") {
1273 return "valueToStringWithNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
1274 return "$value->toString(exec)";
1277 if ($type eq "Node") {
1278 $implIncludes{"kjs_dom.h"} = 1;
1279 return "toNode($value)";
1282 if ($type eq "EventTarget") {
1283 $implIncludes{"kjs_dom.h"} = 1;
1284 return "toEventTargetNode($value)";
1287 if ($type eq "Attr") {
1288 $implIncludes{"kjs_dom.h"} = 1;
1289 return "toAttr($value${maybeOkParam})";
1292 if ($type eq "DocumentType") {
1293 $implIncludes{"kjs_dom.h"} = 1;
1294 return "toDocumentType($value)";
1297 if ($type eq "Element") {
1298 $implIncludes{"kjs_dom.h"} = 1;
1299 return "toElement($value)";
1302 if ($type eq "NodeFilter") {
1303 $implIncludes{"kjs_traversal.h"} = 1;
1304 return "toNodeFilter($value)";
1307 if ($type eq "DOMWindow") {
1308 $implIncludes{"kjs_window.h"} = 1;
1309 return "toDOMWindow($value)";
1312 if ($type eq "SVGRect") {
1313 $implIncludes{"FloatRect.h"} = 1;
1316 if ($type eq "SVGPoint") {
1317 $implIncludes{"FloatPoint.h"} = 1;
1320 # Default, assume autogenerated type conversion routines
1321 $implIncludes{"JS$type.h"} = 1;
1322 return "to$type($value)";
1327 my $signature = shift;
1328 my $implClassName = shift;
1331 my $type = $codeGenerator->StripModule($signature->type);
1333 return "jsBoolean($value)" if $type eq "boolean";
1334 return "jsNumber($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType";
1336 if ($codeGenerator->IsStringType($type)) {
1337 my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1338 if (defined $conv) {
1339 return "jsStringOrNull($value)" if $conv eq "Null";
1340 return "jsStringOrUndefined($value)" if $conv eq "Undefined";
1341 return "jsStringOrFalse($value)" if $conv eq "False";
1343 die "Unknown value for ConvertNullStringTo extended attribute";
1345 return "jsString($value)";
1348 if ($type eq "RGBColor") {
1349 $implIncludes{"kjs_css.h"} = 1;
1350 return "getDOMRGBColor(exec, $value)";
1353 if ($codeGenerator->IsPodType($type)) {
1354 $implIncludes{"JS$type.h"} = 1;
1356 my $nativeType = GetNativeType($type);
1358 my $getter = $value;
1359 $getter =~ s/imp->//;
1360 $getter =~ s/\(\)//;
1362 my $setter = "set" . WK_ucfirst($getter);
1364 if ($implClassName eq "") {
1365 return "toJS(exec, new JSSVGPODTypeWrapper<$nativeType>($value))";
1367 return "toJS(exec, new JSSVGPODTypeWrapperCreator<$nativeType, $implClassName>(imp, &${implClassName}::$getter, &${implClassName}::$setter))";
1371 if ($type eq "HTMLCollection") {
1372 $implIncludes{"kjs_html.h"} = 1;
1373 $implIncludes{"HTMLCollection.h"} = 1;
1374 return "getHTMLCollection(exec, WTF::getPtr($value))";
1377 if ($type eq "StyleSheetList") {
1378 $implIncludes{"StyleSheetList.h"} = 1;
1379 $implIncludes{"kjs_css.h"} = 1;
1380 return "toJS(exec, WTF::getPtr($value), imp)";
1383 if ($codeGenerator->IsSVGAnimatedType($type)) {
1385 $value .= "Animated()";
1388 if ($type eq "DOMImplementation") {
1389 $implIncludes{"kjs_dom.h"} = 1;
1390 $implIncludes{"JSDOMImplementation.h"} = 1;
1391 } elsif ($type eq "Attr" or
1392 $type eq "CDATASection" or
1393 $type eq "Comment" or
1394 $type eq "Document" or
1395 $type eq "DocumentFragment" or
1396 $type eq "DocumentType" or
1397 $type eq "Element" or
1398 $type eq "EntityReference" or
1399 $type eq "HTMLDocument" or
1401 $type eq "ProcessingInstruction" or
1403 $implIncludes{"kjs_dom.h"} = 1;
1404 $implIncludes{"Comment.h"} = 1;
1405 $implIncludes{"CDATASection.h"} = 1;
1406 $implIncludes{"Node.h"} = 1;
1407 $implIncludes{"Element.h"} = 1;
1408 $implIncludes{"DocumentType.h"} = 1;
1409 } elsif ($type eq "EventTarget") {
1410 $implIncludes{"kjs_dom.h"} = 1;
1411 $implIncludes{"EventTargetNode.h"} = 1;
1412 } elsif ($type eq "Event") {
1413 $implIncludes{"kjs_events.h"} = 1;
1414 $implIncludes{"Event.h"} = 1;
1415 } elsif ($type eq "NodeList" or $type eq "NamedNodeMap") {
1416 $implIncludes{"kjs_dom.h"} = 1;
1417 } elsif ($type eq "CSSStyleSheet" or $type eq "StyleSheet" or $type eq "MediaList") {
1418 $implIncludes{"CSSStyleSheet.h"} = 1;
1419 $implIncludes{"MediaList.h"} = 1;
1420 $implIncludes{"kjs_css.h"} = 1;
1421 } elsif ($type eq "CSSStyleDeclaration" or $type eq "Rect") {
1422 $implIncludes{"CSSStyleDeclaration.h"} = 1;
1423 $implIncludes{"RectImpl.h"} = 1;
1424 $implIncludes{"kjs_css.h"} = 1;
1425 } elsif ($type eq "HTMLCanvasElement") {
1426 $implIncludes{"kjs_dom.h"} = 1;
1427 $implIncludes{"HTMLCanvasElement.h"} = 1;
1428 } elsif ($type eq "DOMWindow") {
1429 $implIncludes{"kjs_window.h"} = 1;
1430 } elsif ($type eq "DOMObject") {
1431 $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
1432 } elsif ($type eq "HTMLFormElement") {
1433 $implIncludes{"kjs_html.h"} = 1;
1434 $implIncludes{"HTMLFormElement.h"} = 1;
1435 } elsif ($type =~ /SVGPathSeg/) {
1436 $implIncludes{"JS$type.h"} = 1;
1437 $joinedName = $type;
1438 $joinedName =~ s/Abs|Rel//;
1439 $implIncludes{"$joinedName.h"} = 1;
1441 # Default, include header with same name.
1442 $implIncludes{"JS$type.h"} = 1;
1443 $implIncludes{"$type.h"} = 1;
1446 return $value if $codeGenerator->IsSVGAnimatedType($type);
1447 return "toJS(exec, WTF::getPtr($value))";
1451 sub GenerateHashTable
1459 my $specials = shift;
1460 my $parameters = shift;
1468 my $numEntries = $size;
1470 # Collect hashtable information
1472 foreach (@{$keys}) {
1474 my $h = $object->GenerateHashValue($_) % $numEntries;
1476 while (defined($table[$h])) {
1477 if (defined($links[$h])) {
1491 $maxDepth = $depth if ($depth > $maxDepth);
1494 # Ensure table is big enough (in case of undef entries at the end)
1495 if ($#table + 1 < $size) {
1496 $#table = $size - 1;
1499 # Start outputing the hashtables
1500 my $nameEntries = "${name}Entries";
1501 $nameEntries =~ s/:/_/g;
1503 # first, build the string table
1505 if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
1509 if ($name =~ /Prototype/) {
1510 $type =~ s/Prototype.*//;
1511 $implClass = $type; $implClass =~ s/Wrapper$//;
1512 push(@implContent, "/* Hash table for prototype */\n");
1514 $type =~ s/Constructor.*//;
1515 $implClass = $type; $implClass =~ s/Constructor$//;
1516 push(@implContent, "/* Hash table for constructor */\n");
1519 push(@implContent, "/* Hash table */\n");
1522 # Dump the hash table
1523 push(@implContent, "\nstatic const HashEntry $nameEntries\[\] =\n\{\n");
1526 foreach $entry (@table) {
1527 if (defined($entry)) {
1528 my $key = @$keys[$entry];
1530 push(@implContent, " \{ \"" . $key . "\"");
1531 push(@implContent, ", " . @$values[$entry]);
1532 push(@implContent, ", " . @$specials[$entry]);
1533 push(@implContent, ", " . @$parameters[$entry]);
1534 push(@implContent, ", ");
1536 if (defined($links[$i])) {
1537 push(@implContent, "&${nameEntries}[$links[$i]]" . " \}");
1539 push(@implContent, "0 \}");
1542 push(@implContent, " \{ 0, 0, 0, 0, 0 \}");
1545 push(@implContent, ",") unless($i eq $size - 1);
1546 push(@implContent, "\n");
1552 # dummy bucket -- an empty table would crash Lookup::findEntry
1553 push(@implContent, " \{ 0, 0, 0, 0, 0 \}\n") ;
1557 push(@implContent, "};\n\n");
1558 push(@implContent, "static const HashTable $name = \n");
1559 push(@implContent, "{\n 2, $size, $nameEntries, $numEntries\n};\n\n");
1563 sub GenerateHashValue
1567 @chars = split(/ */, $_[0]);
1569 # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1570 # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1571 # were 16-bit chunks, which should give matching results
1573 my $EXP2_32 = 4294967296;
1575 my $hash = 0x9e3779b9;
1576 my $l = scalar @chars; #I wish this was in Ruby --- Maks
1583 for (; $l > 0; $l--) {
1584 $hash += ord($chars[$s]);
1585 my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
1586 $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
1588 $hash += $hash >> 11;
1593 $hash += ord($chars[$s]);
1594 $hash ^= (leftShift($hash, 11)% $EXP2_32);
1595 $hash += $hash >> 17;
1598 # Force "avalanching" of final 127 bits
1599 $hash ^= leftShift($hash, 3);
1600 $hash += ($hash >> 5);
1601 $hash = ($hash% $EXP2_32);
1602 $hash ^= (leftShift($hash, 2)% $EXP2_32);
1603 $hash += ($hash >> 15);
1604 $hash = $hash% $EXP2_32;
1605 $hash ^= (leftShift($hash, 10)% $EXP2_32);
1607 # this avoids ever returning a hash code of 0, since that is used to
1608 # signal "hash not computed yet", using a value that is likely to be
1609 # effectively the same as 0 when the low bits are masked
1610 $hash = 0x80000000 if ($hash == 0);
1618 if (defined($IMPL)) {
1619 # Write content to file.
1620 print $IMPL @implContentHeader;
1622 foreach my $implInclude (sort keys(%implIncludes)) {
1623 my $checkType = $implInclude;
1624 $checkType =~ s/\.h//;
1626 print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
1629 print $IMPL @implContent;
1633 @implHeaderContent = ();
1638 if (defined($HEADER)) {
1639 # Write content to file.
1640 print $HEADER @headerContent;
1644 @headerContent = ();
1650 my $className = shift;
1651 my $protoClassName = shift;
1652 my $interfaceName = shift;
1653 my $canConstruct = shift;
1655 my $implContent = << "EOF";
1656 class ${className}Constructor : public DOMObject {
1658 ${className}Constructor(ExecState* exec)
1660 setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype());
1661 putDirect(exec->propertyNames().prototype, ${protoClassName}::self(exec), None);
1663 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
1664 JSValue* getValueProperty(ExecState*, int token) const;
1665 virtual const ClassInfo* classInfo() const { return &info; }
1666 static const ClassInfo info;
1668 virtual bool implementsHasInstance() const { return true; }
1671 if ($canConstruct) {
1672 $implContent .= << "EOF";
1673 virtual bool implementsConstruct() const { return true; }
1674 virtual JSObject* construct(ExecState* exec, const List& args) { return static_cast<JSObject*>(toJS(exec, new $interfaceName)); }
1678 $implContent .= << "EOF";
1681 const ClassInfo ${className}Constructor::info = { "${interfaceName}Constructor", 0, &${className}ConstructorTable, 0 };
1683 bool ${className}Constructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1685 return getStaticValueSlot<${className}Constructor, DOMObject>(exec, &${className}ConstructorTable, this, propertyName, slot);
1688 JSValue* ${className}Constructor::getValueProperty(ExecState*, int token) const
1690 // The token is the numeric value of its associated constant
1691 return jsNumber(token);
1696 return $implContent;
1699 sub prototypeFunctionFor
1701 my $className = shift;
1703 my $implContent = << "EOF";
1704 class ${className}PrototypeFunction : public InternalFunctionImp {
1706 ${className}PrototypeFunction(ExecState* exec, int i, int len, const Identifier& name)
1707 : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
1710 put(exec, exec->propertyNames().length, jsNumber(len), DontDelete|ReadOnly|DontEnum);
1712 virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args);
1719 return $implContent;