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.
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.
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.
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.
23 package CodeGeneratorJS
;
30 my @headerContent = ();
31 my @implContentHeader = ();
33 my %implIncludes = ();
36 my $headerTemplate = << "EOF";
38 This file has been generated by generate
-bindings
.pl
. DO NOT MODIFY
!
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
.
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
.
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
.
63 $codeGenerator = shift;
66 bless($reference, $object);
79 my ($value, $distance) = @_;
80 return (($value << $distance) & 0xFFFFFFFF);
83 # Uppercase the first letter, while respecting WebKit style guidelines.
84 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
88 my $ret = ucfirst($param);
89 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
93 # Params: 'domClass' struct
100 # Start actual generation
101 $object->GenerateHeader($dataNode);
102 $object->GenerateImplementation($dataNode);
104 my $name = $dataNode->name;
106 # Open files for writing
107 my $headerFileName = "$outputDir/JS$name.h";
108 my $implFileName = "$outputDir/JS$name.cpp";
110 open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
111 open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
114 # Params: 'idlDocument' struct
118 my $dataNode = shift;
120 $module = $dataNode->module;
123 sub GetParentClassName
125 my $dataNode = shift;
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));
132 sub GetLegacyHeaderIncludes
134 my $legacyParent = shift;
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";
142 die "Don't know what headers to include for module $module";
145 sub AvoidInclusionOfType
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";
154 sub UsesManualToJSImplementation
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";
162 sub IndexGetterReturnsStrings
166 return 1 if $type eq "CSSStyleDeclaration" or $type eq "MediaList";
170 sub CreateSVGContextInterfaceName
174 return $type if $codeGenerator->IsSVGAnimatedType($type);
175 return "SVGPathSeg" if $type =~ /^SVGPathSeg/ and $type ne "SVGPathSegList";
180 sub AddIncludesForType
182 my $type = $codeGenerator->StripModule(shift);
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/) {
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;
196 # default, include the same named file
197 $implIncludes{"${type}.h"} = 1;
200 # additional includes (things needed to compile the bindings but not the header)
202 if ($type eq "CanvasRenderingContext2D") {
203 $implIncludes{"CanvasGradient.h"} = 1;
204 $implIncludes{"CanvasPattern.h"} = 1;
205 $implIncludes{"CanvasStyle.h"} = 1;
208 if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
209 $implIncludes{"PlatformString.h"} = 1;
213 sub AddIncludesForSVGAnimatedType
216 $type =~ s/SVGAnimated//;
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;
225 sub AddClassForwardIfNeeded
227 my $implClassName = shift;
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);
233 sub IsSVGTypeNeedingContextParameter
235 my $implClassName = shift;
237 if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) {
238 return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/;
244 sub HashValueForClassAndName
249 # SVG Filter enums live in WebCore namespace (platform/graphics/)
250 if ($class =~ /^SVGFE*/ or $class =~ /^SVGComponentTransferFunctionElement$/) {
251 return "khtml::$name";
254 return "${class}::$name";
260 my $dataNode = shift;
262 my $interfaceName = $dataNode->name;
263 my $className = "JS$interfaceName";
264 my $implClassName = $interfaceName;
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);
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"};
278 # - Add default header template
279 @headerContent = split("\r", $headerTemplate);
281 # - Add header protection
282 push(@headerContent, "\n#ifndef $className" . "_h");
283 push(@headerContent, "\n#define $className" . "_h\n\n");
285 my $conditionalString;
287 $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
288 push(@headerContent, "\n#if ${conditionalString}\n\n");
291 if (exists $dataNode->extendedAttributes->{"LegacyParent"}) {
292 push(@headerContent, GetLegacyHeaderIncludes
($dataNode->extendedAttributes->{"LegacyParent"}));
295 push(@headerContent, "#include \"$parentClassName.h\"\n");
297 push(@headerContent, "#include \"kjs_binding.h\"\n");
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";
306 push(@headerContent, "#include \"JSSVGPODTypeWrapper.h\"\n") if $podType;
308 my $numConstants = @
{$dataNode->constants};
309 my $numAttributes = @
{$dataNode->attributes};
310 my $numFunctions = @
{$dataNode->functions};
312 push(@headerContent, "\nnamespace khtml {\n\n");
314 # Implementation class forward declaration
315 AddClassForwardIfNeeded
($implClassName) unless $podType;
318 push(@headerContent, "class $className : public $parentClassName {\n");
319 push(@headerContent, "public:\n");
322 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
323 push(@headerContent, " $className($passType);\n");
325 if (IsSVGTypeNeedingContextParameter
($implClassName)) {
326 push(@headerContent, " $className(KJS::ExecState*, $passType, SVGElement* context);\n");
328 push(@headerContent, " $className(KJS::ExecState*, $passType);\n");
333 if (!$hasParent or $interfaceName eq "Document") {
334 push(@headerContent, " virtual ~$className();\n");
338 if ($numAttributes > 0 || $dataNode->extendedAttributes->{"GenerateConstructor"}) {
339 push(@headerContent, " virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
340 push(@headerContent, " KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
341 if ($dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
342 push(@headerContent, " bool customGetOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
346 # Check if we have any writable properties
347 my $hasReadWriteProperties = 0;
348 foreach (@
{$dataNode->attributes}) {
349 if ($_->type !~ /^readonly\ attribute$/) {
350 $hasReadWriteProperties = 1;
354 if ($hasReadWriteProperties) {
355 push(@headerContent, " virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n");
356 push(@headerContent, " void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n");
357 if ($dataNode->extendedAttributes->{"CustomPutFunction"}) {
358 push(@headerContent, " bool customPut(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr);\n");
363 push(@headerContent, " virtual const KJS::ClassInfo* classInfo() const { return &s_info; }\n");
364 push(@headerContent, " static const KJS::ClassInfo s_info;\n\n");
366 # Custom mark function
367 if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
368 push(@headerContent, " virtual void mark();\n\n");
371 # Custom pushEventHandlerScope function
372 if ($dataNode->extendedAttributes->{"CustomPushEventHandlerScope"}) {
373 push(@headerContent, " virtual void pushEventHandlerScope(KJS::ExecState*, KJS::ScopeChain&) const;\n\n");
376 # Custom call functions
377 if ($dataNode->extendedAttributes->{"CustomCall"}) {
378 push(@headerContent, " virtual KJS::JSValue* callAsFunction(KJS::ExecState*, KJS::JSObject*, const KJS::List&);\n");
379 push(@headerContent, " virtual bool implementsCall() const;\n\n");
382 # Constructor object getter
383 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
384 push(@headerContent, " static KJS::JSValue* getConstructor(KJS::ExecState*);\n");
387 my $numCustomFunctions = 0;
388 my $numCustomAttributes = 0;
390 # Attribute and function enums
391 my $hasAttrFunctionEnum = ($numAttributes + $numFunctions > 0) || $dataNode->extendedAttributes->{"GenerateConstructor"};
392 push(@headerContent, " enum {\n") if ($hasAttrFunctionEnum);
394 if ($numAttributes > 0) {
395 push(@headerContent, " // Attributes\n ");
398 foreach (@
{$dataNode->attributes}) {
401 $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"};
402 $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomGetter"};
403 $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"CustomSetter"};
406 if ((($i % 4) eq 0) and ($i ne 0)) {
407 push(@headerContent, "\n ");
410 my $value = $attribute->signature->type =~ /Constructor$/
411 ?
$attribute->signature->name . "ConstructorAttrNum"
412 : WK_ucfirst
($attribute->signature->name) . "AttrNum";
413 $value .= ", " if (($i < $numAttributes - 1) or (($i eq $numAttributes - 1) and (($numFunctions ne 0) or $dataNode->extendedAttributes->{"GenerateConstructor"})));
414 push(@headerContent, $value);
418 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
419 push(@headerContent, "\n\n") if $numAttributes > 0;
420 push(@headerContent, " // The Constructor Attribute\n");
421 push(@headerContent, " ConstructorAttrNum" . ($numFunctions ?
", " : ""));
424 if ($numFunctions > 0) {
425 push(@headerContent, "\n\n") if $numAttributes > 0 || $dataNode->extendedAttributes->{"GenerateConstructor"};
426 push(@headerContent," // Functions\n ");
429 foreach my $function (@
{$dataNode->functions}) {
432 push(@headerContent, "\n ") if ((($i % 4) eq 0) and ($i ne 0));
434 $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"};
436 my $value = WK_ucfirst
($function->signature->name) . "FuncNum";
437 $value .= ", " if ($i < $numFunctions - 1);
438 push(@headerContent, $value);
443 push(@headerContent, "\n };\n") if ($hasAttrFunctionEnum);
445 if ($numCustomAttributes > 0) {
446 push(@headerContent, "\n // Custom attributes\n");
448 foreach my $attribute (@
{$dataNode->attributes}) {
449 if ($attribute->signature->extendedAttributes->{"Custom"}) {
450 push(@headerContent, " KJS::JSValue* " . $attribute->signature->name . "(KJS::ExecState*) const;\n");
451 if ($attribute->type !~ /^readonly/) {
452 push(@headerContent, " void set" . WK_ucfirst
($attribute->signature->name) . "(KJS::ExecState*, KJS::JSValue*);\n");
454 } elsif ($attribute->signature->extendedAttributes->{"CustomGetter"}) {
455 push(@headerContent, " KJS::JSValue* " . $attribute->signature->name . "(KJS::ExecState*) const;\n");
456 } elsif ($attribute->signature->extendedAttributes->{"CustomSetter"}) {
457 if ($attribute->type !~ /^readonly/) {
458 push(@headerContent, " void set" . WK_ucfirst
($attribute->signature->name) . "(KJS::ExecState*, KJS::JSValue*);\n");
464 if ($numCustomFunctions > 0) {
465 push(@headerContent, "\n // Custom functions\n");
466 foreach my $function (@
{$dataNode->functions}) {
467 if ($function->signature->extendedAttributes->{"Custom"}) {
468 push(@headerContent, " KJS::JSValue* " . $function->signature->name . "(KJS::ExecState*, const KJS::List&);\n");
474 if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
475 push(@headerContent, " void indexSetter(KJS::ExecState*, unsigned index, KJS::JSValue*, int attr);\n");
480 push(@headerContent, " JSSVGPODTypeWrapper<$podType>* impl() const { return m_impl.get(); }\n");
481 push(@headerContent, " SVGElement* context() const { return m_context.get(); }\n\n");
482 push(@headerContent, "private:\n");
483 push(@headerContent, " RefPtr<SVGElement> m_context;\n");
484 push(@headerContent, " RefPtr<JSSVGPODTypeWrapper<$podType> > m_impl;\n");
485 } elsif (IsSVGTypeNeedingContextParameter
($implClassName)) {
486 push(@headerContent, " $implClassName* impl() const { return m_impl.get(); }\n");
487 push(@headerContent, " SVGElement* context() const { return m_context.get(); }\n\n");
488 push(@headerContent, "private:\n");
489 push(@headerContent, " RefPtr<SVGElement> m_context;\n");
490 push(@headerContent, " RefPtr<$implClassName > m_impl;\n");
492 push(@headerContent, " $implClassName* impl() const { return m_impl.get(); }\n\n");
493 push(@headerContent, "private:\n");
494 push(@headerContent, " RefPtr<$implClassName> m_impl;\n");
496 } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
497 push(@headerContent, " $implClassName* impl() const;\n");
501 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
502 push(@headerContent, "private:\n");
503 push(@headerContent, " static KJS::JSValue* indexGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
506 if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
507 push(@headerContent, "private:\n");
508 push(@headerContent, " static bool canGetItemsForName(KJS::ExecState*, $implClassName*, const KJS::Identifier&);\n");
509 push(@headerContent, " static KJS::JSValue* nameGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
512 push(@headerContent, "};\n\n");
514 if (!$hasParent || $dataNode->extendedAttributes->{"GenerateToJS"}) {
516 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, JSSVGPODTypeWrapper<$podType>*, SVGElement* context);\n");
517 } elsif (IsSVGTypeNeedingContextParameter
($implClassName)) {
518 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, $passType, SVGElement* context);\n");
519 } elsif ($interfaceName eq "Node") {
520 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, PassRefPtr<Node>);\n");
522 push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, $passType);\n");
525 if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
527 push(@headerContent, "$podType to${interfaceName}(KJS::JSValue*);\n");
529 push(@headerContent, "$implClassName* to${interfaceName}(KJS::JSValue*);\n");
532 push(@headerContent, "\n");
534 # Add prototype declaration -- code adopted from the KJS_DEFINE_PROTOTYPE and KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE macros
535 push(@headerContent, "class ${className}Prototype : public KJS::JSObject {\n");
536 push(@headerContent, "public:\n");
537 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
538 push(@headerContent, " static KJS::JSObject* self();\n");
540 push(@headerContent, " static KJS::JSObject* self(KJS::ExecState* exec);\n");
542 push(@headerContent, " virtual const KJS::ClassInfo* classInfo() const { return &s_info; }\n");
543 push(@headerContent, " static const KJS::ClassInfo s_info;\n");
544 if ($numFunctions > 0 || $numConstants > 0) {
545 push(@headerContent, " bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
547 if ($numConstants ne 0) {
548 push(@headerContent, " KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
550 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
551 push(@headerContent, " ${className}Prototype() { }\n");
553 push(@headerContent, " ${className}Prototype(KJS::ExecState* exec)\n");
554 if ($hasParent && $parentClassName ne "KJS::DOMNodeFilter") {
555 push(@headerContent, " : KJS::JSObject(${parentClassName}Prototype::self(exec)) { }\n");
557 push(@headerContent, " : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { }\n");
561 push(@headerContent, "};\n\n");
563 if ($numFunctions > 0) {
564 push(@headerContent, prototypeFunctionFor
($className));
567 push(@headerContent, "} // namespace khtml\n\n");
568 push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditional;
569 push(@headerContent, "#endif\n");
572 sub GenerateImplementation
574 my ($object, $dataNode) = @_;
576 my $interfaceName = $dataNode->name;
577 my $className = "JS$interfaceName";
578 my $implClassName = $interfaceName;
580 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
581 my $hasRealParent = @
{$dataNode->parents} > 0;
582 my $hasParent = $hasLegacyParent || $hasRealParent;
583 my $parentClassName = GetParentClassName
($dataNode);
584 my $conditional = $dataNode->extendedAttributes->{"Conditional"};
586 # - Add default header template
587 @implContentHeader = split("\r", $headerTemplate);
588 push(@implContentHeader, "\n#include <wtf/Platform.h>\n\n");
589 my $conditionalString;
591 $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
592 push(@implContentHeader, "\n#if ${conditionalString}\n\n");
595 if ($className =~ /^JSSVG/) {
596 push(@implContentHeader, "#include \"Document.h\"\n");
597 push(@implContentHeader, "#include \"Frame.h\"\n");
598 push(@implContentHeader, "#include \"SVGDocumentExtensions.h\"\n");
599 push(@implContentHeader, "#include \"SVGElement.h\"\n");
600 push(@implContentHeader, "#include \"SVGAnimatedTemplate.h\"\n");
602 if ($className =~ /^JSSVGAnimated/) {
603 AddIncludesForSVGAnimatedType
($interfaceName);
607 push(@implContentHeader, "#include \"$className.h\"\n\n");
608 push(@implContentHeader, "#include <wtf/GetPtr.h>\n\n");
609 push(@implContentHeader, "#include <kjs/ExecState.h>\n\n");
610 push(@implContentHeader, "using namespace KJS;\n\n");
612 AddIncludesForType
($interfaceName);
616 push(@implContent, "\nusing namespace KJS;\n\n");
617 push(@implContent, "namespace khtml {\n\n");
619 # - Add all attributes in a hashtable definition
620 my $numAttributes = @
{$dataNode->attributes};
621 $numAttributes++ if $dataNode->extendedAttributes->{"GenerateConstructor"};
623 if ($numAttributes > 0) {
624 my $hashSize = $numAttributes;
625 my $hashName = $className . "Table";
627 my @hashKeys = (); # ie. 'insertBefore'
628 my @hashValues = (); # ie. 'JSNode::InsertBefore'
629 my @hashSpecials = (); # ie. 'DontDelete|Function'
630 my @hashParameters = (); # ie. '2'
632 foreach my $attribute (@
{$dataNode->attributes}) {
633 my $name = $attribute->signature->name;
634 push(@hashKeys, $name);
636 my $value = $className . "::" . ($attribute->signature->type =~ /Constructor$/
637 ?
$attribute->signature->name . "ConstructorAttrNum"
638 : WK_ucfirst
($attribute->signature->name) . "AttrNum");
639 push(@hashValues, $value);
642 push(@specials, "DontDelete") unless $attribute->signature->extendedAttributes->{"Deletable"};
643 push(@specials, "DontEnum") if $attribute->signature->extendedAttributes->{"DontEnum"};
644 push(@specials, "ReadOnly") if $attribute->type =~ /readonly/;
645 my $special = (@specials > 0) ?
join("|", @specials) : "0";
646 push(@hashSpecials, $special);
648 my $numParameters = "0";
649 push(@hashParameters, $numParameters);
652 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
653 push(@hashKeys, "constructor");
654 push(@hashValues, $className . "::ConstructorAttrNum");
655 push(@hashSpecials, "DontDelete|DontEnum|ReadOnly");
656 push(@hashParameters, "0");
659 $object->GenerateHashTable($hashName, $hashSize,
660 \
@hashKeys, \
@hashValues,
661 \
@hashSpecials, \
@hashParameters);
664 my $numConstants = @
{$dataNode->constants};
665 my $numFunctions = @
{$dataNode->functions};
667 # - Add all constants
668 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
669 $hashSize = $numConstants;
670 $hashName = $className . "ConstructorTable";
675 @hashParameters = ();
677 foreach my $constant (@
{$dataNode->constants}) {
678 my $name = $constant->name;
679 push(@hashKeys, $name);
681 my $value = HashValueForClassAndName
($implClassName, $name);
682 push(@hashValues, $value);
684 my $special = "DontDelete|ReadOnly";
685 push(@hashSpecials, $special);
687 my $numParameters = 0;
688 push(@hashParameters, $numParameters);
691 $object->GenerateHashTable($hashName, $hashSize,
692 \
@hashKeys, \
@hashValues,
693 \
@hashSpecials, \
@hashParameters);
696 $protoClassName = "${className}Prototype";
698 push(@implContent, constructorFor
($className, $protoClassName, $interfaceName, $dataNode->extendedAttributes->{"CanBeConstructed"}));
701 # - Add functions and constants to a hashtable definition
702 $hashSize = $numFunctions + $numConstants;
703 $hashName = $className . "PrototypeTable";
708 @hashParameters = ();
710 foreach my $constant (@
{$dataNode->constants}) {
711 my $name = $constant->name;
712 push(@hashKeys, $name);
714 my $value = HashValueForClassAndName
($implClassName, $name);
715 push(@hashValues, $value);
717 my $special = "DontDelete|ReadOnly";
718 push(@hashSpecials, $special);
720 my $numParameters = 0;
721 push(@hashParameters, $numParameters);
724 foreach my $function (@
{$dataNode->functions}) {
725 my $name = $function->signature->name;
726 push(@hashKeys, $name);
728 my $value = $className . "::" . WK_ucfirst
($name) . "FuncNum";
729 push(@hashValues, $value);
732 push(@specials, "DontDelete") unless $function->signature->extendedAttributes->{"Deletable"};
733 push(@specials, "DontEnum") if $function->signature->extendedAttributes->{"DontEnum"};
734 push(@specials, "Function");
735 my $special = (@specials > 0) ?
join("|", @specials) : "0";
736 push(@hashSpecials, $special);
738 my $numParameters = @
{$function->parameters};
739 push(@hashParameters, $numParameters);
742 $object->GenerateHashTable($hashName, $hashSize,
743 \
@hashKeys, \
@hashValues,
744 \
@hashSpecials, \
@hashParameters);
746 push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${interfaceName}Prototype\", 0, &${className}PrototypeTable, 0 };\n\n");
747 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
748 push(@implContent, "JSObject* ${className}Prototype::self()\n");
749 push(@implContent, "{\n");
750 push(@implContent, " return new ${className}Prototype();\n");
751 push(@implContent, "}\n\n");
753 push(@implContent, "JSObject* ${className}Prototype::self(ExecState* exec)\n");
754 push(@implContent, "{\n");
755 push(@implContent, " return ::cacheGlobalObject<${className}Prototype>(exec, \"[[${className}.prototype]]\");\n");
756 push(@implContent, "}\n\n");
758 if ($numConstants > 0 || $numFunctions > 0) {
759 push(@implContent, "bool ${className}Prototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
760 push(@implContent, "{\n");
761 if ($numConstants eq 0) {
762 push(@implContent, " return getStaticFunctionSlot<${className}PrototypeFunction, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
763 } elsif ($numFunctions eq 0) {
764 push(@implContent, " return getStaticValueSlot<${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
766 push(@implContent, " return getStaticPropertySlot<${className}PrototypeFunction, ${className}Prototype, JSObject>(exec, &${className}PrototypeTable, this, propertyName, slot);\n");
768 push(@implContent, "}\n\n");
770 if ($numConstants ne 0) {
771 push(@implContent, "JSValue* ${className}Prototype::getValueProperty(ExecState*, int token) const\n{\n");
772 push(@implContent, " // The token is the numeric value of its associated constant\n");
773 push(@implContent, " return jsNumber(token);\n}\n\n");
776 # - Initialize static ClassInfo object
777 push(@implContent, "const ClassInfo $className" . "::s_info = { \"$interfaceName\", ");
779 push(@implContent, "&" . $parentClassName . "::s_info, ");
781 push(@implContent, "0, ");
784 if ($numAttributes > 0) {
785 push(@implContent, "&${className}Table ");
787 push(@implContent, "0 ");
789 push(@implContent, ", 0 };\n\n");
791 # Get correct pass/store types respecting PODType flag
792 my $podType = $dataNode->extendedAttributes->{"PODType"};
793 my $passType = $podType ?
"JSSVGPODTypeWrapper<$podType>*" : "$implClassName*";
796 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
797 push(@implContent, "${className}::$className($passType impl)\n");
798 push(@implContent, " : $parentClassName(impl)\n");
800 my $needsSVGContext = IsSVGTypeNeedingContextParameter
($implClassName);
801 if ($needsSVGContext) {
802 push(@implContent, "${className}::$className(ExecState* exec, $passType impl, SVGElement* context)\n");
804 push(@implContent, "${className}::$className(ExecState* exec, $passType impl)\n");
808 if ($needsSVGContext and $parentClassName =~ /SVG/) {
809 push(@implContent, " : $parentClassName(exec, impl, context)\n");
811 push(@implContent, " : $parentClassName(exec, impl)\n");
814 if ($needsSVGContext) {
815 push(@implContent, " : m_context(context)\n");
816 push(@implContent, " , m_impl(impl)\n");
818 push(@implContent, " : m_impl(impl)\n");
823 if ($dataNode->extendedAttributes->{"DoNotCache"}) {
824 push(@implContent, "{\n setPrototype(${className}Prototype::self());\n}\n\n");
826 push(@implContent, "{\n setPrototype(${className}Prototype::self(exec));\n}\n\n");
831 push(@implContent, "${className}::~$className()\n");
832 push(@implContent, "{\n");
834 if ($interfaceName eq "Node") {
835 push(@implContent, " ScriptInterpreter::forgetDOMNodeForDocument(m_impl->document(), m_impl.get());\n");
838 my $animatedType = $implClassName;
839 $animatedType =~ s/SVG/SVGAnimated/;
841 # Special case for JSSVGNumber
842 if ($codeGenerator->IsSVGAnimatedType($animatedType) and $podType ne "float") {
843 push(@implContent, " JSSVGPODTypeWrapperCache<$podType, $animatedType>::forgetWrapper(m_impl.get());\n");
846 push(@implContent, " ScriptInterpreter::forgetDOMObject(m_impl.get());\n");
849 push(@implContent, "\n}\n\n");
852 # Document needs a special destructor because it's a special case for caching. It needs
853 # its own special handling rather than relying on the caching that Node normally does.
854 if ($interfaceName eq "Document") {
855 push(@implContent, "${className}::~$className()\n");
856 push(@implContent, "{\n ScriptInterpreter::forgetDOMObject(static_cast<${implClassName}*>(impl()));\n}\n\n");
860 if ($numAttributes ne 0) {
861 push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
862 push(@implContent, "{\n");
864 if ($interfaceName eq "NamedNodeMap" or $interfaceName eq "HTMLCollection") {
865 push(@implContent, " JSValue* proto = prototype();\n");
866 push(@implContent, " if (proto->isObject() && static_cast<JSObject*>(proto)->hasProperty(exec, propertyName))\n");
867 push(@implContent, " return false;\n\n");
870 my $hasNameGetterGeneration = sub {
871 push(@implContent, " if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
872 push(@implContent, " slot.setCustom(this, nameGetter);\n");
873 push(@implContent, " return true;\n");
874 push(@implContent, " }\n");
875 $implIncludes{"AtomicString.h"} = 1;
878 if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
879 &$hasNameGetterGeneration();
882 my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
883 if ($requiresManualLookup) {
884 push(@implContent, " const HashEntry* entry = Lookup::findEntry(&${className}Table, propertyName);\n");
885 push(@implContent, " if (entry) {\n");
886 push(@implContent, " slot.setStaticEntry(this, entry, staticValueGetter<$className>);\n");
887 push(@implContent, " return true;\n");
888 push(@implContent, " }\n");
891 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
892 push(@implContent, " bool ok;\n");
893 push(@implContent, " unsigned index = propertyName.toUInt32(&ok, false);\n");
894 push(@implContent, " if (ok && index < static_cast<$implClassName*>(impl())->length()) {\n");
895 push(@implContent, " slot.setCustomIndex(this, index, indexGetter);\n");
896 push(@implContent, " return true;\n");
897 push(@implContent, " }\n");
900 if ($dataNode->extendedAttributes->{"HasNameGetter"}) {
901 &$hasNameGetterGeneration();
904 if ($dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
905 push(@implContent, " if (customGetOwnPropertySlot(exec, propertyName, slot))\n");
906 push(@implContent, " return true;\n");
909 if ($requiresManualLookup) {
910 push(@implContent, " return ${parentClassName}::getOwnPropertySlot(exec, propertyName, slot);\n");
912 push(@implContent, " return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
914 push(@implContent, "}\n\n");
916 push(@implContent, "JSValue* ${className}::getValueProperty(ExecState* exec, int token) const\n{\n");
918 push(@implContent, " switch (token) {\n");
920 foreach my $attribute (@
{$dataNode->attributes}) {
921 my $name = $attribute->signature->name;
923 my $implClassNameForValueConversion = "";
924 if (!$podType and ($codeGenerator->IsSVGAnimatedType($implClassName) or $attribute->type !~ /^readonly/)) {
925 $implClassNameForValueConversion = $implClassName;
928 if ($attribute->signature->type =~ /Constructor$/) {
929 push(@implContent, " case " . $name . "ConstructorAttrNum: {\n");
931 push(@implContent, " case " . WK_ucfirst
($name) . "AttrNum: {\n");
934 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
935 push(@implContent, " if (!isSafeScript(exec))\n");
936 push(@implContent, " return jsUndefined();\n");
939 if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomGetter"}) {
940 push(@implContent, " return $name(exec);\n");
941 } elsif ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) {
942 $implIncludes{"kjs_dom.h"} = 1;
943 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
944 push(@implContent, " return checkNodeSecurity(exec, imp->$name()) ? " . NativeToJSValue
($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$name()") . " : jsUndefined();\n");
945 } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) {
946 $implIncludes{"Document.h"} = 1;
947 $implIncludes{"kjs_dom.h"} = 1;
948 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
949 push(@implContent, " return checkNodeSecurity(exec, imp->contentDocument()) ? " . NativeToJSValue
($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$name()") . " : jsUndefined();\n");
950 } elsif ($attribute->signature->type =~ /Constructor$/) {
951 my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
952 $constructorType =~ s/Constructor$//;
953 push(@implContent, " return JS" . $constructorType . "::getConstructor(exec);\n");
954 } elsif (!@
{$attribute->getterExceptions}) {
956 push(@implContent, " $podType imp(*impl());\n\n");
957 if ($podType eq "float") { # Special case for JSSVGNumber
958 push(@implContent, " return " . NativeToJSValue
($attribute->signature, 0, $implClassName, "", "imp") . ";\n");
960 push(@implContent, " return " . NativeToJSValue
($attribute->signature, 0, $implClassName, "", "imp.$name()") . ";\n");
963 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
964 my $type = $codeGenerator->StripModule($attribute->signature->type);
965 my $jsType = NativeToJSValue
($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$name()");
967 if ($codeGenerator->IsSVGAnimatedType($type)) {
968 push(@implContent, " RefPtr<$type> obj = $jsType;\n");
969 push(@implContent, " return toJS(exec, obj.get(), imp);\n");
971 push(@implContent, " return $jsType;\n");
975 push(@implContent, " ExceptionCode ec = 0;\n");
978 push(@implContent, " $podType imp(*impl());\n\n");
979 push(@implContent, " KJS::JSValue* result = " . NativeToJSValue
($attribute->signature, 0, $implClassName, "", "imp.$name(ec)") . ";\n");
981 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
982 push(@implContent, " KJS::JSValue* result = " . NativeToJSValue
($attribute->signature, 0, $implClassName, $implClassNameForValueConversion, "imp->$name(ec)") . ";\n");
985 push(@implContent, " setDOMException(exec, ec);\n");
986 push(@implContent, " return result;\n");
988 push(@implContent, " }\n");
991 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
992 push(@implContent, " case ConstructorAttrNum:\n");
993 push(@implContent, " return getConstructor(exec);\n");
996 push(@implContent, " }\n");
997 push(@implContent, " return 0;\n}\n\n");
999 # Check if we have any writable attributes
1000 my $hasReadWriteProperties = 0;
1001 foreach my $attribute (@
{$dataNode->attributes}) {
1002 $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
1004 if ($hasReadWriteProperties) {
1005 push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
1006 push(@implContent, "{\n");
1007 if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
1008 push(@implContent, " bool ok;\n");
1009 push(@implContent, " unsigned index = propertyName.toUInt32(&ok, false);\n");
1010 push(@implContent, " if (ok) {\n");
1011 push(@implContent, " indexSetter(exec, index, value, attr);\n");
1012 push(@implContent, " return;\n");
1013 push(@implContent, " }\n");
1015 if ($dataNode->extendedAttributes->{"CustomPutFunction"}) {
1016 push(@implContent, " if (customPut(exec, propertyName, value, attr))\n");
1017 push(@implContent, " return;\n");
1020 push(@implContent, " lookupPut<$className, $parentClassName>(exec, propertyName, value, attr, &${className}Table, this);\n");
1021 push(@implContent, "}\n\n");
1023 push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
1024 push(@implContent, "{\n");
1026 push(@implContent, " switch (token) {\n");
1028 foreach my $attribute (@
{$dataNode->attributes}) {
1029 if ($attribute->type !~ /^readonly/) {
1030 my $name = $attribute->signature->name;
1032 if ($attribute->signature->type =~ /Constructor$/) {
1033 push(@implContent, " case " . $name ."ConstructorAttrNum: {\n");
1035 push(@implContent, " case " . WK_ucfirst
($name) . "AttrNum: {\n");
1038 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
1039 push(@implContent, " if (!isSafeScript(exec))\n");
1040 push(@implContent, " return;\n");
1043 if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomSetter"}) {
1044 push(@implContent, " set" . WK_ucfirst
($name) . "(exec, value);\n");
1045 } elsif ($attribute->signature->type =~ /Constructor$/) {
1046 my $constructorType = $attribute->signature->type;
1047 $constructorType =~ s/Constructor$//;
1048 $implIncludes{"JS" . $constructorType . ".h"} = 1;
1049 push(@implContent, " // Shadowing a built-in constructor\n");
1050 push(@implContent, " JSObject::put(exec, \"$name\", value);\n");
1051 } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
1052 push(@implContent, " JSObject::put(exec, \"$name\", value);\n");
1055 push(@implContent, " $podType imp(*impl());\n\n");
1056 if ($podType eq "float") { # Special case for JSSVGNumber
1057 push(@implContent, " imp = " . JSValueToNative
($attribute->signature, "value") . ";\n");
1059 push(@implContent, " imp.set" . WK_ucfirst
($name) . "(" . JSValueToNative
($attribute->signature, "value") . ");\n");
1061 push(@implContent, " m_impl->commitChange(exec, imp);\n");
1063 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
1064 push(@implContent, " ExceptionCode ec = 0;\n") if @
{$attribute->setterExceptions};
1065 push(@implContent, " imp->set" . WK_ucfirst
($name) . "(" . JSValueToNative
($attribute->signature, "value"));
1066 push(@implContent, ", ec") if @
{$attribute->setterExceptions};
1067 push(@implContent, ");\n");
1068 push(@implContent, " setDOMException(exec, ec);\n") if @
{$attribute->setterExceptions};
1071 push(@implContent, " break;\n");
1072 push(@implContent, " }\n");
1075 push(@implContent, " }\n"); # end switch
1077 if (IsSVGTypeNeedingContextParameter
($implClassName)) {
1078 push(@implContent, " if (context())\n");
1079 push(@implContent, " context()->notifyAttributeChange();\n");
1082 push(@implContent, "}\n\n"); # end function
1086 if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
1087 push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
1088 push(@implContent, " return ::cacheGlobalObject<${className}Constructor>(exec, \"[[${interfaceName}.constructor]]\");\n");
1089 push(@implContent, "}\n");
1093 if ($numFunctions ne 0) {
1094 push(@implContent, "JSValue* ${className}PrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)\n{\n");
1095 push(@implContent, " if (!thisObj->inherits(&${className}::s_info))\n");
1096 push(@implContent, " return throwError(exec, TypeError);\n\n");
1098 push(@implContent, " $className* castedThisObj = static_cast<$className*>(thisObj);\n");
1100 push(@implContent, " JSSVGPODTypeWrapper<$podType>* wrapper = castedThisObj->impl();\n");
1101 push(@implContent, " $podType imp(*wrapper);\n\n");
1103 push(@implContent, " $implClassName* imp = static_cast<$implClassName*>(castedThisObj->impl());\n\n");
1106 push(@implContent, " switch (id) {\n");
1108 my $hasCustomFunctionsOnly = 1;
1110 foreach my $function (@
{$dataNode->functions}) {
1111 push(@implContent, " case ${className}::" . WK_ucfirst
($function->signature->name) . "FuncNum: {\n");
1113 if ($function->signature->extendedAttributes->{"Custom"}) {
1114 push(@implContent, " return castedThisObj->" . $function->signature->name . "(exec, args);\n }\n");
1118 $hasCustomFunctionsOnly = 0;
1119 AddIncludesForType
($function->signature->type);
1121 if (@
{$function->raisesExceptions}) {
1122 push(@implContent, " ExceptionCode ec = 0;\n");
1125 if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) {
1126 push(@implContent, " if (!checkNodeSecurity(exec, imp->getSVGDocument(" . (@
{$function->raisesExceptions} ?
"ec" : "") .")))\n");
1127 push(@implContent, " return jsUndefined();\n");
1128 $implIncludes{"kjs_dom.h"} = 1;
1132 my $functionString = "imp" . ($podType ?
"." : "->") . $function->signature->name . "(";
1134 my $numParameters = @
{$function->parameters};
1135 my $hasOptionalArguments = 0;
1137 foreach my $parameter (@
{$function->parameters}) {
1138 if (!$hasOptionalArguments && $parameter->extendedAttributes->{"Optional"}) {
1139 push(@implContent, "\n int argsCount = args.size();\n");
1140 $hasOptionalArguments = 1;
1143 if ($hasOptionalArguments) {
1144 push(@implContent, " if (argsCount < " . ($paramIndex + 1) . ") {\n");
1145 GenerateImplementationFunctionCall
($function, $functionString, $paramIndex, " " x
3, $podType, $implClassName);
1146 push(@implContent, " }\n\n");
1149 my $name = $parameter->name;
1151 if ($parameter->type eq "XPathNSResolver") {
1152 push(@implContent, " RefPtr<XPathNSResolver> customResolver;\n");
1153 push(@implContent, " XPathNSResolver* resolver = toXPathNSResolver(args[$paramIndex]);\n");
1154 push(@implContent, " if (!resolver) {\n");
1155 push(@implContent, " customResolver = JSCustomXPathNSResolver::create(exec, args[$paramIndex]);\n");
1156 push(@implContent, " if (exec->hadException())\n");
1157 push(@implContent, " return jsUndefined();\n");
1158 push(@implContent, " resolver = customResolver.get();\n");
1159 push(@implContent, " }\n");
1161 push(@implContent, " bool ${name}Ok;\n") if TypeCanFailConversion
($parameter);
1162 push(@implContent, " " . GetNativeTypeFromSignature
($parameter) . " $name = " . JSValueToNative
($parameter, "args[$paramIndex]", TypeCanFailConversion
($parameter) ?
"${name}Ok" : undef) . ";\n");
1163 if (TypeCanFailConversion
($parameter)) {
1164 push(@implContent, " if (!${name}Ok) {\n");
1165 push(@implContent, " setDOMException(exec, DOM::DOMException::TYPE_MISMATCH_ERR);\n");
1166 push(@implContent, " return jsUndefined();\n }\n");
1169 # If a parameter is "an index", it should throw an INDEX_SIZE_ERR
1171 if ($parameter->extendedAttributes->{"IsIndex"}) {
1172 $implIncludes{"ExceptionCode.h"} = 1;
1173 push(@implContent, " if ($name < 0) {\n");
1174 push(@implContent, " setDOMException(exec, DOM::DOMException::INDEX_SIZE_ERR);\n");
1175 push(@implContent, " return jsUndefined();\n }\n");
1179 $functionString .= ", " if $paramIndex;
1180 $functionString .= $name;
1185 push(@implContent, "\n");
1186 GenerateImplementationFunctionCall
($function, $functionString, $paramIndex, " " x
2, $podType, $implClassName);
1188 push(@implContent, " }\n"); # end case
1190 push(@implContent, " }\n"); # end switch
1191 push(@implContent, " (void)imp;\n") if $hasCustomFunctionsOnly;
1192 push(@implContent, " return 0;\n");
1193 push(@implContent, "}\n");
1196 if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
1197 push(@implContent, "\nJSValue* ${className}::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot)\n");
1198 push(@implContent, "{\n");
1199 push(@implContent, " ${className}* thisObj = static_cast<$className*>(slot.slotBase());\n");
1200 if (IndexGetterReturnsStrings
($implClassName)) {
1201 # TODO $implIncludes{"PlatformString.h"} = 1;
1202 push(@implContent, " return jsStringOrNull(thisObj->impl()->item(slot.index()));\n");
1204 push(@implContent, " return toJS(exec, static_cast<$implClassName*>(thisObj->impl())->item(slot.index()));\n");
1206 push(@implContent, "}\n");
1207 if ($interfaceName eq "HTMLCollection") {
1208 $implIncludes{"JSNode.h"} = 1;
1209 $implIncludes{"Node.h"} = 1;
1213 if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !UsesManualToJSImplementation
($implClassName)) {
1215 push(@implContent, "KJS::JSValue* toJS(KJS::ExecState* exec, JSSVGPODTypeWrapper<$podType>* obj, SVGElement* context)\n");
1216 } elsif (IsSVGTypeNeedingContextParameter
($implClassName)) {
1217 push(@implContent, "KJS::JSValue* toJS(KJS::ExecState* exec, $passType obj, SVGElement* context)\n");
1219 push(@implContent, "KJS::JSValue* toJS(KJS::ExecState* exec, $passType obj)\n");
1222 push(@implContent, "{\n");
1224 push(@implContent, " return KJS::cacheSVGDOMObject<JSSVGPODTypeWrapper<$podType>, $className>(exec, obj, context);\n");
1225 } elsif (IsSVGTypeNeedingContextParameter
($implClassName)) {
1226 push(@implContent, " return KJS::cacheSVGDOMObject<$implClassName, $className>(exec, obj, context);\n");
1228 push(@implContent, " return KJS::cacheDOMObject<$implClassName, $className>(exec, obj);\n");
1230 push(@implContent, "}\n");
1233 if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) {
1235 push(@implContent, "$podType to${interfaceName}(KJS::JSValue* val)\n");
1237 push(@implContent, "$implClassName* to${interfaceName}(KJS::JSValue* val)\n");
1240 push(@implContent, "{\n");
1242 push(@implContent, " return val->isObject(&${className}::s_info) ? " . ($podType ?
"($podType) *" : "") . "static_cast<$className*>(val)->impl() : ");
1243 if ($podType and $podType ne "float") {
1244 push(@implContent, "$podType();\n}\n");
1246 push(@implContent, "0;\n}\n");
1250 if ($dataNode->extendedAttributes->{"GenerateNativeConverter"} && $hasParent) {
1251 push(@implContent, "\n$implClassName* ${className}::impl() const\n");
1252 push(@implContent, "{\n");
1253 push(@implContent, " return static_cast<$implClassName*>(${parentClassName}::impl());\n");
1254 push(@implContent, "}\n");
1257 push(@implContent, "\n}\n");
1259 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditional;
1262 sub GenerateImplementationFunctionCall
()
1264 my $function = shift;
1265 my $functionString = shift;
1266 my $paramIndex = shift;
1268 my $podType = shift;
1269 my $implClassName = shift;
1271 if (@
{$function->raisesExceptions}) {
1272 $functionString .= ", " if $paramIndex;
1273 $functionString .= "ec";
1275 $functionString .= ")";
1277 if ($function->signature->type eq "void") {
1278 push(@implContent, $indent . "$functionString;\n");
1279 push(@implContent, $indent . "setDOMException(exec, ec);\n") if @
{$function->raisesExceptions};
1282 push(@implContent, $indent . "wrapper->commitChange(exec, imp);\n\n");
1283 push(@implContent, $indent . "if (castedThisObj->context())\n");
1284 push(@implContent, $indent . " castedThisObj->context()->notifyAttributeChange();\n");
1287 push(@implContent, $indent . "return jsUndefined();\n");
1289 push(@implContent, "\n" . $indent . "KJS::JSValue* result = " . NativeToJSValue
($function->signature, 1, $implClassName, "", $functionString) . ";\n");
1290 push(@implContent, $indent . "setDOMException(exec, ec);\n") if @
{$function->raisesExceptions};
1293 push(@implContent, $indent . "wrapper->commitChange(exec, imp);\n\n");
1294 push(@implContent, $indent . "if (castedThisObj->context())\n");
1295 push(@implContent, $indent . " castedThisObj->context()->notifyAttributeChange();\n");
1298 push(@implContent, $indent . "return result;\n");
1302 sub GetNativeTypeFromSignature
1304 my $signature = shift;
1305 my $type = $codeGenerator->StripModule($signature->type);
1307 if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) {
1308 # Special-case index arguments because we need to check that they aren't < 0.
1312 return GetNativeType
($type);
1319 return "unsigned" if $type eq "unsigned long";
1320 return $type if $type eq "unsigned short" or $type eq "float" or $type eq "double" or $type eq "AtomicString";
1321 return "bool" if $type eq "boolean";
1322 return "int" if $type eq "long";
1323 return "String" if $type eq "DOMString";
1324 return "Range::CompareHow" if $type eq "CompareHow";
1325 return "EventTargetNode*" if $type eq "EventTarget";
1326 return "FloatRect" if $type eq "SVGRect";
1327 return "FloatPoint" if $type eq "SVGPoint";
1328 return "AffineTransform" if $type eq "SVGMatrix";
1329 return "SVGTransform" if $type eq "SVGTransform";
1330 return "SVGLength" if $type eq "SVGLength";
1331 return "float" if $type eq "SVGNumber";
1332 return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType";
1334 # Default, assume native type is a pointer with same type name as idl type
1338 sub TypeCanFailConversion
1340 my $signature = shift;
1342 my $type = $codeGenerator->StripModule($signature->type);
1344 # FIXME: convert to use a hash
1346 return 0 if $type eq "boolean" or
1348 $type eq "double" or
1349 $type eq "AtomicString" or
1350 $type eq "DOMString" or
1352 $type eq "Element" or
1353 $type eq "DocumentType" or
1355 $type eq "EventListener" or
1356 $type eq "EventTarget" or
1358 $type eq "NodeFilter" or
1359 $type eq "DOMWindow" or
1360 $type eq "SQLResultSet" or
1361 $type eq "XPathEvaluator" or
1362 $type eq "XPathNSResolver" or
1363 $type eq "XPathResult" or
1364 $type eq "SVGAngle" or
1365 $type eq "SVGLength" or
1366 $type eq "SVGNumber" or
1367 $type eq "SVGPoint" or
1368 $type eq "SVGTransform" or
1369 $type eq "SVGPathSeg" or
1370 $type eq "SVGMatrix" or
1371 $type eq "SVGRect" or
1372 $type eq "SVGElement" or
1373 $type eq "HTMLElement" or
1374 $type eq "HTMLOptionElement" or
1375 $type eq "unsigned short" or # or can it?
1376 $type eq "CompareHow" or # or can it?
1377 $type eq "SVGPaintType" or # or can it?
1378 $type eq "VoidCallback";
1380 if ($type eq "unsigned long" or $type eq "long" or $type eq "Attr") {
1381 $implIncludes{"ExceptionCode.h"} = 1;
1385 die "Don't know whether a JS value can fail conversion to type $type."
1390 my $signature = shift;
1392 my $okParam = shift;
1393 my $maybeOkParam = $okParam ?
", ${okParam}" : "";
1395 my $type = $codeGenerator->StripModule($signature->type);
1397 return "$value->toBoolean(exec)" if $type eq "boolean";
1398 return "$value->toNumber(exec)" if $type eq "double";
1399 return "$value->toFloat(exec)" if $type eq "float" or $type eq "SVGNumber";
1400 return "$value->toInt32(exec${maybeOkParam})" if $type eq "unsigned long" or $type eq "long" or $type eq "unsigned short";
1402 return "static_cast<Range::CompareHow>($value->toInt32(exec))" if $type eq "CompareHow";
1403 return "static_cast<SVGPaint::SVGPaintType>($value->toInt32(exec))" if $type eq "SVGPaintType";
1405 return "$value->toString(exec)" if $type eq "AtomicString";
1406 if ($type eq "DOMString") {
1407 return "valueToStringWithNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertNullToNullString"};
1408 return "valueToStringWithUndefinedOrNullCheck(exec, $value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"};
1409 return "$value->toString(exec).domString()";
1412 if ($type eq "EventTarget") {
1413 $implIncludes{"JSEventTargetNode.h"} = 1;
1414 return "toEventTargetNode($value)";
1417 if ($type eq "Attr") {
1418 $implIncludes{"kjs_dom.h"} = 1;
1419 return "toAttr($value${maybeOkParam})";
1422 if ($type eq "SVGRect") {
1423 $implIncludes{"FloatRect.h"} = 1;
1426 if ($type eq "SVGPoint") {
1427 $implIncludes{"FloatPoint.h"} = 1;
1430 if ($type eq "VoidCallback") {
1431 $implIncludes{"VoidCallback.h"} = 1;
1432 return "toVoidCallback($value)";
1435 # Default, assume autogenerated type conversion routines
1436 $implIncludes{"JS$type.h"} = 1;
1437 return "to$type($value)";
1442 my $signature = shift;
1443 my $inFunctionCall = shift;
1444 my $implClassName = shift;
1445 my $implClassNameForValueConversion = shift;
1448 my $type = $codeGenerator->StripModule($signature->type);
1450 return "jsBoolean($value)" if $type eq "boolean";
1451 return "jsNumber($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType" or $type eq "DOMTimeStamp";
1453 if ($codeGenerator->IsStringType($type)) {
1454 # TODO $implIncludes{"PlatformString.h"} = 1;
1455 my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1456 if (defined $conv) {
1457 return "jsStringOrNull($value)" if $conv eq "Null";
1458 return "jsStringOrUndefined($value)" if $conv eq "Undefined";
1459 return "jsStringOrFalse($value)" if $conv eq "False";
1461 die "Unknown value for ConvertNullStringTo extended attribute";
1463 return "jsString($value)";
1466 if ($type eq "RGBColor") {
1467 $implIncludes{"kjs_css.h"} = 1;
1468 return "getJSRGBColor(exec, $value)";
1471 if ($codeGenerator->IsPodType($type)) {
1472 $implIncludes{"JS$type.h"} = 1;
1474 my $nativeType = GetNativeType
($type);
1476 my $getter = $value;
1477 $getter =~ s/imp->//;
1478 $getter =~ s/\(\)//;
1480 my $setter = "set" . WK_ucfirst
($getter);
1482 if ($implClassNameForValueConversion eq "") {
1483 if (IsSVGTypeNeedingContextParameter
($implClassName)) {
1484 return "toJS(exec, new JSSVGPODTypeWrapperCreatorReadOnly<$nativeType>($value), castedThisObj->context())" if $inFunctionCall eq 1;
1486 # Special case: SVGZoomEvent - it doesn't have a context, but it's no problem, as there are no readwrite props
1487 return "toJS(exec, new JSSVGPODTypeWrapperCreatorReadOnly<$nativeType>($value), 0)" if $implClassName eq "SVGZoomEvent";
1488 return "toJS(exec, new JSSVGPODTypeWrapperCreatorReadOnly<$nativeType>($value), context())";
1490 return "toJS(exec, new JSSVGPODTypeWrapperCreatorReadOnly<$nativeType>($value), imp)";
1492 } else { # These classes, always have a m_context pointer!
1493 return "toJS(exec, JSSVGPODTypeWrapperCache<$nativeType, $implClassNameForValueConversion>::lookupOrCreateWrapper(imp, &${implClassNameForValueConversion}::$getter, &${implClassNameForValueConversion}::$setter), context())";
1497 if ($codeGenerator->IsSVGAnimatedType($type)) {
1499 $value .= "Animated()";
1502 if ($type eq "CSSStyleDeclaration") {
1503 $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
1506 if ($type eq "NamedNodeMap") {
1507 $implIncludes{"NamedAttrMap.h"} = 1;
1510 if ($type eq "NodeList") {
1511 $implIncludes{"NameNodeList.h"} = 1;
1514 if ($type eq "EventTarget") {
1515 $implIncludes{"EventTargetNode.h"} = 1;
1516 $implIncludes{"JSEventTargetNode.h"} = 1;
1517 $implIncludes{"kjs_dom.h"} = 1;
1518 } elsif ($type eq "DOMWindow") {
1519 $implIncludes{"kjs_window.h"} = 1;
1520 } elsif ($type eq "DOMObject") {
1521 $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
1522 } elsif ($type eq "Clipboard") {
1523 $implIncludes{"kjs_events.h"} = 1;
1524 $implIncludes{"Clipboard.h"} = 1;
1525 } elsif ($type =~ /SVGPathSeg/) {
1526 $implIncludes{"JS$type.h"} = 1;
1527 $joinedName = $type;
1528 $joinedName =~ s/Abs|Rel//;
1529 $implIncludes{"$joinedName.h"} = 1;
1531 # Default, include header with same name.
1532 $implIncludes{"JS$type.h"} = 1;
1533 $implIncludes{"$type.h"} = 1;
1536 return $value if $codeGenerator->IsSVGAnimatedType($type);
1538 if (IsSVGTypeNeedingContextParameter
($type)) {
1539 if (IsSVGTypeNeedingContextParameter
($implClassName)) {
1540 if ($inFunctionCall eq 1) {
1541 return "toJS(exec, WTF::getPtr($value), castedThisObj->context())";
1543 return "toJS(exec, WTF::getPtr($value), context())";
1546 return "toJS(exec, WTF::getPtr($value), imp)";
1550 return "toJS(exec, WTF::getPtr($value))";
1553 sub ceilingToPowerOf2
1558 while ($size > $powerOf2) {
1566 sub GenerateHashTable
1574 my $specials = shift;
1575 my $parameters = shift;
1581 $size = ceilingToPowerOf2
($size * 2);
1585 my $numEntries = $size;
1587 # Collect hashtable information
1589 foreach (@
{$keys}) {
1591 my $h = $object->GenerateHashValue($_) % $numEntries;
1593 while (defined($table[$h])) {
1594 if (defined($links[$h])) {
1608 $maxDepth = $depth if ($depth > $maxDepth);
1611 # Ensure table is big enough (in case of undef entries at the end)
1612 if ($#table + 1 < $size) {
1613 $#table = $size - 1;
1616 # Start outputing the hashtables
1617 my $nameEntries = "${name}Entries";
1618 $nameEntries =~ s/:/_/g;
1620 if (($name =~ /Prototype/) or ($name =~ /Constructor/)) {
1624 if ($name =~ /Prototype/) {
1625 $type =~ s/Prototype.*//;
1626 $implClass = $type; $implClass =~ s/Wrapper$//;
1627 push(@implContent, "/* Hash table for prototype */\n");
1629 $type =~ s/Constructor.*//;
1630 $implClass = $type; $implClass =~ s/Constructor$//;
1631 push(@implContent, "/* Hash table for constructor */\n");
1634 push(@implContent, "/* Hash table */\n");
1637 # Dump the hash table
1638 push(@implContent, "\nstatic const HashEntry $nameEntries\[\] =\n\{\n");
1641 foreach $entry (@table) {
1642 if (defined($entry)) {
1643 my $key = @
$keys[$entry];
1645 push(@implContent, " \{ \"" . $key . "\"");
1646 push(@implContent, ", " . @
$values[$entry]);
1647 push(@implContent, ", " . @
$specials[$entry]);
1648 push(@implContent, ", " . @
$parameters[$entry]);
1649 push(@implContent, ", ");
1651 if (defined($links[$i])) {
1652 push(@implContent, "&" . $nameEntries . "[$links[$i]]" . " \}");
1654 push(@implContent, "0 \}");
1657 push(@implContent, " { 0, 0, 0, 0, 0 }");
1660 push(@implContent, ",") unless($i eq $size - 1);
1661 push(@implContent, "\n");
1666 # my $sizeMask = $numEntries - 1;
1667 my $sizeMask = $numEntries;
1669 push(@implContent, "};\n\n");
1670 push(@implContent, "static const HashTable $name = \n");
1671 push(@implContent, "{\n 2, $size, $nameEntries, $sizeMask\n};\n\n");
1675 sub GenerateHashValue
1679 @chars = split(/ */, $_[0]);
1681 # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1682 # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1683 # were 16-bit chunks, which should give matching results
1685 my $EXP2_32 = 4294967296;
1687 my $hash = 0x9e3779b9;
1688 my $l = scalar @chars; #I wish this was in Ruby --- Maks
1695 for (; $l > 0; $l--) {
1696 $hash += ord($chars[$s]);
1697 my $tmp = leftShift
(ord($chars[$s+1]), 11) ^ $hash;
1698 $hash = (leftShift
($hash, 16)% $EXP2_32) ^ $tmp;
1700 $hash += $hash >> 11;
1706 $hash += ord($chars[$s]);
1707 $hash ^= (leftShift
($hash, 11)% $EXP2_32);
1708 $hash += $hash >> 17;
1711 # Force "avalanching" of final 127 bits
1712 $hash ^= leftShift
($hash, 3);
1713 $hash += ($hash >> 5);
1714 $hash = ($hash% $EXP2_32);
1715 $hash ^= (leftShift
($hash, 2)% $EXP2_32);
1716 $hash += ($hash >> 15);
1717 $hash = $hash% $EXP2_32;
1718 $hash ^= (leftShift
($hash, 10)% $EXP2_32);
1720 # this avoids ever returning a hash code of 0, since that is used to
1721 # signal "hash not computed yet", using a value that is likely to be
1722 # effectively the same as 0 when the low bits are masked
1723 $hash = 0x80000000 if ($hash == 0);
1731 if (defined($IMPL)) {
1732 # Write content to file.
1733 print $IMPL @implContentHeader;
1735 foreach my $implInclude (sort keys(%implIncludes)) {
1736 my $checkType = $implInclude;
1737 $checkType =~ s/\.h//;
1739 print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType);
1742 print $IMPL @implContent;
1746 @implHeaderContent = ();
1751 if (defined($HEADER)) {
1752 # Write content to file.
1753 print $HEADER @headerContent;
1757 @headerContent = ();
1763 my $className = shift;
1764 my $protoClassName = shift;
1765 my $interfaceName = shift;
1766 my $canConstruct = shift;
1768 my $implContent = << "EOF";
1769 class ${className
}Constructor
: public DOMObject
{
1771 ${className
}Constructor
(ExecState
* exec)
1773 setPrototype
(exec->lexicalInterpreter()->builtinObjectPrototype());
1774 putDirect
(exec->propertyNames().prototype, ${protoClassName
}::self
(exec), None
);
1776 virtual bool getOwnPropertySlot
(ExecState
*, const Identifier
&, PropertySlot
&);
1777 JSValue
* getValueProperty
(ExecState
*, int token
) const
;
1778 virtual const ClassInfo
* classInfo
() const
{ return &s_info
; }
1779 static const ClassInfo s_info
;
1781 virtual bool implementsHasInstance
() const
{ return true
; }
1784 if ($canConstruct) {
1785 $implContent .= << "EOF";
1786 virtual bool implementsConstruct
() const
{ return true
; }
1787 virtual JSObject
* construct
(ExecState
* exec, const List
& args
) { return static_cast
<JSObject
*>(toJS
(exec, new
$interfaceName)); }
1791 $implContent .= << "EOF";
1794 const ClassInfo
${className
}Constructor
::s_info
= { "${interfaceName}Constructor", 0, &${className
}ConstructorTable
, 0 };
1796 bool
${className
}Constructor
::getOwnPropertySlot
(ExecState
* exec, const Identifier
& propertyName
, PropertySlot
& slot
)
1798 return getStaticValueSlot
<${className
}Constructor
, DOMObject
>(exec, &${className
}ConstructorTable
, this
, propertyName
, slot
);
1801 JSValue
* ${className
}Constructor
::getValueProperty
(ExecState
*, int token
) const
1803 // The token is the numeric value of its associated constant
1804 return jsNumber
(token
);
1809 return $implContent;
1812 sub prototypeFunctionFor
1814 my $className = shift;
1816 my $implContent = << "EOF";
1817 class ${className
}PrototypeFunction
: public KJS
::InternalFunctionImp
{
1819 ${className
}PrototypeFunction
(KJS
::ExecState
* exec, int i
, int len
, const KJS
::Identifier
& name
)
1820 : KJS
::InternalFunctionImp
(static_cast
<KJS
::FunctionPrototype
*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name
)
1823 put
(exec, exec->propertyNames().length, KJS
::jsNumber
(len
), KJS
::DontDelete
|KJS
::ReadOnly
|KJS
::DontEnum
);
1825 virtual KJS
::JSValue
* callAsFunction
(KJS
::ExecState
*, KJS
::JSObject
*, const KJS
::List
&);
1833 return $implContent;