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