1 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann (at] kde.org> 2 # Copyright (C) 2006 Anders Carlsson <andersca (at] mac.com> 3 # Copyright (C) 2006 Samuel Weinig <sam.weinig (at] gmail.com> 4 # Copyright (C) 2006 Alexey Proskuryakov <ap (at] webkit.org> 5 # Copyright (C) 2006 Apple Computer, Inc. 6 # Copyright (C) 2007, 2008, 2009 Google Inc. 7 # Copyright (C) 2009 Cameron McCormack <cam (at] mcc.id.au> 8 # Copyright (C) Research In Motion Limited 2010. All rights reserved. 9 # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 # 11 # This library is free software; you can redistribute it and/or 12 # modify it under the terms of the GNU Library General Public 13 # License as published by the Free Software Foundation; either 14 # version 2 of the License, or (at your option) any later version. 15 # 16 # This library is distributed in the hope that it will be useful, 17 # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 # Library General Public License for more details. 20 # 21 # You should have received a copy of the GNU Library General Public License 22 # along with this library; see the file COPYING.LIB. If not, write to 23 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 24 # Boston, MA 02111-1307, USA. 25 # 26 27 package CodeGeneratorV8; 28 29 use Digest::MD5; 30 31 my $module = ""; 32 my $outputDir = ""; 33 my $outputHeadersDir = ""; 34 35 my @headerContent = (); 36 my @implContentHeader = (); 37 my @implFixedHeader = (); 38 my @implContent = (); 39 my @implContentDecls = (); 40 my %implIncludes = (); 41 my %headerIncludes = (); 42 43 my @allParents = (); 44 45 # Default .h template 46 my $headerTemplate = << "EOF"; 47 /* 48 This file is part of the WebKit open source project. 49 This file has been generated by generate-bindings.pl. DO NOT MODIFY! 50 51 This library is free software; you can redistribute it and/or 52 modify it under the terms of the GNU Library General Public 53 License as published by the Free Software Foundation; either 54 version 2 of the License, or (at your option) any later version. 55 56 This library is distributed in the hope that it will be useful, 57 but WITHOUT ANY WARRANTY; without even the implied warranty of 58 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 59 Library General Public License for more details. 60 61 You should have received a copy of the GNU Library General Public License 62 along with this library; see the file COPYING.LIB. If not, write to 63 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 64 Boston, MA 02111-1307, USA. 65 */ 66 EOF 67 68 # Default constructor 69 sub new 70 { 71 my $object = shift; 72 my $reference = { }; 73 74 $codeGenerator = shift; 75 $outputDir = shift; 76 $outputHeadersDir = shift; 77 78 bless($reference, $object); 79 return $reference; 80 } 81 82 sub finish 83 { 84 my $object = shift; 85 86 # Commit changes! 87 $object->WriteData(); 88 } 89 90 # Params: 'domClass' struct 91 sub GenerateInterface 92 { 93 my $object = shift; 94 my $dataNode = shift; 95 my $defines = shift; 96 97 # Start actual generation 98 if ($dataNode->extendedAttributes->{"Callback"}) { 99 $object->GenerateCallbackHeader($dataNode); 100 $object->GenerateCallbackImplementation($dataNode); 101 } else { 102 $object->GenerateHeader($dataNode); 103 $object->GenerateImplementation($dataNode); 104 } 105 106 my $name = $dataNode->name; 107 108 # Open files for writing 109 my $headerFileName = "$outputHeadersDir/V8$name.h"; 110 my $implFileName = "$outputDir/V8$name.cpp"; 111 112 open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName"; 113 open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName"; 114 } 115 116 # Params: 'idlDocument' struct 117 sub GenerateModule 118 { 119 my $object = shift; 120 my $dataNode = shift; 121 122 $module = $dataNode->module; 123 } 124 125 sub AddIncludesForType 126 { 127 my $type = $codeGenerator->StripModule(shift); 128 129 # When we're finished with the one-file-per-class 130 # reorganization, we won't need these special cases. 131 if (!$codeGenerator->IsPrimitiveType($type) and !$codeGenerator->IsStringType($type) and !$codeGenerator->AvoidInclusionOfType($type) and $type ne "Date") { 132 # default, include the same named file 133 $implIncludes{GetV8HeaderName(${type})} = 1; 134 135 if ($type =~ /SVGPathSeg/) { 136 $joinedName = $type; 137 $joinedName =~ s/Abs|Rel//; 138 $implIncludes{"${joinedName}.h"} = 1; 139 } 140 } 141 142 # additional includes (things needed to compile the bindings but not the header) 143 144 if ($type eq "CanvasRenderingContext2D") { 145 $implIncludes{"CanvasGradient.h"} = 1; 146 $implIncludes{"CanvasPattern.h"} = 1; 147 $implIncludes{"CanvasStyle.h"} = 1; 148 } 149 150 if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") { 151 $implIncludes{"PlatformString.h"} = 1; 152 } 153 154 if ($type eq "CSSStyleDeclaration") { 155 $implIncludes{"CSSMutableStyleDeclaration.h"} = 1; 156 } 157 158 if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") { 159 # So we can get String -> AtomicString conversion for namedItem(). 160 $implIncludes{"wtf/text/AtomicString.h"} = 1; 161 } 162 } 163 164 # If the node has a [Conditional=XXX] attribute, returns an "ENABLE(XXX)" string for use in an #if. 165 sub GenerateConditionalString 166 { 167 my $node = shift; 168 my $conditional = $node->extendedAttributes->{"Conditional"}; 169 if ($conditional) { 170 if ($conditional =~ /&/) { 171 return "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; 172 } elsif ($conditional =~ /\|/) { 173 return "ENABLE(" . join(") || ENABLE(", split(/\|/, $conditional)) . ")"; 174 } else { 175 return "ENABLE(" . $conditional . ")"; 176 } 177 } else { 178 return ""; 179 } 180 } 181 182 sub GetSVGPropertyTypes 183 { 184 my $implType = shift; 185 186 my $svgPropertyType; 187 my $svgListPropertyType; 188 my $svgNativeType; 189 190 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/; 191 192 $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implType); 193 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType; 194 195 # Append space to avoid compilation errors when using PassRefPtr<$svgNativeType> 196 $svgNativeType = "$svgNativeType "; 197 198 my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implType); 199 if ($svgNativeType =~ /SVGPropertyTearOff/) { 200 $svgPropertyType = $svgWrappedNativeType; 201 $implIncludes{"SVGAnimatedPropertyTearOff.h"} = 1; 202 } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/) { 203 $svgListPropertyType = $svgWrappedNativeType; 204 $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; 205 $headerIncludes{"SVGStaticListPropertyTearOff.h"} = 1; 206 } elsif ($svgNativeType =~ /SVGTransformListPropertyTearOff/) { 207 $svgListPropertyType = $svgWrappedNativeType; 208 $headerIncludes{"SVGAnimatedListPropertyTearOff.h"} = 1; 209 $headerIncludes{"SVGTransformListPropertyTearOff.h"} = 1; 210 } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) { 211 $svgListPropertyType = $svgWrappedNativeType; 212 $headerIncludes{"SVGPathSegListPropertyTearOff.h"} = 1; 213 } 214 215 if ($svgPropertyType) { 216 $svgPropertyType = "SVGPoint" if $svgPropertyType eq "FloatPoint"; 217 } 218 219 return ($svgPropertyType, $svgListPropertyType, $svgNativeType); 220 } 221 222 sub GenerateHeader 223 { 224 my $object = shift; 225 my $dataNode = shift; 226 227 my $interfaceName = $dataNode->name; 228 my $className = "V8$interfaceName"; 229 my $implClassName = $interfaceName; 230 231 # Copy contents of parent classes except the first parent or if it is 232 # EventTarget. 233 $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode, \@allParents, 1); 234 235 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; 236 237 # - Add default header template 238 push(@headerContent, GenerateHeaderContentHeader($dataNode)); 239 240 $headerIncludes{"wtf/text/StringHash.h"} = 1; 241 $headerIncludes{"WrapperTypeInfo.h"} = 1; 242 $headerIncludes{"V8DOMWrapper.h"} = 1; 243 244 my $headerClassInclude = GetHeaderClassInclude($implClassName); 245 $headerIncludes{$headerClassInclude} = 1 if $headerClassInclude ne ""; 246 247 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName); 248 249 foreach my $headerInclude (sort keys(%headerIncludes)) { 250 if ($headerInclude =~ /wtf/) { 251 push(@headerContent, "#include \<${headerInclude}\>\n"); 252 } else { 253 push(@headerContent, "#include \"${headerInclude}\"\n"); 254 } 255 } 256 257 push(@headerContent, "#include <v8.h>\n"); 258 push(@headerContent, "#include <wtf/HashMap.h>\n"); 259 260 push(@headerContent, "\nnamespace WebCore {\n"); 261 push(@headerContent, "\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType; 262 if ($svgNativeType) { 263 if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) { 264 push(@headerContent, "\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n"); 265 } else { 266 push(@headerContent, "\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n"); 267 } 268 } 269 push(@headerContent, "\nclass FloatRect;\n") if $svgPropertyType && $svgPropertyType eq "FloatRect"; 270 push(@headerContent, "\nclass $className {\n"); 271 272 my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName); 273 my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName); 274 my $forceNewObjectParameter = IsDOMNodeType($interfaceName) ? ", bool forceNewObject = false" : ""; 275 my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : ""; 276 my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : ""; 277 278 push(@headerContent, <<END); 279 280 public: 281 static bool HasInstance(v8::Handle<v8::Value> value); 282 static v8::Persistent<v8::FunctionTemplate> GetRawTemplate(); 283 static v8::Persistent<v8::FunctionTemplate> GetTemplate(); 284 static ${nativeType}* toNative(v8::Handle<v8::Object> object) 285 { 286 return reinterpret_cast<${nativeType}*>(object->GetPointerFromInternalField(v8DOMWrapperObjectIndex)); 287 } 288 inline static v8::Handle<v8::Object> wrap(${nativeType}*${forceNewObjectParameter}); 289 static void derefObject(void*); 290 static WrapperTypeInfo info; 291 END 292 if (IsActiveDomType($implClassName)) { 293 push(@headerContent, " static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n"); 294 } 295 296 if ($implClassName eq "DOMWindow") { 297 push(@headerContent, <<END); 298 static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate(); 299 END 300 } 301 302 if ($implClassName eq "HTMLDocument") { 303 push(@headerContent, <<END); 304 static v8::Local<v8::Object> WrapInShadowObject(v8::Local<v8::Object> wrapper, Node* impl); 305 static v8::Handle<v8::Value> GetNamedProperty(HTMLDocument* htmlDocument, const AtomicString& key); 306 END 307 } 308 309 my @enabledAtRuntime; 310 foreach my $function (@{$dataNode->functions}) { 311 my $name = $function->signature->name; 312 my $attrExt = $function->signature->extendedAttributes; 313 314 if ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { 315 push(@headerContent, <<END); 316 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments&); 317 END 318 } 319 320 if ($attrExt->{"EnabledAtRuntime"}) { 321 push(@enabledAtRuntime, $function); 322 } 323 } 324 325 if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) { 326 push(@headerContent, <<END); 327 static v8::Handle<v8::Value> constructorCallback(const v8::Arguments& args); 328 END 329 } 330 331 foreach my $attribute (@{$dataNode->attributes}) { 332 my $name = $attribute->signature->name; 333 my $attrExt = $attribute->signature->extendedAttributes; 334 if ($attrExt->{"V8CustomGetter"} || $attrExt->{"CustomGetter"} 335 || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) { 336 push(@headerContent, <<END); 337 static v8::Handle<v8::Value> ${name}AccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info); 338 END 339 } 340 if ($attrExt->{"V8CustomSetter"} || $attrExt->{"CustomSetter"} 341 || $attrExt->{"V8Custom"} || $attrExt->{"Custom"}) { 342 push(@headerContent, <<END); 343 static void ${name}AccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info); 344 END 345 } 346 if ($attrExt->{"EnabledAtRuntime"}) { 347 push(@enabledAtRuntime, $attribute); 348 } 349 } 350 351 GenerateHeaderNamedAndIndexedPropertyAccessors($dataNode); 352 GenerateHeaderCustomCall($dataNode); 353 GenerateHeaderCustomInternalFieldIndices($dataNode); 354 355 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"}) { 356 push(@headerContent, <<END); 357 static bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data); 358 static bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data); 359 END 360 } 361 362 push(@headerContent, <<END); 363 private: 364 static v8::Handle<v8::Object> wrapSlow(${nativeType}*); 365 }; 366 367 END 368 369 push(@headerContent, <<END); 370 371 v8::Handle<v8::Object> ${className}::wrap(${nativeType}* impl${forceNewObjectInput}) 372 { 373 END 374 push(@headerContent, " if (!forceNewObject) {\n") if IsDOMNodeType($interfaceName); 375 my $getWrapper = IsNodeSubType($dataNode) ? "V8DOMWrapper::getWrapper(impl)" : "${domMapFunction}.get(impl)"; 376 push(@headerContent, <<END); 377 v8::Handle<v8::Object> wrapper = ${getWrapper}; 378 if (!wrapper.IsEmpty()) 379 return wrapper; 380 END 381 push(@headerContent, " }\n") if IsDOMNodeType($interfaceName); 382 push(@headerContent, <<END); 383 return ${className}::wrapSlow(impl); 384 } 385 END 386 387 if (!HasCustomToV8Implementation($dataNode, $interfaceName)) { 388 push(@headerContent, <<END); 389 390 inline v8::Handle<v8::Value> toV8(${nativeType}* impl${forceNewObjectParameter}) 391 { 392 if (!impl) 393 return v8::Null(); 394 return ${className}::wrap(impl${forceNewObjectCall}); 395 } 396 END 397 } elsif ($interfaceName ne 'Node') { 398 push(@headerContent, <<END); 399 400 v8::Handle<v8::Value> toV8(${nativeType}*${forceNewObjectParameter}); 401 END 402 } else { 403 push(@headerContent, <<END); 404 405 v8::Handle<v8::Value> toV8Slow(Node*, bool); 406 407 inline v8::Handle<v8::Value> toV8(Node* impl, bool forceNewObject = false) 408 { 409 if (!impl) 410 return v8::Null(); 411 if (!forceNewObject) { 412 v8::Handle<v8::Value> wrapper = V8DOMWrapper::getWrapper(impl); 413 if (!wrapper.IsEmpty()) 414 return wrapper; 415 } 416 return toV8Slow(impl, forceNewObject); 417 } 418 END 419 } 420 421 if (IsRefPtrType($implClassName)) { 422 push(@headerContent, <<END); 423 inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl${forceNewObjectParameter}) 424 { 425 return toV8(impl.get()${forceNewObjectCall}); 426 } 427 END 428 } 429 430 push(@headerContent, "}\n\n"); 431 push(@headerContent, "#endif // $className" . "_h\n"); 432 433 my $conditionalString = GenerateConditionalString($dataNode); 434 push(@headerContent, "#endif // ${conditionalString}\n\n") if $conditionalString; 435 } 436 437 sub GetInternalFields 438 { 439 my $dataNode = shift; 440 my $name = $dataNode->name; 441 442 my @customInternalFields = (); 443 444 # We can't ask whether a parent type has a given extendedAttribute, so special-case Node, AbstractWorker and WorkerContext to include all sub-types. 445 # FIXME: SVGElementInstance should probably have the EventTarget extended attribute, but doesn't. 446 if ($dataNode->extendedAttributes->{"EventTarget"} || IsNodeSubType($dataNode) || IsSubType($dataNode, "AbstractWorker") || IsSubType($dataNode, "WorkerContext") 447 || $name eq "SVGElementInstance") { 448 push(@customInternalFields, "eventListenerCacheIndex"); 449 } 450 451 if ($name eq "DOMWindow") { 452 push(@customInternalFields, "enteredIsolatedWorldIndex"); 453 } 454 return @customInternalFields; 455 } 456 457 sub GetHeaderClassInclude 458 { 459 my $className = shift; 460 if ($className =~ /SVGPathSeg/) { 461 $className =~ s/Abs|Rel//; 462 } 463 return "" if ($codeGenerator->AvoidInclusionOfType($className)); 464 return "${className}.h"; 465 } 466 467 sub GenerateHeaderCustomInternalFieldIndices 468 { 469 my $dataNode = shift; 470 my @customInternalFields = GetInternalFields($dataNode); 471 my $customFieldCounter = 0; 472 foreach my $customInternalField (@customInternalFields) { 473 push(@headerContent, <<END); 474 static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; 475 END 476 $customFieldCounter++; 477 } 478 push(@headerContent, <<END); 479 static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; 480 END 481 } 482 483 my %indexerSpecialCases = ( 484 "Storage" => 1, 485 "HTMLAppletElement" => 1, 486 "HTMLEmbedElement" => 1, 487 "HTMLObjectElement" => 1 488 ); 489 490 sub GenerateHeaderNamedAndIndexedPropertyAccessors 491 { 492 my $dataNode = shift; 493 my $interfaceName = $dataNode->name; 494 my $hasCustomIndexedGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; 495 my $hasCustomIndexedSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"}; 496 my $hasCustomNamedGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; 497 my $hasCustomNamedSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"}; 498 my $hasCustomDeleters = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; 499 my $hasCustomEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"}; 500 if ($interfaceName eq "HTMLOptionsCollection") { 501 $interfaceName = "HTMLCollection"; 502 $hasCustomIndexedGetter = 1; 503 $hasCustomNamedGetter = 1; 504 } 505 if ($interfaceName eq "DOMWindow") { 506 $hasCustomDeleterr = 0; 507 $hasEnumerator = 0; 508 } 509 if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") { 510 $hasCustomNamedGetter = 1; 511 } 512 if ($interfaceName eq "HTMLDocument") { 513 $hasCustomNamedGetter = 0; 514 $hasCustomIndexedGetter = 0; 515 } 516 my $isIndexerSpecialCase = exists $indexerSpecialCases{$interfaceName}; 517 518 if ($hasCustomIndexedGetter || $isIndexerSpecialCase) { 519 push(@headerContent, <<END); 520 static v8::Handle<v8::Value> indexedPropertyGetter(uint32_t, const v8::AccessorInfo&); 521 END 522 } 523 524 if ($isIndexerSpecialCase || $hasCustomIndexedSetter) { 525 push(@headerContent, <<END); 526 static v8::Handle<v8::Value> indexedPropertySetter(uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo&); 527 END 528 } 529 if ($hasCustomDeleters) { 530 push(@headerContent, <<END); 531 static v8::Handle<v8::Boolean> indexedPropertyDeleter(uint32_t, const v8::AccessorInfo&); 532 END 533 } 534 if ($hasCustomNamedGetter) { 535 push(@headerContent, <<END); 536 static v8::Handle<v8::Value> namedPropertyGetter(v8::Local<v8::String>, const v8::AccessorInfo&); 537 END 538 } 539 if ($hasCustomNamedSetter) { 540 push(@headerContent, <<END); 541 static v8::Handle<v8::Value> namedPropertySetter(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo&); 542 END 543 } 544 if ($hasCustomDeleters) { 545 push(@headerContent, <<END); 546 static v8::Handle<v8::Boolean> namedPropertyDeleter(v8::Local<v8::String>, const v8::AccessorInfo&); 547 END 548 } 549 if ($hasCustomEnumerator) { 550 push(@headerContent, <<END); 551 static v8::Handle<v8::Array> namedPropertyEnumerator(const v8::AccessorInfo&); 552 static v8::Handle<v8::Integer> namedPropertyQuery(v8::Local<v8::String>, const v8::AccessorInfo&); 553 END 554 } 555 } 556 557 sub GenerateHeaderCustomCall 558 { 559 my $dataNode = shift; 560 561 if ($dataNode->extendedAttributes->{"CustomCall"}) { 562 push(@headerContent, " static v8::Handle<v8::Value> callAsFunctionCallback(const v8::Arguments&);\n"); 563 } 564 if ($dataNode->name eq "Event") { 565 push(@headerContent, " static v8::Handle<v8::Value> dataTransferAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); 566 push(@headerContent, " static void valueAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info);\n"); 567 } 568 if ($dataNode->name eq "Location") { 569 push(@headerContent, " static v8::Handle<v8::Value> assignAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); 570 push(@headerContent, " static v8::Handle<v8::Value> reloadAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); 571 push(@headerContent, " static v8::Handle<v8::Value> replaceAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info);\n"); 572 } 573 } 574 575 sub GenerateSetDOMException 576 { 577 my $indent = shift; 578 my $result = ""; 579 580 $result .= $indent . "if (UNLIKELY(ec)) {\n"; 581 $result .= $indent . " V8Proxy::setDOMException(ec);\n"; 582 $result .= $indent . " return v8::Handle<v8::Value>();\n"; 583 $result .= $indent . "}\n"; 584 585 return $result; 586 } 587 588 sub IsSubType 589 { 590 my $dataNode = shift; 591 my $parentType = shift; 592 return 1 if ($dataNode->name eq $parentType); 593 foreach (@allParents) { 594 my $parent = $codeGenerator->StripModule($_); 595 return 1 if $parent eq $parentType; 596 } 597 return 0; 598 } 599 600 sub IsNodeSubType 601 { 602 my $dataNode = shift; 603 return IsSubType($dataNode, "Node"); 604 } 605 606 sub GenerateDomainSafeFunctionGetter 607 { 608 my $function = shift; 609 my $implClassName = shift; 610 611 my $className = "V8" . $implClassName; 612 my $funcName = $function->signature->name; 613 614 my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())"; 615 if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) { 616 $signature = "v8::Local<v8::Signature>()"; 617 } 618 619 my $newTemplateString = GenerateNewFunctionTemplate($function, $implClassName, $signature); 620 621 push(@implContentDecls, <<END); 622 static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 623 { 624 INC_STATS(\"DOM.$implClassName.$funcName._get\"); 625 static v8::Persistent<v8::FunctionTemplate> privateTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); 626 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(${className}::GetTemplate(), info.This()); 627 if (holder.IsEmpty()) { 628 // can only reach here by 'object.__proto__.func', and it should passed 629 // domain security check already 630 return privateTemplate->GetFunction(); 631 } 632 ${implClassName}* imp = ${className}::toNative(holder); 633 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), false)) { 634 static v8::Persistent<v8::FunctionTemplate> sharedTemplate = v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); 635 return sharedTemplate->GetFunction(); 636 } 637 return privateTemplate->GetFunction(); 638 } 639 640 END 641 } 642 643 sub GenerateConstructorGetter 644 { 645 my $implClassName = shift; 646 647 push(@implContentDecls, <<END); 648 static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 649 { 650 INC_STATS(\"DOM.$implClassName.constructors._get\"); 651 v8::Handle<v8::Value> data = info.Data(); 652 ASSERT(data->IsExternal() || data->IsNumber()); 653 WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data); 654 END 655 656 if ($implClassName eq "DOMWindow") { 657 push(@implContentDecls, <<END); 658 // Get the proxy corresponding to the DOMWindow if possible to 659 // make sure that the constructor function is constructed in the 660 // context of the DOMWindow and not in the context of the caller. 661 return V8DOMWrapper::getConstructor(type, V8DOMWindow::toNative(info.Holder())); 662 END 663 } elsif ($implClassName eq "DedicatedWorkerContext" or $implClassName eq "WorkerContext" or $implClassName eq "SharedWorkerContext") { 664 push(@implContentDecls, <<END); 665 return V8DOMWrapper::getConstructor(type, V8WorkerContext::toNative(info.Holder())); 666 END 667 } else { 668 push(@implContentDecls, " return v8::Handle<v8::Value>();"); 669 } 670 671 push(@implContentDecls, <<END); 672 } 673 674 END 675 } 676 677 sub GenerateNormalAttrGetter 678 { 679 my $attribute = shift; 680 my $dataNode = shift; 681 my $implClassName = shift; 682 my $interfaceName = shift; 683 684 my $attrExt = $attribute->signature->extendedAttributes; 685 my $attrName = $attribute->signature->name; 686 my $attrType = GetTypeFromSignature($attribute->signature); 687 my $nativeType = GetNativeTypeFromSignature($attribute->signature, -1); 688 689 my $getterStringUsesImp = $implClassName ne "SVGNumber"; 690 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName); 691 692 # Getter 693 my $conditionalString = GenerateConditionalString($attribute->signature); 694 push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString; 695 696 push(@implContentDecls, <<END); 697 static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) 698 { 699 INC_STATS(\"DOM.$implClassName.$attrName._get\"); 700 END 701 702 if ($svgNativeType) { 703 my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); 704 if ($svgWrappedNativeType =~ /List/) { 705 push(@implContentDecls, <<END); 706 $svgNativeType* imp = V8${implClassName}::toNative(info.Holder()); 707 END 708 } else { 709 push(@implContentDecls, <<END); 710 $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder()); 711 $svgWrappedNativeType& impInstance = wrapper->propertyReference(); 712 END 713 if ($getterStringUsesImp) { 714 push(@implContentDecls, <<END); 715 $svgWrappedNativeType* imp = &impInstance; 716 END 717 } 718 } 719 } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) { 720 if ($interfaceName eq "DOMWindow") { 721 push(@implContentDecls, <<END); 722 v8::Handle<v8::Object> holder = info.Holder(); 723 END 724 } else { 725 # perform lookup first 726 push(@implContentDecls, <<END); 727 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This()); 728 if (holder.IsEmpty()) 729 return v8::Handle<v8::Value>(); 730 END 731 } 732 push(@implContentDecls, <<END); 733 ${implClassName}* imp = V8${implClassName}::toNative(holder); 734 END 735 } else { 736 my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; 737 my $url = $attribute->signature->extendedAttributes->{"URL"}; 738 if ($getterStringUsesImp && $reflect && !$url && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { 739 # Generate super-compact call for regular attribute getter: 740 my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect; 741 my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); 742 $implIncludes{"${namespace}.h"} = 1; 743 push(@implContentDecls, " return getElementStringAttr(info, ${namespace}::${contentAttributeName}Attr);\n"); 744 push(@implContentDecls, "}\n\n"); 745 push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; 746 return; 747 # Skip the rest of the function! 748 } 749 push(@implContentDecls, <<END); 750 ${implClassName}* imp = V8${implClassName}::toNative(info.Holder()); 751 END 752 } 753 754 # Generate security checks if necessary 755 if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) { 756 push(@implContentDecls, " if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->$attrName()))\n return v8::Handle<v8::Value>();\n\n"); 757 } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) { 758 push(@implContentDecls, " if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->contentDocument()))\n return v8::Handle<v8::Value>();\n\n"); 759 } 760 761 my $useExceptions = 1 if @{$attribute->getterExceptions}; 762 if ($useExceptions) { 763 $implIncludes{"ExceptionCode.h"} = 1; 764 push(@implContentDecls, " ExceptionCode ec = 0;\n"); 765 } 766 767 if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) { 768 $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; 769 } 770 771 my $returnType = GetTypeFromSignature($attribute->signature); 772 773 my $getterString; 774 if ($getterStringUsesImp) { 775 $getterString = "imp->" . $codeGenerator->GetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute); 776 $getterString .= "ec" if $useExceptions; 777 $getterString .= ")"; 778 } else { 779 $getterString = "impInstance"; 780 } 781 782 my $result; 783 my $wrapper; 784 785 if ($attribute->signature->type eq "EventListener" && $dataNode->name eq "DOMWindow") { 786 push(@implContentDecls, " if (!imp->document())\n"); 787 push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); 788 } 789 790 if ($useExceptions) { 791 if ($nativeType =~ /^V8Parameter/) { 792 push(@implContentDecls, " " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $getterString) . ";\n"); 793 } else { 794 push(@implContentDecls, " $nativeType v = $getterString;\n"); 795 } 796 push(@implContentDecls, GenerateSetDOMException(" ")); 797 $result = "v"; 798 $result .= ".release()" if (IsRefPtrType($returnType)); 799 } else { 800 # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary 801 $result = $getterString; 802 } 803 804 # Special case for readonly or Replaceable attributes (with a few exceptions). This attempts to ensure that JS wrappers don't get 805 # garbage-collected prematurely when their lifetime is strongly tied to their owner. We accomplish this by inserting a reference to 806 # the newly created wrapper into an internal field of the holder object. 807 if (!IsNodeSubType($dataNode) && $attrName ne "self" && (IsWrapperType($returnType) && ($attribute->type =~ /^readonly/ || $attribute->signature->extendedAttributes->{"Replaceable"}) 808 && $returnType ne "EventTarget" && $returnType ne "SerializedScriptValue" && $returnType ne "DOMWindow" 809 && $returnType !~ /SVG/ && $returnType !~ /HTML/ && !IsDOMNodeType($returnType))) { 810 AddIncludesForType($returnType); 811 my $domMapFunction = GetDomMapFunction(0, $returnType); 812 # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already 813 # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference. 814 push(@implContentDecls, " RefPtr<$returnType> result = ${getterString};\n"); 815 push(@implContentDecls, " v8::Handle<v8::Value> wrapper = result.get() ? ${domMapFunction}.get(result.get()) : v8::Handle<v8::Value>();\n"); 816 push(@implContentDecls, " if (wrapper.IsEmpty()) {\n"); 817 push(@implContentDecls, " wrapper = toV8(result.get());\n"); 818 push(@implContentDecls, " if (!wrapper.IsEmpty())\n"); 819 if ($dataNode->name eq "DOMWindow") { 820 push(@implContentDecls, " V8DOMWrapper::setHiddenWindowReference(imp->frame(), wrapper);\n"); 821 } else { 822 push(@implContentDecls, " V8DOMWrapper::setHiddenReference(info.Holder(), wrapper);\n"); 823 } 824 push(@implContentDecls, " }\n"); 825 push(@implContentDecls, " return wrapper;\n"); 826 push(@implContentDecls, "}\n\n"); 827 push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; 828 return; 829 } 830 831 if ($codeGenerator->IsSVGAnimatedType($implClassName) and $codeGenerator->IsSVGTypeNeedingTearOff($attrType)) { 832 $implIncludes{"V8$attrType.h"} = 1; 833 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType); 834 # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked. 835 push(@implContentDecls, " return toV8(static_cast<$svgNativeType*>($result));\n"); 836 } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($attrType) and not $implClassName =~ /List$/) { 837 $implIncludes{"V8$attrType.h"} = 1; 838 $implIncludes{"SVGPropertyTearOff.h"} = 1; 839 my $tearOffType = $codeGenerator->GetSVGTypeNeedingTearOff($attrType); 840 if ($codeGenerator->IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { 841 my $getter = $result; 842 $getter =~ s/imp->//; 843 $getter =~ s/\(\)//; 844 845 my $updateMethod = "&${implClassName}::update" . $codeGenerator->WK_ucfirst($getter); 846 847 my $selfIsTearOffType = $codeGenerator->IsSVGTypeNeedingTearOff($implClassName); 848 if ($selfIsTearOffType) { 849 $implIncludes{"SVGStaticPropertyWithParentTearOff.h"} = 1; 850 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyWithParentTearOff<$implClassName, /; 851 852 if ($result =~ /matrix/ and $implClassName eq "SVGTransform") { 853 # SVGTransform offers a matrix() method for internal usage that returns an AffineTransform 854 # and a svgMatrix() method returning a SVGMatrix, used for the bindings. 855 $result =~ s/matrix/svgMatrix/; 856 } 857 858 push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create(wrapper, $result, $updateMethod)));\n"); 859 } else { 860 $implIncludes{"SVGStaticPropertyTearOff.h"} = 1; 861 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /; 862 863 push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create(imp, $result, $updateMethod)));\n"); 864 } 865 } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) { 866 my $extraImp = "GetOwnerElementForType<$implClassName, IsDerivedFromSVGElement<$implClassName>::value>::ownerElement(imp), "; 867 push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create($extraImp$result)));\n"); 868 } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) { 869 push(@implContentDecls, " return toV8(WTF::getPtr($result));\n"); 870 } else { 871 push(@implContentDecls, " return toV8(WTF::getPtr(${tearOffType}::create($result)));\n"); 872 } 873 } else { 874 push(@implContentDecls, " " . ReturnNativeToJSValue($attribute->signature, $result, " ").";\n"); 875 } 876 877 push(@implContentDecls, "}\n\n"); # end of getter 878 push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; 879 } 880 881 sub GenerateNormalAttrSetter 882 { 883 my $attribute = shift; 884 my $dataNode = shift; 885 my $implClassName = shift; 886 my $interfaceName = shift; 887 888 $implIncludes{"V8BindingMacros.h"} = 1; 889 890 my $attrExt = $attribute->signature->extendedAttributes; 891 892 my $conditionalString = GenerateConditionalString($attribute->signature); 893 push(@implContentDecls, "#if ${conditionalString}\n\n") if $conditionalString; 894 895 push(@implContentDecls, "static void ${attrName}AttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)\n{\n"); 896 push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); 897 898 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an 899 # interface type, then if the incoming value does not implement that interface, a TypeError is 900 # thrown rather than silently passing NULL to the C++ code. 901 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both 902 # strings and numbers, so do not throw TypeError if the attribute is of these types. 903 if ($attribute->signature->extendedAttributes->{"StrictTypeChecking"}) { 904 my $argType = GetTypeFromSignature($attribute->signature); 905 if (IsWrapperType($argType)) { 906 push(@implContentDecls, " if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value)) {\n"); 907 push(@implContentDecls, " V8Proxy::throwTypeError();\n"); 908 push(@implContentDecls, " return;\n"); 909 push(@implContentDecls, " }\n"); 910 } 911 } 912 913 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($implClassName); 914 if ($svgNativeType) { 915 my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); 916 if ($svgWrappedNativeType =~ /List$/) { 917 push(@implContentDecls, <<END); 918 $svgNativeType* imp = V8${implClassName}::toNative(info.Holder()); 919 END 920 } else { 921 push(@implContentDecls, " $svgNativeType* wrapper = V8${implClassName}::toNative(info.Holder());\n"); 922 push(@implContentDecls, " if (wrapper->role() == AnimValRole) {\n"); 923 push(@implContentDecls, " V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n"); 924 push(@implContentDecls, " return;\n"); 925 push(@implContentDecls, " }\n"); 926 push(@implContentDecls, " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"); 927 push(@implContentDecls, " $svgWrappedNativeType* imp = &impInstance;\n"); 928 } 929 } elsif ($attrExt->{"v8OnProto"}) { 930 if ($interfaceName eq "DOMWindow") { 931 push(@implContentDecls, <<END); 932 v8::Handle<v8::Object> holder = info.Holder(); 933 END 934 } else { 935 # perform lookup first 936 push(@implContentDecls, <<END); 937 v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8${interfaceName}::GetTemplate(), info.This()); 938 if (holder.IsEmpty()) 939 return; 940 END 941 } 942 push(@implContentDecls, <<END); 943 ${implClassName}* imp = V8${implClassName}::toNative(holder); 944 END 945 } else { 946 my $attrType = GetTypeFromSignature($attribute->signature); 947 my $reflect = $attribute->signature->extendedAttributes->{"Reflect"}; 948 if ($reflect && IsNodeSubType($dataNode) && $codeGenerator->IsStringType($attrType)) { 949 # Generate super-compact call for regular attribute setter: 950 my $contentAttributeName = $reflect eq "1" ? lc $attrName : $reflect; 951 my $namespace = $codeGenerator->NamespaceForAttributeName($interfaceName, $contentAttributeName); 952 $implIncludes{"${namespace}.h"} = 1; 953 push(@implContentDecls, " setElementStringAttr(info, ${namespace}::${contentAttributeName}Attr, value);\n"); 954 push(@implContentDecls, "}\n\n"); 955 push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; 956 return; 957 # Skip the rest of the function! 958 } 959 960 push(@implContentDecls, <<END); 961 ${implClassName}* imp = V8${implClassName}::toNative(info.Holder()); 962 END 963 } 964 965 my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); 966 if ($attribute->signature->type eq "EventListener") { 967 if ($dataNode->name eq "DOMWindow") { 968 push(@implContentDecls, " if (!imp->document())\n"); 969 push(@implContentDecls, " return;\n"); 970 } 971 } else { 972 my $value = JSValueToNative($attribute->signature, "value"); 973 if ($nativeType =~ /^V8Parameter/) { 974 push(@implContentDecls, " " . ConvertToV8Parameter($attribute->signature, $nativeType, "v", $value, "VOID") . "\n"); 975 } else { 976 push(@implContentDecls, " $nativeType v = $value;\n"); 977 } 978 } 979 980 my $result = "v"; 981 my $returnType = GetTypeFromSignature($attribute->signature); 982 if (IsRefPtrType($returnType)) { 983 $result = "WTF::getPtr(" . $result . ")"; 984 } 985 986 my $useExceptions = 1 if @{$attribute->setterExceptions}; 987 988 if ($useExceptions) { 989 $implIncludes{"ExceptionCode.h"} = 1; 990 push(@implContentDecls, " ExceptionCode ec = 0;\n"); 991 } 992 993 if ($implClassName eq "SVGNumber") { 994 push(@implContentDecls, " *imp = $result;\n"); 995 } else { 996 if ($attribute->signature->type eq "EventListener") { 997 my $implSetterFunctionName = $codeGenerator->WK_ucfirst($attrName); 998 $implIncludes{"V8AbstractEventListener.h"} = 1; 999 push(@implContentDecls, " transferHiddenDependency(info.Holder(), imp->$attrName(), value, V8${interfaceName}::eventListenerCacheIndex);\n"); 1000 if ($interfaceName eq "WorkerContext" and $attribute->signature->name eq "onerror") { 1001 $implIncludes{"V8EventListenerList.h"} = 1; 1002 $implIncludes{"V8WorkerContextErrorHandler.h"} = 1; 1003 push(@implContentDecls, " imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WorkerContextErrorHandler>(value, true)"); 1004 } elsif ($interfaceName eq "DOMWindow" and $attribute->signature->name eq "onerror") { 1005 $implIncludes{"V8EventListenerList.h"} = 1; 1006 $implIncludes{"V8WindowErrorHandler.h"} = 1; 1007 push(@implContentDecls, " imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8WindowErrorHandler>(value, true)"); 1008 } else { 1009 push(@implContentDecls, " imp->set$implSetterFunctionName(V8DOMWrapper::getEventListener(value, true, ListenerFindOrCreate)"); 1010 } 1011 } else { 1012 my $setterExpressionPrefix = $codeGenerator->SetterExpressionPrefix(\%implIncludes, $interfaceName, $attribute); 1013 push(@implContentDecls, " imp->$setterExpressionPrefix$result"); 1014 } 1015 push(@implContentDecls, ", ec") if $useExceptions; 1016 push(@implContentDecls, ");\n"); 1017 } 1018 1019 if ($useExceptions) { 1020 push(@implContentDecls, " if (UNLIKELY(ec))\n"); 1021 push(@implContentDecls, " V8Proxy::setDOMException(ec);\n"); 1022 } 1023 1024 if ($svgNativeType) { 1025 if ($useExceptions) { 1026 push(@implContentDecls, " if (!ec)\n"); 1027 push(@implContentDecls, " wrapper->commitChange();\n"); 1028 } else { 1029 push(@implContentDecls, " wrapper->commitChange();\n"); 1030 } 1031 } 1032 1033 push(@implContentDecls, " return;\n"); 1034 push(@implContentDecls, "}\n\n"); # end of setter 1035 push(@implContentDecls, "#endif // ${conditionalString}\n\n") if $conditionalString; 1036 } 1037 1038 sub GetFunctionTemplateCallbackName 1039 { 1040 $function = shift; 1041 $interfaceName = shift; 1042 1043 my $name = $function->signature->name; 1044 1045 if ($function->signature->extendedAttributes->{"Custom"} || 1046 $function->signature->extendedAttributes->{"V8Custom"}) { 1047 if ($function->signature->extendedAttributes->{"Custom"} && 1048 $function->signature->extendedAttributes->{"V8Custom"}) { 1049 die "Custom and V8Custom should be mutually exclusive!" 1050 } 1051 return "V8${interfaceName}::${name}Callback"; 1052 } else { 1053 return "${interfaceName}Internal::${name}Callback"; 1054 } 1055 } 1056 1057 sub GenerateNewFunctionTemplate 1058 { 1059 $function = shift; 1060 $interfaceName = shift; 1061 $signature = shift; 1062 1063 my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); 1064 return "v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), $signature)"; 1065 } 1066 1067 sub GenerateEventListenerCallback 1068 { 1069 my $implClassName = shift; 1070 my $functionName = shift; 1071 my $lookupType = ($functionName eq "add") ? "OrCreate" : "Only"; 1072 my $passRefPtrHandling = ($functionName eq "add") ? "" : ".get()"; 1073 my $hiddenDependencyAction = ($functionName eq "add") ? "create" : "remove"; 1074 1075 push(@implContentDecls, <<END); 1076 static v8::Handle<v8::Value> ${functionName}EventListenerCallback(const v8::Arguments& args) 1077 { 1078 INC_STATS("DOM.${implClassName}.${functionName}EventListener()"); 1079 RefPtr<EventListener> listener = V8DOMWrapper::getEventListener(args[1], false, ListenerFind${lookupType}); 1080 if (listener) { 1081 V8${implClassName}::toNative(args.Holder())->${functionName}EventListener(v8ValueToAtomicWebCoreString(args[0]), listener${passRefPtrHandling}, args[2]->BooleanValue()); 1082 ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], V8${implClassName}::eventListenerCacheIndex); 1083 } 1084 return v8::Undefined(); 1085 } 1086 1087 END 1088 } 1089 1090 sub GenerateParametersCheckExpression 1091 { 1092 my $numParameters = shift; 1093 my $function = shift; 1094 1095 my @andExpression = (); 1096 push(@andExpression, "args.Length() == $numParameters"); 1097 my $parameterIndex = 0; 1098 foreach $parameter (@{$function->parameters}) { 1099 last if $parameterIndex >= $numParameters; 1100 my $value = "args[$parameterIndex]"; 1101 my $type = GetTypeFromSignature($parameter); 1102 1103 # Only DOMString or wrapper types are checked. 1104 # For DOMString, Null, Undefined and any Object are accepted too, as 1105 # these are acceptable values for a DOMString argument (any Object can 1106 # be converted to a string via .toString). 1107 if ($codeGenerator->IsStringType($type)) { 1108 push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())"); 1109 } elsif ($parameter->extendedAttributes->{"Callback"}) { 1110 # For Callbacks only checks if the value is null or object. 1111 push(@andExpression, "(${value}->IsNull() || ${value}->IsObject())"); 1112 } elsif (IsWrapperType($type)) { 1113 push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value))"); 1114 } 1115 1116 $parameterIndex++; 1117 } 1118 my $res = join(" && ", @andExpression); 1119 $res = "($res)" if @andExpression > 1; 1120 return $res; 1121 } 1122 1123 sub GenerateFunctionParametersCheck 1124 { 1125 my $function = shift; 1126 1127 my @orExpression = (); 1128 my $numParameters = 0; 1129 foreach $parameter (@{$function->parameters}) { 1130 if ($parameter->extendedAttributes->{"Optional"}) { 1131 push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); 1132 } 1133 $numParameters++; 1134 } 1135 push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); 1136 return join(" || ", @orExpression); 1137 } 1138 1139 sub GenerateOverloadedFunctionCallback 1140 { 1141 my $function = shift; 1142 my $dataNode = shift; 1143 my $implClassName = shift; 1144 1145 # Generate code for choosing the correct overload to call. Overloads are 1146 # chosen based on the total number of arguments passed and the type of 1147 # values passed in non-primitive argument slots. When more than a single 1148 # overload is applicable, precedence is given according to the order of 1149 # declaration in the IDL. 1150 1151 my $name = $function->signature->name; 1152 push(@implContentDecls, <<END); 1153 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) 1154 { 1155 INC_STATS(\"DOM.$implClassName.$name\"); 1156 END 1157 1158 foreach my $overload (@{$function->{overloads}}) { 1159 my $parametersCheck = GenerateFunctionParametersCheck($overload); 1160 push(@implContentDecls, " if ($parametersCheck)\n"); 1161 push(@implContentDecls, " return ${name}$overload->{overloadIndex}Callback(args);\n"); 1162 } 1163 push(@implContentDecls, <<END); 1164 V8Proxy::throwTypeError(); 1165 return notHandledByInterceptor(); 1166 END 1167 push(@implContentDecls, "}\n\n"); 1168 } 1169 1170 sub GenerateFunctionCallback 1171 { 1172 my $function = shift; 1173 my $dataNode = shift; 1174 my $implClassName = shift; 1175 1176 my $interfaceName = $dataNode->name; 1177 my $name = $function->signature->name; 1178 1179 if (@{$function->{overloads}} > 1) { 1180 # Append a number to an overloaded method's name to make it unique: 1181 $name = $name . $function->{overloadIndex}; 1182 } 1183 1184 # Adding and removing event listeners are not standard callback behavior, 1185 # but they are extremely consistent across the various classes that take event listeners, 1186 # so we can generate them as a "special case". 1187 if ($name eq "addEventListener") { 1188 GenerateEventListenerCallback($implClassName, "add"); 1189 return; 1190 } elsif ($name eq "removeEventListener") { 1191 GenerateEventListenerCallback($implClassName, "remove"); 1192 return; 1193 } 1194 1195 push(@implContentDecls, <<END); 1196 static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) 1197 { 1198 INC_STATS(\"DOM.$implClassName.$name\"); 1199 END 1200 1201 my $numParameters = @{$function->parameters}; 1202 1203 my $requiresAllArguments = $function->signature->extendedAttributes->{"RequiresAllArguments"}; 1204 if ($requiresAllArguments) { 1205 my $numMandatoryParams = @{$function->parameters}; 1206 foreach my $param (reverse(@{$function->parameters})) { 1207 if ($param->extendedAttributes->{"Optional"}) { 1208 $numMandatoryParams--; 1209 } else { 1210 last; 1211 } 1212 } 1213 push(@implContentDecls, " if (args.Length() < $numMandatoryParams)\n"); 1214 if ($requiresAllArguments eq "Raise") { 1215 push(@implContentDecls, " return throwError(\"Not enough arguments\", V8Proxy::SyntaxError);\n"); 1216 } else { 1217 push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); 1218 } 1219 } 1220 1221 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($implClassName); 1222 1223 if ($svgNativeType) { 1224 my $nativeClassName = GetNativeType($implClassName); 1225 if ($implClassName =~ /List$/) { 1226 push(@implContentDecls, " $nativeClassName imp = V8${implClassName}::toNative(args.Holder());\n"); 1227 } else { 1228 push(@implContentDecls, " $nativeClassName wrapper = V8${implClassName}::toNative(args.Holder());\n"); 1229 push(@implContentDecls, " if (wrapper->role() == AnimValRole) {\n"); 1230 push(@implContentDecls, " V8Proxy::setDOMException(NO_MODIFICATION_ALLOWED_ERR);\n"); 1231 push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); 1232 push(@implContentDecls, " }\n"); 1233 my $svgWrappedNativeType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($implClassName); 1234 push(@implContentDecls, " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"); 1235 push(@implContentDecls, " $svgWrappedNativeType* imp = &impInstance;\n"); 1236 } 1237 } elsif (!$function->signature->extendedAttributes->{"ClassMethod"}) { 1238 push(@implContentDecls, <<END); 1239 ${implClassName}* imp = V8${implClassName}::toNative(args.Holder()); 1240 END 1241 } 1242 1243 # Check domain security if needed 1244 if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} 1245 || $interfaceName eq "DOMWindow") 1246 && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { 1247 # We have not find real use cases yet. 1248 push(@implContentDecls, <<END); 1249 if (!V8BindingSecurity::canAccessFrame(V8BindingState::Only(), imp->frame(), true)) 1250 return v8::Handle<v8::Value>(); 1251 END 1252 } 1253 1254 my $raisesExceptions = @{$function->raisesExceptions}; 1255 if (!$raisesExceptions) { 1256 foreach my $parameter (@{$function->parameters}) { 1257 if ((!$parameter->extendedAttributes->{"Callback"} and TypeCanFailConversion($parameter)) or $parameter->extendedAttributes->{"IsIndex"}) { 1258 $raisesExceptions = 1; 1259 } 1260 } 1261 } 1262 1263 if ($raisesExceptions) { 1264 $implIncludes{"ExceptionCode.h"} = 1; 1265 push(@implContentDecls, " ExceptionCode ec = 0;\n"); 1266 push(@implContentDecls, " {\n"); 1267 # The brace here is needed to prevent the ensuing 'goto fail's from jumping past constructors 1268 # of objects (like Strings) declared later, causing compile errors. The block scope ends 1269 # right before the label 'fail:'. 1270 } 1271 1272 if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { 1273 push(@implContentDecls, <<END); 1274 RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, $numParameters)); 1275 size_t maxStackSize = imp->shouldCaptureFullStackTrace() ? ScriptCallStack::maxCallStackSizeToCapture : 1; 1276 RefPtr<ScriptCallStack> callStack(createScriptCallStack(maxStackSize)); 1277 if (!callStack) 1278 return v8::Undefined(); 1279 END 1280 $implIncludes{"ScriptArguments.h"} = 1; 1281 $implIncludes{"ScriptCallStack.h"} = 1; 1282 $implIncludes{"ScriptCallStackFactory.h"} = 1; 1283 } 1284 if ($function->signature->extendedAttributes->{"SVGCheckSecurityDocument"}) { 1285 push(@implContentDecls, <<END); 1286 if (!V8BindingSecurity::checkNodeSecurity(V8BindingState::Only(), imp->getSVGDocument(ec))) 1287 return v8::Handle<v8::Value>(); 1288 END 1289 } 1290 1291 my $paramIndex = 0; 1292 foreach my $parameter (@{$function->parameters}) { 1293 TranslateParameter($parameter); 1294 1295 my $parameterName = $parameter->name; 1296 1297 # Optional callbacks should be treated differently, because they always have a default value (0), 1298 # and we can reduce the number of overloaded functions that take a different number of parameters. 1299 if ($parameter->extendedAttributes->{"Optional"} && !$parameter->extendedAttributes->{"Callback"}) { 1300 # Generate early call if there are not enough parameters. 1301 push(@implContentDecls, " if (args.Length() <= $paramIndex) {\n"); 1302 my $functionCall = GenerateFunctionCallString($function, $paramIndex, " " x 2, $implClassName); 1303 push(@implContentDecls, $functionCall); 1304 push(@implContentDecls, " }\n"); 1305 } 1306 1307 $implIncludes{"ExceptionCode.h"} = 1; 1308 my $nativeType = GetNativeTypeFromSignature($parameter, $paramIndex); 1309 if ($parameter->extendedAttributes->{"Callback"}) { 1310 my $className = GetCallbackClassName($parameter->type); 1311 $implIncludes{"$className.h"} = 1; 1312 if ($parameter->extendedAttributes->{"Optional"}) { 1313 push(@implContentDecls, " RefPtr<" . $parameter->type . "> $parameterName;\n"); 1314 push(@implContentDecls, " if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n"); 1315 push(@implContentDecls, " if (!args[$paramIndex]->IsObject())\n"); 1316 push(@implContentDecls, " return throwError(TYPE_MISMATCH_ERR);\n"); 1317 push(@implContentDecls, " $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n"); 1318 push(@implContentDecls, " }\n"); 1319 } else { 1320 push(@implContentDecls, " if (args.Length() <= $paramIndex || !args[$paramIndex]->IsObject())\n"); 1321 push(@implContentDecls, " return throwError(TYPE_MISMATCH_ERR);\n"); 1322 push(@implContentDecls, " RefPtr<" . $parameter->type . "> $parameterName = ${className}::create(args[$paramIndex], getScriptExecutionContext());\n"); 1323 } 1324 } elsif ($parameter->type eq "SerializedScriptValue") { 1325 $implIncludes{"SerializedScriptValue.h"} = 1; 1326 push(@implContentDecls, " bool ${parameterName}DidThrow = false;\n"); 1327 push(@implContentDecls, " $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], ${parameterName}DidThrow);\n"); 1328 push(@implContentDecls, " if (${parameterName}DidThrow)\n"); 1329 push(@implContentDecls, " return v8::Undefined();\n"); 1330 } elsif (TypeCanFailConversion($parameter)) { 1331 push(@implContentDecls, " $nativeType $parameterName = " . 1332 JSValueToNative($parameter, "args[$paramIndex]") . ";\n"); 1333 push(@implContentDecls, " if (UNLIKELY(!$parameterName)) {\n"); 1334 push(@implContentDecls, " ec = TYPE_MISMATCH_ERR;\n"); 1335 push(@implContentDecls, " goto fail;\n"); 1336 push(@implContentDecls, " }\n"); 1337 } elsif ($nativeType =~ /^V8Parameter/) { 1338 my $value = JSValueToNative($parameter, "args[$paramIndex]"); 1339 push(@implContentDecls, " " . ConvertToV8Parameter($parameter, $nativeType, $parameterName, $value) . "\n"); 1340 } else { 1341 $implIncludes{"V8BindingMacros.h"} = 1; 1342 # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an 1343 # interface type, then if the incoming value does not implement that interface, a TypeError 1344 # is thrown rather than silently passing NULL to the C++ code. 1345 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted 1346 # to both strings and numbers, so do not throw TypeError if the argument is of these 1347 # types. 1348 if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) { 1349 my $argValue = "args[$paramIndex]"; 1350 my $argType = GetTypeFromSignature($parameter); 1351 if (IsWrapperType($argType)) { 1352 push(@implContentDecls, " if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue)) {\n"); 1353 push(@implContentDecls, " V8Proxy::throwTypeError();\n"); 1354 push(@implContentDecls, " return notHandledByInterceptor();\n"); 1355 push(@implContentDecls, " }\n"); 1356 } 1357 } 1358 push(@implContentDecls, " EXCEPTION_BLOCK($nativeType, $parameterName, " . 1359 JSValueToNative($parameter, "args[$paramIndex]") . ");\n"); 1360 } 1361 1362 if ($parameter->extendedAttributes->{"IsIndex"}) { 1363 push(@implContentDecls, " if (UNLIKELY($parameterName < 0)) {\n"); 1364 push(@implContentDecls, " ec = INDEX_SIZE_ERR;\n"); 1365 push(@implContentDecls, " goto fail;\n"); 1366 push(@implContentDecls, " }\n"); 1367 } 1368 1369 $paramIndex++; 1370 } 1371 1372 # Build the function call string. 1373 my $callString = GenerateFunctionCallString($function, $paramIndex, " ", $implClassName); 1374 push(@implContentDecls, "$callString"); 1375 1376 if ($raisesExceptions) { 1377 push(@implContentDecls, " }\n"); 1378 push(@implContentDecls, " fail:\n"); 1379 push(@implContentDecls, " V8Proxy::setDOMException(ec);\n"); 1380 push(@implContentDecls, " return v8::Handle<v8::Value>();\n"); 1381 } 1382 1383 push(@implContentDecls, "}\n\n"); 1384 } 1385 1386 sub GenerateBatchedAttributeData 1387 { 1388 my $dataNode = shift; 1389 my $interfaceName = $dataNode->name; 1390 my $attributes = shift; 1391 1392 foreach my $attribute (@$attributes) { 1393 my $conditionalString = GenerateConditionalString($attribute->signature); 1394 push(@implContent, "#if ${conditionalString}\n") if $conditionalString; 1395 GenerateSingleBatchedAttribute($interfaceName, $attribute, ",", ""); 1396 push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString; 1397 } 1398 } 1399 1400 sub GenerateSingleBatchedAttribute 1401 { 1402 my $interfaceName = shift; 1403 my $attribute = shift; 1404 my $delimiter = shift; 1405 my $indent = shift; 1406 my $attrName = $attribute->signature->name; 1407 my $attrExt = $attribute->signature->extendedAttributes; 1408 1409 # Attributes of type SerializedScriptValue are set in the 1410 # constructor and don't require callbacks. 1411 return if ($attribute->signature->type eq "SerializedScriptValue"); 1412 1413 my $accessControl = "v8::DEFAULT"; 1414 if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) { 1415 $accessControl = "v8::ALL_CAN_READ"; 1416 } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) { 1417 $accessControl = "v8::ALL_CAN_WRITE"; 1418 } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) { 1419 $accessControl = "v8::ALL_CAN_READ"; 1420 if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) { 1421 $accessControl .= " | v8::ALL_CAN_WRITE"; 1422 } 1423 } 1424 if ($attrExt->{"V8DisallowShadowing"}) { 1425 $accessControl .= " | v8::PROHIBITS_OVERWRITING"; 1426 } 1427 $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")"; 1428 1429 my $customAccessor = 1430 $attrExt->{"Custom"} || 1431 $attrExt->{"CustomSetter"} || 1432 $attrExt->{"CustomGetter"} || 1433 $attrExt->{"V8Custom"} || 1434 $attrExt->{"V8CustomSetter"} || 1435 $attrExt->{"V8CustomGetter"} || 1436 ""; 1437 if ($customAccessor eq 1) { 1438 # use the naming convension, interface + (capitalize) attr name 1439 $customAccessor = $interfaceName . "::" . $attrName; 1440 } 1441 1442 my $getter; 1443 my $setter; 1444 my $propAttr = "v8::None"; 1445 my $hasCustomSetter = 0; 1446 1447 # Check attributes. 1448 if ($attrExt->{"DontEnum"}) { 1449 $propAttr .= " | v8::DontEnum"; 1450 } 1451 if ($attrExt->{"V8DisallowShadowing"}) { 1452 $propAttr .= " | v8::DontDelete"; 1453 } 1454 1455 my $on_proto = "0 /* on instance */"; 1456 my $data = "0 /* no data */"; 1457 1458 # Constructor 1459 if ($attribute->signature->type =~ /Constructor$/) { 1460 my $constructorType = $codeGenerator->StripModule($attribute->signature->type); 1461 $constructorType =~ s/Constructor$//; 1462 $implIncludes{"V8${constructorType}.h"} = 1; 1463 if ($customAccessor) { 1464 $getter = "V8${customAccessor}AccessorGetter"; 1465 } else { 1466 $data = "&V8${constructorType}::info"; 1467 $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; 1468 } 1469 $setter = "0"; 1470 $propAttr = "v8::ReadOnly"; 1471 1472 } else { 1473 # Default Getter and Setter 1474 $getter = "${interfaceName}Internal::${attrName}AttrGetter"; 1475 $setter = "${interfaceName}Internal::${attrName}AttrSetter"; 1476 1477 # Custom Setter 1478 if ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { 1479 $hasCustomSetter = 1; 1480 $setter = "V8${customAccessor}AccessorSetter"; 1481 } 1482 1483 # Custom Getter 1484 if ($attrExt->{"CustomGetter"} || $attrExt->{"V8CustomGetter"} || $attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { 1485 $getter = "V8${customAccessor}AccessorGetter"; 1486 } 1487 } 1488 1489 # Replaceable 1490 if ($attrExt->{"Replaceable"} && !$hasCustomSetter) { 1491 $setter = "0"; 1492 # Handle the special case of window.top being marked as Replaceable. 1493 # FIXME: Investigate whether we could treat window.top as replaceable 1494 # and allow shadowing without it being a security hole. 1495 if (!($interfaceName eq "DOMWindow" and $attrName eq "top")) { 1496 $propAttr .= " | v8::ReadOnly"; 1497 } 1498 } 1499 1500 # Read only attributes 1501 if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) { 1502 $setter = "0"; 1503 } 1504 1505 # An accessor can be installed on the proto 1506 if ($attrExt->{"v8OnProto"}) { 1507 $on_proto = "1 /* on proto */"; 1508 } 1509 1510 my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type . 1511 "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; 1512 1513 push(@implContent, $indent . " \/\/ $commentInfo\n"); 1514 push(@implContent, $indent . " {\"$attrName\", $getter, $setter, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n"); 1515 } 1516 1517 sub GenerateImplementationIndexer 1518 { 1519 my $dataNode = shift; 1520 my $indexer = shift; 1521 my $interfaceName = $dataNode->name; 1522 1523 # FIXME: Figure out what HasNumericIndexGetter is really supposed to do. Right now, it's only set on WebGL-related files. 1524 my $hasCustomSetter = $dataNode->extendedAttributes->{"HasCustomIndexSetter"} && !$dataNode->extendedAttributes->{"HasNumericIndexGetter"}; 1525 my $hasGetter = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; 1526 1527 # FIXME: Find a way to not have to special-case HTMLOptionsCollection. 1528 if ($interfaceName eq "HTMLOptionsCollection") { 1529 $hasGetter = 1; 1530 } 1531 1532 # FIXME: Investigate and remove this nastinesss. In V8, named property handling and indexer handling are apparently decoupled, 1533 # which means that object[X] where X is a number doesn't reach named property indexer. So we need to provide 1534 # simplistic, mirrored indexer handling in addition to named property handling. 1535 my $isSpecialCase = exists $indexerSpecialCases{$interfaceName}; 1536 if ($isSpecialCase) { 1537 $hasGetter = 1; 1538 if ($dataNode->extendedAttributes->{"DelegatingPutFunction"}) { 1539 $hasCustomSetter = 1; 1540 } 1541 } 1542 1543 if (!$hasGetter) { 1544 return; 1545 } 1546 1547 $implIncludes{"V8Collection.h"} = 1; 1548 1549 my $indexerType = $indexer ? $indexer->type : 0; 1550 1551 # FIXME: Remove this once toV8 helper methods are implemented (see https://bugs.webkit.org/show_bug.cgi?id=32563). 1552 if ($interfaceName eq "WebKitCSSKeyframesRule") { 1553 $indexerType = "WebKitCSSKeyframeRule"; 1554 } 1555 1556 # FIXME: The item() getter is not inherited from CSSValueList, seemingly due to the way 1557 # the CodeGenerator->AddMethodsConstantsAndAttributesFromParentClasses() method works, 1558 # so we need to set the indexerType manually in this case. 1559 if ($interfaceName eq "WebKitCSSTransformValue") { 1560 $indexerType = "CSSValue"; 1561 } 1562 1563 if ($indexerType && !$hasCustomSetter) { 1564 if ($indexerType eq "DOMString") { 1565 my $conversion = $indexer->extendedAttributes->{"ConvertNullStringTo"}; 1566 if ($conversion && $conversion eq "Null") { 1567 push(@implContent, <<END); 1568 setCollectionStringOrNullIndexedGetter<${interfaceName}>(desc); 1569 END 1570 } else { 1571 push(@implContent, <<END); 1572 setCollectionStringIndexedGetter<${interfaceName}>(desc); 1573 END 1574 } 1575 } else { 1576 push(@implContent, <<END); 1577 setCollectionIndexedGetter<${interfaceName}, ${indexerType}>(desc); 1578 END 1579 # Include the header for this indexer type, because setCollectionIndexedGetter() requires toV8() for this type. 1580 $implIncludes{"V8${indexerType}.h"} = 1; 1581 } 1582 1583 return; 1584 } 1585 1586 my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; 1587 my $hasEnumerator = !$isSpecialCase && IsNodeSubType($dataNode); 1588 my $setOn = "Instance"; 1589 1590 # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow 1591 # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to 1592 # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set 1593 # on the object. 1594 if ($interfaceName eq "DOMWindow") { 1595 $setOn = "Prototype"; 1596 $hasDeleter = 0; 1597 } 1598 1599 push(@implContent, " desc->${setOn}Template()->SetIndexedPropertyHandler(V8${interfaceName}::indexedPropertyGetter"); 1600 push(@implContent, $hasCustomSetter ? ", V8${interfaceName}::indexedPropertySetter" : ", 0"); 1601 push(@implContent, ", 0"); # IndexedPropertyQuery -- not being used at the moment. 1602 push(@implContent, $hasDeleter ? ", V8${interfaceName}::indexedPropertyDeleter" : ", 0"); 1603 push(@implContent, ", nodeCollectionIndexedPropertyEnumerator<${interfaceName}>") if $hasEnumerator; 1604 push(@implContent, ");\n"); 1605 } 1606 1607 sub GenerateImplementationNamedPropertyGetter 1608 { 1609 my $dataNode = shift; 1610 my $namedPropertyGetter = shift; 1611 my $interfaceName = $dataNode->name; 1612 my $hasCustomGetter = $dataNode->extendedAttributes->{"HasOverridingNameGetter"} || $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}; 1613 1614 # FIXME: Remove hard-coded HTMLOptionsCollection reference by changing HTMLOptionsCollection to not inherit 1615 # from HTMLCollection per W3C spec (http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#HTMLOptionsCollection). 1616 if ($interfaceName eq "HTMLOptionsCollection") { 1617 $interfaceName = "HTMLCollection"; 1618 $hasCustomGetter = 1; 1619 } 1620 1621 if ($interfaceName eq "HTMLAppletElement" || $interfaceName eq "HTMLEmbedElement" || $interfaceName eq "HTMLObjectElement") { 1622 $hasCustomGetter = 1; 1623 } 1624 1625 if ($interfaceName eq "HTMLDocument") { 1626 $hasCustomGetter = 0; 1627 } 1628 1629 my $hasGetter = $dataNode->extendedAttributes->{"HasNameGetter"} || $hasCustomGetter; 1630 if (!$hasGetter) { 1631 return; 1632 } 1633 1634 if ($namedPropertyGetter && $namedPropertyGetter->type ne "Node" && !$namedPropertyGetter->extendedAttributes->{"Custom"} && !$hasCustomGetter) { 1635 $implIncludes{"V8Collection.h"} = 1; 1636 my $type = $namedPropertyGetter->type; 1637 push(@implContent, <<END); 1638 setCollectionNamedGetter<${interfaceName}, ${type}>(desc); 1639 END 1640 return; 1641 } 1642 1643 my $hasSetter = $dataNode->extendedAttributes->{"DelegatingPutFunction"}; 1644 my $hasDeleter = $dataNode->extendedAttributes->{"CustomDeleteProperty"}; 1645 my $hasEnumerator = $dataNode->extendedAttributes->{"CustomGetPropertyNames"}; 1646 my $setOn = "Instance"; 1647 1648 # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on DOMWindow 1649 # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to 1650 # get implementation straight out of the DOMWindow prototype regardless of what prototype is actually set 1651 # on the object. 1652 if ($interfaceName eq "DOMWindow") { 1653 $setOn = "Prototype"; 1654 $hasDeleter = 0; 1655 $hasEnumerator = 0; 1656 } 1657 1658 push(@implContent, " desc->${setOn}Template()->SetNamedPropertyHandler(V8${interfaceName}::namedPropertyGetter, "); 1659 push(@implContent, $hasSetter ? "V8${interfaceName}::namedPropertySetter, " : "0, "); 1660 # If there is a custom enumerator, there MUST be custom query to properly communicate property attributes. 1661 push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyQuery, " : "0, "); 1662 push(@implContent, $hasDeleter ? "V8${interfaceName}::namedPropertyDeleter, " : "0, "); 1663 push(@implContent, $hasEnumerator ? "V8${interfaceName}::namedPropertyEnumerator" : "0"); 1664 push(@implContent, ");\n"); 1665 } 1666 1667 sub GenerateImplementationCustomCall 1668 { 1669 my $dataNode = shift; 1670 my $interfaceName = $dataNode->name; 1671 my $hasCustomCall = $dataNode->extendedAttributes->{"CustomCall"}; 1672 1673 # FIXME: Remove hard-coded HTMLOptionsCollection reference. 1674 if ($interfaceName eq "HTMLOptionsCollection") { 1675 $interfaceName = "HTMLCollection"; 1676 $hasCustomCall = 1; 1677 } 1678 1679 if ($hasCustomCall) { 1680 push(@implContent, " desc->InstanceTemplate()->SetCallAsFunctionHandler(V8${interfaceName}::callAsFunctionCallback);\n"); 1681 } 1682 } 1683 1684 sub GenerateImplementationMasqueradesAsUndefined 1685 { 1686 my $dataNode = shift; 1687 if ($dataNode->extendedAttributes->{"MasqueradesAsUndefined"}) 1688 { 1689 push(@implContent, " desc->InstanceTemplate()->MarkAsUndetectable();\n"); 1690 } 1691 } 1692 1693 sub GenerateImplementation 1694 { 1695 my $object = shift; 1696 my $dataNode = shift; 1697 my $interfaceName = $dataNode->name; 1698 my $visibleInterfaceName = GetVisibleInterfaceName($interfaceName); 1699 my $className = "V8$interfaceName"; 1700 my $implClassName = $interfaceName; 1701 my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; 1702 1703 # - Add default header template 1704 push(@implFixedHeader, GenerateImplementationContentHeader($dataNode)); 1705 1706 $implIncludes{"RuntimeEnabledFeatures.h"} = 1; 1707 $implIncludes{"V8Proxy.h"} = 1; 1708 $implIncludes{"V8Binding.h"} = 1; 1709 $implIncludes{"V8BindingState.h"} = 1; 1710 $implIncludes{"V8DOMWrapper.h"} = 1; 1711 $implIncludes{"V8IsolatedContext.h"} = 1; 1712 1713 AddIncludesForType($interfaceName); 1714 1715 my $toActive = IsActiveDomType($interfaceName) ? "${className}::toActiveDOMObject" : "0"; 1716 1717 # Find the super descriptor. 1718 my $parentClass = ""; 1719 my $parentClassTemplate = ""; 1720 foreach (@{$dataNode->parents}) { 1721 my $parent = $codeGenerator->StripModule($_); 1722 if ($parent eq "EventTarget") { 1723 next; 1724 } 1725 $implIncludes{"V8${parent}.h"} = 1; 1726 $parentClass = "V8" . $parent; 1727 $parentClassTemplate = $parentClass . "::GetTemplate()"; 1728 last; 1729 } 1730 push(@implContentDecls, "namespace WebCore {\n\n"); 1731 my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0"; 1732 push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, ${toActive}, ${parentClassInfo} };\n\n"); 1733 push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n"); 1734 push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n"); 1735 1736 my $hasConstructors = 0; 1737 my $serializedAttribute; 1738 # Generate property accessors for attributes. 1739 for ($index = 0; $index < @{$dataNode->attributes}; $index++) { 1740 $attribute = @{$dataNode->attributes}[$index]; 1741 $attrName = $attribute->signature->name; 1742 $attrType = $attribute->signature->type; 1743 1744 # Generate special code for the constructor attributes. 1745 if ($attrType =~ /Constructor$/) { 1746 if (!($attribute->signature->extendedAttributes->{"CustomGetter"} || 1747 $attribute->signature->extendedAttributes->{"V8CustomGetter"})) { 1748 $hasConstructors = 1; 1749 } 1750 next; 1751 } 1752 1753 if ($attrType eq "EventListener" && $interfaceName eq "DOMWindow") { 1754 $attribute->signature->extendedAttributes->{"v8OnProto"} = 1; 1755 } 1756 1757 # Attributes of type SerializedScriptValue are set in the 1758 # constructor and don't require callbacks. 1759 if ($attrType eq "SerializedScriptValue") { 1760 die "Only one attribute of type SerializedScriptValue supported" if $serializedAttribute; 1761 $implIncludes{"SerializedScriptValue.h"} = 1; 1762 $serializedAttribute = $attribute; 1763 next; 1764 } 1765 1766 # Do not generate accessor if this is a custom attribute. The 1767 # call will be forwarded to a hand-written accessor 1768 # implementation. 1769 if ($attribute->signature->extendedAttributes->{"Custom"} || 1770 $attribute->signature->extendedAttributes->{"V8Custom"}) { 1771 next; 1772 } 1773 1774 # Generate the accessor. 1775 if (!($attribute->signature->extendedAttributes->{"CustomGetter"} || 1776 $attribute->signature->extendedAttributes->{"V8CustomGetter"})) { 1777 GenerateNormalAttrGetter($attribute, $dataNode, $implClassName, $interfaceName); 1778 } 1779 if (!$attribute->signature->extendedAttributes->{"CustomSetter"} && 1780 !$attribute->signature->extendedAttributes->{"V8CustomSetter"} && 1781 !$attribute->signature->extendedAttributes->{"Replaceable"} && 1782 $attribute->type !~ /^readonly/ && 1783 !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) { 1784 GenerateNormalAttrSetter($attribute, $dataNode, $implClassName, $interfaceName); 1785 } 1786 } 1787 1788 if ($hasConstructors) { 1789 GenerateConstructorGetter($implClassName); 1790 } 1791 1792 $codeGenerator->LinkOverloadedFunctions($dataNode); 1793 1794 my $indexer; 1795 my $namedPropertyGetter; 1796 # Generate methods for functions. 1797 foreach my $function (@{$dataNode->functions}) { 1798 if (!($function->signature->extendedAttributes->{"Custom"} || $function->signature->extendedAttributes->{"V8Custom"})) { 1799 GenerateFunctionCallback($function, $dataNode, $implClassName); 1800 if ($function->{overloadIndex} > 1 && $function->{overloadIndex} == @{$function->{overloads}}) { 1801 GenerateOverloadedFunctionCallback($function, $dataNode, $implClassName); 1802 } 1803 } 1804 1805 if ($function->signature->name eq "item") { 1806 $indexer = $function->signature; 1807 } 1808 1809 if ($function->signature->name eq "namedItem") { 1810 $namedPropertyGetter = $function->signature; 1811 } 1812 1813 # If the function does not need domain security check, we need to 1814 # generate an access getter that returns different function objects 1815 # for different calling context. 1816 if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} || ($interfaceName eq "DOMWindow")) && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { 1817 GenerateDomainSafeFunctionGetter($function, $implClassName); 1818 } 1819 } 1820 1821 # Attributes 1822 my $attributes = $dataNode->attributes; 1823 1824 # For the DOMWindow interface we partition the attributes into the 1825 # ones that disallows shadowing and the rest. 1826 my @disallowsShadowing; 1827 # Also separate out attributes that are enabled at runtime so we can process them specially. 1828 my @enabledAtRuntime; 1829 my @normal; 1830 foreach my $attribute (@$attributes) { 1831 1832 if ($interfaceName eq "DOMWindow" && $attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) { 1833 push(@disallowsShadowing, $attribute); 1834 } elsif ($attribute->signature->extendedAttributes->{"EnabledAtRuntime"}) { 1835 push(@enabledAtRuntime, $attribute); 1836 } else { 1837 push(@normal, $attribute); 1838 } 1839 } 1840 $attributes = \@normal; 1841 # Put the attributes that disallow shadowing on the shadow object. 1842 if (@disallowsShadowing) { 1843 push(@implContent, "static const BatchedAttribute shadowAttrs[] = {\n"); 1844 GenerateBatchedAttributeData($dataNode, \@disallowsShadowing); 1845 push(@implContent, "};\n"); 1846 } 1847 1848 my $has_attributes = 0; 1849 if (@$attributes && (@$attributes > 1 || $$attributes[0]->signature->type ne "SerializedScriptValue")) { 1850 $has_attributes = 1; 1851 push(@implContent, "static const BatchedAttribute ${interfaceName}Attrs[] = {\n"); 1852 GenerateBatchedAttributeData($dataNode, $attributes); 1853 push(@implContent, "};\n"); 1854 } 1855 1856 # Setup table of standard callback functions 1857 $num_callbacks = 0; 1858 $has_callbacks = 0; 1859 foreach my $function (@{$dataNode->functions}) { 1860 # Only one table entry is needed for overloaded methods: 1861 next if $function->{overloadIndex} > 1; 1862 1863 my $attrExt = $function->signature->extendedAttributes; 1864 # Don't put any nonstandard functions into this table: 1865 if ($attrExt->{"V8OnInstance"}) { 1866 next; 1867 } 1868 if ($attrExt->{"ClassMethod"}) { 1869 next; 1870 } 1871 if ($attrExt->{"EnabledAtRuntime"} || RequiresCustomSignature($function) || $attrExt->{"V8DoNotCheckSignature"}) { 1872 next; 1873 } 1874 if ($attrExt->{"DoNotCheckDomainSecurity"} && 1875 ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { 1876 next; 1877 } 1878 if ($attrExt->{"DontEnum"} || $attrExt->{"V8ReadOnly"}) { 1879 next; 1880 } 1881 if (!$has_callbacks) { 1882 $has_callbacks = 1; 1883 push(@implContent, "static const BatchedCallback ${interfaceName}Callbacks[] = {\n"); 1884 } 1885 my $name = $function->signature->name; 1886 my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); 1887 push(@implContent, <<END); 1888 {"$name", $callback}, 1889 END 1890 $num_callbacks++; 1891 } 1892 push(@implContent, "};\n") if $has_callbacks; 1893 1894 # Setup constants 1895 my $has_constants = 0; 1896 if (@{$dataNode->constants}) { 1897 $has_constants = 1; 1898 push(@implContent, "static const BatchedConstant ${interfaceName}Consts[] = {\n"); 1899 } 1900 foreach my $constant (@{$dataNode->constants}) { 1901 my $name = $constant->name; 1902 my $value = $constant->value; 1903 # FIXME: we need the static_cast here only because of one constant, NodeFilter.idl 1904 # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF". It would be better if we 1905 # handled this here, and converted it to a -1 constant in the c++ output. 1906 push(@implContent, <<END); 1907 {"${name}", static_cast<signed int>($value)}, 1908 END 1909 } 1910 if ($has_constants) { 1911 push(@implContent, "};\n"); 1912 push(@implContent, $codeGenerator->GenerateCompileTimeCheckForEnumsIfNeeded($dataNode)); 1913 } 1914 1915 push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n"); 1916 1917 # In namespace WebCore, add generated implementation for 'CanBeConstructed'. 1918 if ($dataNode->extendedAttributes->{"CanBeConstructed"} && !$dataNode->extendedAttributes->{"CustomConstructor"} && !$dataNode->extendedAttributes->{"V8CustomConstructor"}) { 1919 my $v8ConstructFunction; 1920 my $callWith = $dataNode->extendedAttributes->{"CallWith"}; 1921 if ($callWith and $callWith eq "ScriptExecutionContext") { 1922 $v8ConstructFunction = "constructDOMObjectWithScriptExecutionContext"; 1923 } else { 1924 $v8ConstructFunction = "constructDOMObject"; 1925 } 1926 push(@implContent, <<END); 1927 v8::Handle<v8::Value> ${className}::constructorCallback(const v8::Arguments& args) 1928 { 1929 INC_STATS("DOM.${interfaceName}.Contructor"); 1930 return V8Proxy::${v8ConstructFunction}<$interfaceName>(args, &info); 1931 } 1932 END 1933 } 1934 1935 my $access_check = ""; 1936 if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !($interfaceName eq "DOMWindow")) { 1937 $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));"; 1938 } 1939 1940 # For the DOMWindow interface, generate the shadow object template 1941 # configuration method. 1942 if ($implClassName eq "DOMWindow") { 1943 push(@implContent, <<END); 1944 static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) 1945 { 1946 batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs)); 1947 1948 // Install a security handler with V8. 1949 templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info)); 1950 templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount); 1951 return templ; 1952 } 1953 END 1954 } 1955 1956 if (!$parentClassTemplate) { 1957 $parentClassTemplate = "v8::Persistent<v8::FunctionTemplate>()"; 1958 } 1959 1960 # Generate the template configuration method 1961 push(@implContent, <<END); 1962 static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) 1963 { 1964 v8::Local<v8::Signature> defaultSignature = configureTemplate(desc, \"${visibleInterfaceName}\", $parentClassTemplate, V8${interfaceName}::internalFieldCount, 1965 END 1966 # Set up our attributes if we have them 1967 if ($has_attributes) { 1968 push(@implContent, <<END); 1969 ${interfaceName}Attrs, WTF_ARRAY_LENGTH(${interfaceName}Attrs), 1970 END 1971 } else { 1972 push(@implContent, <<END); 1973 0, 0, 1974 END 1975 } 1976 1977 if ($has_callbacks) { 1978 push(@implContent, <<END); 1979 ${interfaceName}Callbacks, WTF_ARRAY_LENGTH(${interfaceName}Callbacks)); 1980 END 1981 } else { 1982 push(@implContent, <<END); 1983 0, 0); 1984 UNUSED_PARAM(defaultSignature); // In some cases, it will not be used. 1985 END 1986 $implIncludes{"wtf/UnusedParam.h"} = 1; 1987 } 1988 1989 if ($dataNode->extendedAttributes->{"CustomConstructor"} || $dataNode->extendedAttributes->{"V8CustomConstructor"} || $dataNode->extendedAttributes->{"CanBeConstructed"}) { 1990 push(@implContent, <<END); 1991 desc->SetCallHandler(V8${interfaceName}::constructorCallback); 1992 END 1993 } 1994 1995 if ($access_check or @enabledAtRuntime or @{$dataNode->functions} or $has_constants) { 1996 push(@implContent, <<END); 1997 v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); 1998 v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate(); 1999 END 2000 } 2001 2002 push(@implContent, " $access_check\n"); 2003 2004 # Setup the enable-at-runtime attrs if we have them 2005 foreach my $runtime_attr (@enabledAtRuntime) { 2006 my $enable_function = GetRuntimeEnableFunctionName($runtime_attr->signature); 2007 my $conditionalString = GenerateConditionalString($runtime_attr->signature); 2008 push(@implContent, "\n#if ${conditionalString}\n") if $conditionalString; 2009 push(@implContent, " if (${enable_function}()) {\n"); 2010 push(@implContent, " static const BatchedAttribute attrData =\\\n"); 2011 GenerateSingleBatchedAttribute($interfaceName, $runtime_attr, ";", " "); 2012 push(@implContent, <<END); 2013 configureAttribute(instance, proto, attrData); 2014 } 2015 END 2016 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; 2017 } 2018 2019 GenerateImplementationIndexer($dataNode, $indexer); 2020 GenerateImplementationNamedPropertyGetter($dataNode, $namedPropertyGetter); 2021 GenerateImplementationCustomCall($dataNode); 2022 GenerateImplementationMasqueradesAsUndefined($dataNode); 2023 2024 # Define our functions with Set() or SetAccessor() 2025 $total_functions = 0; 2026 foreach my $function (@{$dataNode->functions}) { 2027 # Only one accessor is needed for overloaded methods: 2028 next if $function->{overloadIndex} > 1; 2029 2030 $total_functions++; 2031 my $attrExt = $function->signature->extendedAttributes; 2032 my $name = $function->signature->name; 2033 2034 my $property_attributes = "v8::DontDelete"; 2035 if ($attrExt->{"DontEnum"}) { 2036 $property_attributes .= " | v8::DontEnum"; 2037 } 2038 if ($attrExt->{"V8ReadOnly"}) { 2039 $property_attributes .= " | v8::ReadOnly"; 2040 } 2041 2042 my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; 2043 2044 my $template = "proto"; 2045 if ($attrExt->{"V8OnInstance"}) { 2046 $template = "instance"; 2047 } 2048 if ($attrExt->{"ClassMethod"}) { 2049 $template = "desc"; 2050 } 2051 2052 my $conditional = ""; 2053 if ($attrExt->{"EnabledAtRuntime"}) { 2054 # Only call Set()/SetAccessor() if this method should be enabled 2055 $enable_function = GetRuntimeEnableFunctionName($function->signature); 2056 $conditional = "if (${enable_function}())\n "; 2057 } 2058 2059 if ($attrExt->{"DoNotCheckDomainSecurity"} && 2060 ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { 2061 # Mark the accessor as ReadOnly and set it on the proto object so 2062 # it can be shadowed. This is really a hack to make it work. 2063 # There are several sceneria to call into the accessor: 2064 # 1) from the same domain: "window.open": 2065 # the accessor finds the DOM wrapper in the proto chain; 2066 # 2) from the same domain: "window.__proto__.open": 2067 # the accessor will NOT find a DOM wrapper in the prototype chain 2068 # 3) from another domain: "window.open": 2069 # the access find the DOM wrapper in the prototype chain 2070 # "window.__proto__.open" from another domain will fail when 2071 # accessing '__proto__' 2072 # 2073 # The solution is very hacky and fragile, it really needs to be replaced 2074 # by a better solution. 2075 $property_attributes .= " | v8::ReadOnly"; 2076 push(@implContent, <<END); 2077 2078 // $commentInfo 2079 ${conditional}$template->SetAccessor(v8::String::New("$name"), ${interfaceName}Internal::${name}AttrGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes)); 2080 END 2081 $num_callbacks++; 2082 next; 2083 } 2084 2085 my $signature = "defaultSignature"; 2086 if ($attrExt->{"V8DoNotCheckSignature"} || $attrExt->{"ClassMethod"}) { 2087 $signature = "v8::Local<v8::Signature>()"; 2088 } 2089 2090 if (RequiresCustomSignature($function)) { 2091 $signature = "${name}Signature"; 2092 push(@implContent, "\n // Custom Signature '$name'\n", CreateCustomSignature($function)); 2093 } 2094 2095 # Normal function call is a template 2096 my $callback = GetFunctionTemplateCallbackName($function, $interfaceName); 2097 2098 if ($property_attributes eq "v8::DontDelete") { 2099 $property_attributes = ""; 2100 } else { 2101 $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)"; 2102 } 2103 2104 if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") { 2105 # Standard type of callback, already created in the batch, so skip it here. 2106 next; 2107 } 2108 2109 push(@implContent, <<END); 2110 ${conditional}$template->Set(v8::String::New("$name"), v8::FunctionTemplate::New($callback, v8::Handle<v8::Value>(), ${signature})$property_attributes); 2111 END 2112 $num_callbacks++; 2113 } 2114 2115 die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions; 2116 2117 if ($has_constants) { 2118 push(@implContent, <<END); 2119 batchConfigureConstants(desc, proto, ${interfaceName}Consts, WTF_ARRAY_LENGTH(${interfaceName}Consts)); 2120 END 2121 } 2122 2123 # Special cases 2124 if ($interfaceName eq "DOMWindow") { 2125 push(@implContent, <<END); 2126 2127 proto->SetInternalFieldCount(V8DOMWindow::internalFieldCount); 2128 desc->SetHiddenPrototype(true); 2129 instance->SetInternalFieldCount(V8DOMWindow::internalFieldCount); 2130 // Set access check callbacks, but turned off initially. 2131 // When a context is detached from a frame, turn on the access check. 2132 // Turning on checks also invalidates inline caches of the object. 2133 instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false); 2134 END 2135 } 2136 if ($interfaceName eq "HTMLDocument") { 2137 push(@implContent, <<END); 2138 desc->SetHiddenPrototype(true); 2139 END 2140 } 2141 if ($interfaceName eq "Location") { 2142 push(@implContent, <<END); 2143 2144 // For security reasons, these functions are on the instance instead 2145 // of on the prototype object to ensure that they cannot be overwritten. 2146 instance->SetAccessor(v8::String::New("reload"), V8Location::reloadAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); 2147 instance->SetAccessor(v8::String::New("replace"), V8Location::replaceAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); 2148 instance->SetAccessor(v8::String::New("assign"), V8Location::assignAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)); 2149 END 2150 } 2151 2152 my $nativeType = GetNativeTypeForConversions($dataNode, $interfaceName); 2153 push(@implContent, <<END); 2154 2155 // Custom toString template 2156 desc->Set(getToStringName(), getToStringTemplate()); 2157 return desc; 2158 } 2159 2160 v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() 2161 { 2162 static v8::Persistent<v8::FunctionTemplate> ${className}RawCache = createRawTemplate(); 2163 return ${className}RawCache; 2164 } 2165 2166 v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate()\ 2167 { 2168 static v8::Persistent<v8::FunctionTemplate> ${className}Cache = Configure${className}Template(GetRawTemplate()); 2169 return ${className}Cache; 2170 } 2171 2172 bool ${className}::HasInstance(v8::Handle<v8::Value> value) 2173 { 2174 return GetRawTemplate()->HasInstance(value); 2175 } 2176 2177 END 2178 2179 if (IsActiveDomType($interfaceName)) { 2180 # MessagePort is handled like an active dom object even though it doesn't inherit 2181 # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject. 2182 my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)"; 2183 push(@implContent, <<END); 2184 ActiveDOMObject* ${className}::toActiveDOMObject(v8::Handle<v8::Object> object) 2185 { 2186 return ${returnValue}; 2187 } 2188 END 2189 } 2190 2191 if ($implClassName eq "DOMWindow") { 2192 push(@implContent, <<END); 2193 v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() 2194 { 2195 static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObjectCache; 2196 if (V8DOMWindowShadowObjectCache.IsEmpty()) { 2197 V8DOMWindowShadowObjectCache = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); 2198 ConfigureShadowObjectTemplate(V8DOMWindowShadowObjectCache); 2199 } 2200 return V8DOMWindowShadowObjectCache; 2201 } 2202 END 2203 } 2204 2205 GenerateToV8Converters($dataNode, $interfaceName, $className, $nativeType, $serializedAttribute); 2206 2207 push(@implContent, <<END); 2208 2209 void ${className}::derefObject(void* object) 2210 { 2211 END 2212 2213 if (IsRefPtrType($interfaceName)) { 2214 push(@implContent, <<END); 2215 static_cast<${nativeType}*>(object)->deref(); 2216 END 2217 } 2218 2219 push(@implContent, <<END); 2220 } 2221 2222 } // namespace WebCore 2223 END 2224 2225 my $conditionalString = GenerateConditionalString($dataNode); 2226 push(@implContent, "\n#endif // ${conditionalString}\n") if $conditionalString; 2227 2228 # We've already added the header for this file in implFixedHeader, so remove 2229 # it from implIncludes to ensure we don't #include it twice. 2230 delete $implIncludes{"${className}.h"}; 2231 } 2232 2233 sub GenerateHeaderContentHeader 2234 { 2235 my $dataNode = shift; 2236 my $className = "V8" . $dataNode->name; 2237 my $conditionalString = GenerateConditionalString($dataNode); 2238 2239 my @headerContentHeader = split("\r", $headerTemplate); 2240 2241 push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString; 2242 push(@headerContentHeader, "\n#ifndef ${className}" . "_h"); 2243 push(@headerContentHeader, "\n#define ${className}" . "_h\n\n"); 2244 return @headerContentHeader; 2245 } 2246 2247 sub GenerateImplementationContentHeader 2248 { 2249 my $dataNode = shift; 2250 my $className = "V8" . $dataNode->name; 2251 my $conditionalString = GenerateConditionalString($dataNode); 2252 2253 my @implContentHeader = split("\r", $headerTemplate); 2254 2255 push(@implContentHeader, "\n#include \"config.h\"\n"); 2256 push(@implContentHeader, "#include \"${className}.h\"\n\n"); 2257 push(@implContentHeader, "#if ${conditionalString}\n\n") if $conditionalString; 2258 return @implContentHeader; 2259 } 2260 2261 sub GenerateCallbackHeader 2262 { 2263 my $object = shift; 2264 my $dataNode = shift; 2265 2266 my $interfaceName = $dataNode->name; 2267 my $className = "V8$interfaceName"; 2268 2269 2270 # - Add default header template 2271 push(@headerContent, GenerateHeaderContentHeader($dataNode)); 2272 2273 my @unsortedIncludes = (); 2274 push(@unsortedIncludes, "#include \"ActiveDOMCallback.h\""); 2275 push(@unsortedIncludes, "#include \"$interfaceName.h\""); 2276 push(@unsortedIncludes, "#include \"WorldContextHandle.h\""); 2277 push(@unsortedIncludes, "#include <v8.h>"); 2278 push(@unsortedIncludes, "#include <wtf/Forward.h>"); 2279 push(@headerContent, join("\n", sort @unsortedIncludes)); 2280 2281 push(@headerContent, "\n\nnamespace WebCore {\n\n"); 2282 push(@headerContent, "class ScriptExecutionContext;\n\n"); 2283 push(@headerContent, "class $className : public $interfaceName, public ActiveDOMCallback {\n"); 2284 2285 push(@headerContent, <<END); 2286 public: 2287 static PassRefPtr<${className}> create(v8::Local<v8::Value> value, ScriptExecutionContext* context) 2288 { 2289 ASSERT(value->IsObject()); 2290 ASSERT(context); 2291 return adoptRef(new ${className}(value->ToObject(), context)); 2292 } 2293 2294 virtual ~${className}(); 2295 2296 END 2297 2298 # Functions 2299 my $numFunctions = @{$dataNode->functions}; 2300 if ($numFunctions > 0) { 2301 push(@headerContent, " // Functions\n"); 2302 foreach my $function (@{$dataNode->functions}) { 2303 my @params = @{$function->parameters}; 2304 if (!$function->signature->extendedAttributes->{"Custom"} && 2305 !(GetNativeType($function->signature->type) eq "bool")) { 2306 push(@headerContent, " COMPILE_ASSERT(false)"); 2307 } 2308 2309 push(@headerContent, " virtual " . GetNativeTypeForCallbacks($function->signature->type) . " " . $function->signature->name . "("); 2310 2311 my @args = (); 2312 foreach my $param (@params) { 2313 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); 2314 } 2315 push(@headerContent, join(", ", @args)); 2316 push(@headerContent, ");\n"); 2317 } 2318 } 2319 2320 push(@headerContent, <<END); 2321 2322 private: 2323 ${className}(v8::Local<v8::Object>, ScriptExecutionContext*); 2324 2325 v8::Persistent<v8::Object> m_callback; 2326 WorldContextHandle m_worldContext; 2327 }; 2328 2329 END 2330 2331 push(@headerContent, "}\n\n"); 2332 push(@headerContent, "#endif // $className" . "_h\n\n"); 2333 2334 my $conditionalString = GenerateConditionalString($dataNode); 2335 push(@headerContent, "#endif // ${conditionalString}\n") if $conditionalString; 2336 } 2337 2338 sub GenerateCallbackImplementation 2339 { 2340 my $object = shift; 2341 my $dataNode = shift; 2342 my $interfaceName = $dataNode->name; 2343 my $className = "V8$interfaceName"; 2344 2345 # - Add default header template 2346 push(@implFixedHeader, GenerateImplementationContentHeader($dataNode)); 2347 2348 $implIncludes{"ScriptExecutionContext.h"} = 1; 2349 $implIncludes{"V8Binding.h"} = 1; 2350 $implIncludes{"V8CustomVoidCallback.h"} = 1; 2351 $implIncludes{"V8Proxy.h"} = 1; 2352 2353 push(@implContent, "#include <wtf/Assertions.h>\n\n"); 2354 push(@implContent, "namespace WebCore {\n\n"); 2355 push(@implContent, <<END); 2356 ${className}::${className}(v8::Local<v8::Object> callback, ScriptExecutionContext* context) 2357 : ActiveDOMCallback(context) 2358 , m_callback(v8::Persistent<v8::Object>::New(callback)) 2359 , m_worldContext(UseCurrentWorld) 2360 { 2361 } 2362 2363 ${className}::~${className}() 2364 { 2365 m_callback.Dispose(); 2366 } 2367 2368 END 2369 2370 # Functions 2371 my $numFunctions = @{$dataNode->functions}; 2372 if ($numFunctions > 0) { 2373 push(@implContent, "// Functions\n"); 2374 foreach my $function (@{$dataNode->functions}) { 2375 my @params = @{$function->parameters}; 2376 if ($function->signature->extendedAttributes->{"Custom"} || 2377 !(GetNativeTypeForCallbacks($function->signature->type) eq "bool")) { 2378 next; 2379 } 2380 2381 AddIncludesForType($function->signature->type); 2382 push(@implContent, "\n" . GetNativeTypeForCallbacks($function->signature->type) . " ${className}::" . $function->signature->name . "("); 2383 2384 my @args = (); 2385 foreach my $param (@params) { 2386 AddIncludesForType($param->type); 2387 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); 2388 } 2389 push(@implContent, join(", ", @args)); 2390 2391 push(@implContent, ")\n"); 2392 push(@implContent, "{\n"); 2393 push(@implContent, " if (!canInvokeCallback())\n"); 2394 push(@implContent, " return true;\n\n"); 2395 push(@implContent, " v8::HandleScope handleScope;\n\n"); 2396 push(@implContent, " v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_worldContext);\n"); 2397 push(@implContent, " if (v8Context.IsEmpty())\n"); 2398 push(@implContent, " return true;\n\n"); 2399 push(@implContent, " v8::Context::Scope scope(v8Context);\n\n"); 2400 2401 @args = (); 2402 foreach my $param (@params) { 2403 my $paramName = $param->name; 2404 push(@implContent, " v8::Handle<v8::Value> ${paramName}Handle = " . NativeToJSValue($param, $paramName) . ";\n"); 2405 push(@implContent, " if (${paramName}Handle.IsEmpty()) {\n"); 2406 push(@implContent, " CRASH();\n"); 2407 push(@implContent, " return true;\n"); 2408 push(@implContent, " }\n"); 2409 push(@args, " ${paramName}Handle"); 2410 } 2411 2412 if (scalar(@args) > 0) { 2413 push(@implContent, "\n v8::Handle<v8::Value> argv[] = {\n"); 2414 push(@implContent, join(",\n", @args)); 2415 push(@implContent, "\n };\n\n"); 2416 } else { 2417 push(@implContent, "\n v8::Handle<v8::Value> *argv = 0;\n\n"); 2418 } 2419 push(@implContent, " bool callbackReturnValue = false;\n"); 2420 push(@implContent, " return !invokeCallback(m_callback, " . scalar(@params) . ", argv, callbackReturnValue, scriptExecutionContext());\n"); 2421 push(@implContent, "}\n"); 2422 } 2423 } 2424 2425 push(@implContent, "\n} // namespace WebCore\n\n"); 2426 2427 my $conditionalString = GenerateConditionalString($dataNode); 2428 push(@implContent, "#endif // ${conditionalString}\n") if $conditionalString; 2429 } 2430 2431 sub GenerateToV8Converters 2432 { 2433 my $dataNode = shift; 2434 my $interfaceName = shift; 2435 my $className = shift; 2436 my $nativeType = shift; 2437 my $serializedAttribute = shift; 2438 2439 my $domMapFunction = GetDomMapFunction($dataNode, $interfaceName); 2440 my $forceNewObjectInput = IsDOMNodeType($interfaceName) ? ", bool forceNewObject" : ""; 2441 my $forceNewObjectCall = IsDOMNodeType($interfaceName) ? ", forceNewObject" : ""; 2442 2443 push(@implContent, <<END); 2444 2445 v8::Handle<v8::Object> ${className}::wrapSlow(${nativeType}* impl) 2446 { 2447 v8::Handle<v8::Object> wrapper; 2448 V8Proxy* proxy = 0; 2449 END 2450 2451 if (IsNodeSubType($dataNode)) { 2452 push(@implContent, <<END); 2453 if (impl->document()) { 2454 proxy = V8Proxy::retrieve(impl->document()->frame()); 2455 if (proxy && static_cast<Node*>(impl->document()) == static_cast<Node*>(impl)) { 2456 if (proxy->windowShell()->initContextIfNeeded()) { 2457 // initContextIfNeeded may have created a wrapper for the object, retry from the start. 2458 return ${className}::wrap(impl); 2459 } 2460 } 2461 } 2462 2463 END 2464 } 2465 2466 if (IsNodeSubType($dataNode)) { 2467 push(@implContent, <<END); 2468 2469 v8::Handle<v8::Context> context; 2470 if (proxy) 2471 context = proxy->context(); 2472 2473 // Enter the node's context and create the wrapper in that context. 2474 if (!context.IsEmpty()) 2475 context->Enter(); 2476 END 2477 } 2478 2479 push(@implContent, <<END); 2480 wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl); 2481 END 2482 if (IsNodeSubType($dataNode)) { 2483 push(@implContent, <<END); 2484 // Exit the node's context if it was entered. 2485 if (!context.IsEmpty()) 2486 context->Exit(); 2487 END 2488 } 2489 2490 push(@implContent, <<END); 2491 if (wrapper.IsEmpty()) 2492 return wrapper; 2493 END 2494 push(@implContent, "\n impl->ref();\n") if IsRefPtrType($interfaceName); 2495 2496 # Eagerly deserialize attributes of type SerializedScriptValue 2497 # while we're in the right context. 2498 if ($serializedAttribute) { 2499 die "Attribute of type SerializedScriptValue expected" if $serializedAttribute->signature->type ne "SerializedScriptValue"; 2500 my $attrName = $serializedAttribute->signature->name; 2501 my $attrAttr = "v8::DontDelete"; 2502 if ($serializedAttribute->type =~ /^readonly/) { 2503 $attrAttr .= " | v8::ReadOnly"; 2504 } 2505 $attrAttr = "static_cast<v8::PropertyAttribute>($attrAttr)"; 2506 my $getterFunc = $codeGenerator->WK_lcfirst($attrName); 2507 push(@implContent, <<END); 2508 SerializedScriptValue::deserializeAndSetProperty(wrapper, "${attrName}", ${attrAttr}, impl->${getterFunc}()); 2509 END 2510 } 2511 2512 push(@implContent, <<END); 2513 v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper); 2514 END 2515 if (IsNodeSubType($dataNode)) { 2516 push(@implContent, <<END); 2517 wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId); 2518 END 2519 } 2520 push(@implContent, <<END); 2521 ${domMapFunction}.set(impl, wrapperHandle); 2522 END 2523 2524 push(@implContent, <<END); 2525 return wrapper; 2526 } 2527 END 2528 } 2529 2530 sub HasCustomToV8Implementation { 2531 # FIXME: This subroutine is lame. Probably should be an .idl attribute (CustomToV8)? 2532 $dataNode = shift; 2533 $interfaceName = shift; 2534 2535 # We generate a custom converter (but JSC doesn't) for the following: 2536 return 1 if $interfaceName eq "CSSStyleSheet"; 2537 return 1 if $interfaceName eq "CanvasPixelArray"; 2538 return 1 if $interfaceName eq "DOMStringMap"; 2539 return 1 if $interfaceName eq "DOMWindow"; 2540 return 1 if $interfaceName eq "DOMTokenList"; 2541 return 1 if $interfaceName eq "Element"; 2542 return 1 if $interfaceName eq "HTMLDocument"; 2543 return 1 if $interfaceName eq "HTMLElement"; 2544 return 1 if $interfaceName eq "Location"; 2545 return 1 if $interfaceName eq "NamedNodeMap"; 2546 return 1 if $interfaceName eq "SVGDocument"; 2547 return 1 if $interfaceName eq "SVGElement"; 2548 return 1 if $interfaceName eq "ScriptProfile"; 2549 return 1 if $interfaceName eq "ScriptProfileNode"; 2550 return 1 if $interfaceName eq "WorkerContext"; 2551 # We don't generate a custom converter (but JSC does) for the following: 2552 return 0 if $interfaceName eq "AbstractWorker"; 2553 return 0 if $interfaceName eq "CanvasRenderingContext"; 2554 return 0 if $interfaceName eq "SVGElementInstance"; 2555 return 0 if $interfaceName eq "NodeList"; 2556 2557 # For everything else, do what JSC does. 2558 return $dataNode->extendedAttributes->{"CustomToJS"}; 2559 } 2560 2561 sub GetDomMapFunction 2562 { 2563 my $dataNode = shift; 2564 my $type = shift; 2565 return "getDOMSVGElementInstanceMap()" if $type eq "SVGElementInstance"; 2566 return "getDOMNodeMap()" if ($dataNode && IsNodeSubType($dataNode)); 2567 return "getActiveDOMObjectMap()" if IsActiveDomType($type); 2568 return "getDOMObjectMap()"; 2569 } 2570 2571 sub IsActiveDomType 2572 { 2573 # FIXME: Consider making this an .idl attribute. 2574 my $type = shift; 2575 return 1 if $type eq "EventSource"; 2576 return 1 if $type eq "MessagePort"; 2577 return 1 if $type eq "XMLHttpRequest"; 2578 return 1 if $type eq "WebSocket"; 2579 return 1 if $type eq "Worker"; 2580 return 1 if $type eq "SharedWorker"; 2581 return 1 if $type eq "IDBRequest"; 2582 return 1 if $type eq "IDBTransaction"; 2583 return 1 if $type eq "FileReader"; 2584 return 1 if $type eq "FileWriter"; 2585 return 0; 2586 } 2587 2588 sub GetNativeTypeForConversions 2589 { 2590 my $dataNode = shift; 2591 my $type = shift; 2592 2593 $type = $codeGenerator->GetSVGTypeNeedingTearOff($type) if $codeGenerator->IsSVGTypeNeedingTearOff($type); 2594 return $type; 2595 } 2596 2597 sub GenerateFunctionCallString() 2598 { 2599 my $function = shift; 2600 my $numberOfParameters = shift; 2601 my $indent = shift; 2602 my $implClassName = shift; 2603 2604 my $name = $function->signature->name; 2605 my $returnType = GetTypeFromSignature($function->signature); 2606 my $nativeReturnType = GetNativeType($returnType, 0); 2607 my $result = ""; 2608 2609 my $isSVGTearOffType = ($codeGenerator->IsSVGTypeNeedingTearOff($returnType) and not $implClassName =~ /List$/); 2610 $nativeReturnType = $codeGenerator->GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType; 2611 2612 if ($function->signature->extendedAttributes->{"v8implname"}) { 2613 $name = $function->signature->extendedAttributes->{"v8implname"}; 2614 } 2615 2616 if ($function->signature->extendedAttributes->{"ImplementationFunction"}) { 2617 $name = $function->signature->extendedAttributes->{"ImplementationFunction"}; 2618 } 2619 2620 my $functionString = "imp->${name}("; 2621 if ($function->signature->extendedAttributes->{"ClassMethod"}) { 2622 $functionString = "${implClassName}::${name}("; 2623 } 2624 2625 my $index = 0; 2626 my $hasScriptState = 0; 2627 2628 my $callWith = $function->signature->extendedAttributes->{"CallWith"}; 2629 if ($callWith) { 2630 my $callWithArg = "COMPILE_ASSERT(false)"; 2631 if ($callWith eq "DynamicFrame") { 2632 $result .= $indent . "Frame* enteredFrame = V8Proxy::retrieveFrameForEnteredContext();\n"; 2633 $result .= $indent . "if (!enteredFrame)\n"; 2634 $result .= $indent . " return v8::Undefined();\n"; 2635 $callWithArg = "enteredFrame"; 2636 } elsif ($callWith eq "ScriptState") { 2637 $result .= $indent . "EmptyScriptState state;\n"; 2638 $callWithArg = "&state"; 2639 $hasScriptState = 1; 2640 } elsif ($callWith eq "ScriptExecutionContext") { 2641 $result .= $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n"; 2642 $result .= $indent . "if (!scriptContext)\n"; 2643 $result .= $indent . " return v8::Undefined();\n"; 2644 $callWithArg = "scriptContext"; 2645 } 2646 $functionString .= ", " if $index; 2647 $functionString .= $callWithArg; 2648 $index++; 2649 $numberOfParameters++ 2650 } 2651 2652 foreach my $parameter (@{$function->parameters}) { 2653 if ($index eq $numberOfParameters) { 2654 last; 2655 } 2656 $functionString .= ", " if $index; 2657 my $paramName = $parameter->name; 2658 my $paramType = $parameter->type; 2659 2660 if ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") { 2661 $functionString .= "$paramName.get()"; 2662 } elsif ($codeGenerator->IsSVGTypeNeedingTearOff($parameter->type) and not $implClassName =~ /List$/) { 2663 $functionString .= "$paramName->propertyReference()"; 2664 $result .= $indent . "if (!$paramName) {\n"; 2665 $result .= $indent . " V8Proxy::setDOMException(WebCore::TYPE_MISMATCH_ERR);\n"; 2666 $result .= $indent . " return v8::Handle<v8::Value>();\n"; 2667 $result .= $indent . "}\n"; 2668 } elsif ($parameter->type eq "SVGMatrix" and $implClassName eq "SVGTransformList") { 2669 $functionString .= "$paramName.get()"; 2670 } else { 2671 $functionString .= $paramName; 2672 } 2673 $index++; 2674 } 2675 2676 if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { 2677 $functionString .= ", " if $index; 2678 $functionString .= "scriptArguments, callStack"; 2679 $index += 2; 2680 } 2681 2682 if ($function->signature->extendedAttributes->{"NeedsUserGestureCheck"}) { 2683 $functionString .= ", " if $index; 2684 # FIXME: We need to pass DOMWrapperWorld as a parameter. 2685 # See http://trac.webkit.org/changeset/54182 2686 $functionString .= "processingUserGesture()"; 2687 $index++; 2688 } 2689 2690 if (@{$function->raisesExceptions}) { 2691 $functionString .= ", " if $index; 2692 $functionString .= "ec"; 2693 $index++; 2694 } 2695 $functionString .= ")"; 2696 2697 my $return = "result"; 2698 my $returnIsRef = IsRefPtrType($returnType); 2699 2700 if ($returnType eq "void") { 2701 $result .= $indent . "$functionString;\n"; 2702 } elsif ($hasScriptState or @{$function->raisesExceptions}) { 2703 $result .= $indent . $nativeReturnType . " result = $functionString;\n"; 2704 } else { 2705 # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary 2706 $return = $functionString; 2707 $returnIsRef = 0; 2708 2709 if ($implClassName eq "SVGTransformList" and IsRefPtrType($returnType)) { 2710 $return = "WTF::getPtr(" . $return . ")"; 2711 } 2712 } 2713 2714 if (@{$function->raisesExceptions}) { 2715 $result .= $indent . "if (UNLIKELY(ec))\n"; 2716 $result .= $indent . " goto fail;\n"; 2717 } 2718 2719 if ($hasScriptState) { 2720 $result .= $indent . "if (state.hadException())\n"; 2721 $result .= $indent . " return throwError(state.exception());\n" 2722 } 2723 2724 if ($isSVGTearOffType) { 2725 $implIncludes{"V8$returnType.h"} = 1; 2726 $implIncludes{"SVGPropertyTearOff.h"} = 1; 2727 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($returnType); 2728 $result .= $indent . "return toV8(WTF::getPtr(${svgNativeType}::create($return)));\n"; 2729 return $result; 2730 } 2731 2732 # If the implementing class is a POD type, commit changes 2733 if ($codeGenerator->IsSVGTypeNeedingTearOff($implClassName) and not $implClassName =~ /List$/) { 2734 $result .= $indent . "wrapper->commitChange();\n"; 2735 } 2736 2737 $return .= ".release()" if ($returnIsRef); 2738 $result .= $indent . ReturnNativeToJSValue($function->signature, $return, $indent) . ";\n"; 2739 2740 return $result; 2741 } 2742 2743 2744 sub GetTypeFromSignature 2745 { 2746 my $signature = shift; 2747 2748 return $codeGenerator->StripModule($signature->type); 2749 } 2750 2751 2752 sub GetNativeTypeFromSignature 2753 { 2754 my $signature = shift; 2755 my $parameterIndex = shift; 2756 2757 my $type = GetTypeFromSignature($signature); 2758 2759 if ($type eq "unsigned long" and $signature->extendedAttributes->{"IsIndex"}) { 2760 # Special-case index arguments because we need to check that they aren't < 0. 2761 return "int"; 2762 } 2763 2764 $type = GetNativeType($type, $parameterIndex >= 0 ? 1 : 0); 2765 2766 if ($parameterIndex >= 0 && $type eq "V8Parameter") { 2767 my $mode = ""; 2768 if ($signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}) { 2769 $mode = "WithUndefinedOrNullCheck"; 2770 } elsif ($signature->extendedAttributes->{"ConvertNullToNullString"} || $signature->extendedAttributes->{"Reflect"}) { 2771 $mode = "WithNullCheck"; 2772 } 2773 $type .= "<$mode>"; 2774 } 2775 2776 return $type; 2777 } 2778 2779 sub IsRefPtrType 2780 { 2781 my $type = shift; 2782 2783 return 0 if $type eq "boolean"; 2784 return 0 if $type eq "float"; 2785 return 0 if $type eq "int"; 2786 return 0 if $type eq "Date"; 2787 return 0 if $type eq "DOMString"; 2788 return 0 if $type eq "double"; 2789 return 0 if $type eq "short"; 2790 return 0 if $type eq "long"; 2791 return 0 if $type eq "unsigned"; 2792 return 0 if $type eq "unsigned long"; 2793 return 0 if $type eq "unsigned short"; 2794 2795 return 1; 2796 } 2797 2798 sub GetNativeType 2799 { 2800 my $type = shift; 2801 my $isParameter = shift; 2802 2803 my $svgNativeType = $codeGenerator->GetSVGTypeNeedingTearOff($type); 2804 if ($svgNativeType) { 2805 if ($svgNativeType =~ /List$/) { 2806 return "${svgNativeType}*"; 2807 } else { 2808 return "RefPtr<${svgNativeType} >"; 2809 } 2810 } 2811 2812 if ($type eq "float" or $type eq "double") { 2813 return $type; 2814 } 2815 2816 return "V8Parameter" if ($type eq "DOMString" or $type eq "DOMUserData") and $isParameter; 2817 return "int" if $type eq "int"; 2818 return "int" if $type eq "short" or $type eq "unsigned short"; 2819 return "unsigned" if $type eq "unsigned long"; 2820 return "int" if $type eq "long"; 2821 return "long long" if $type eq "long long"; 2822 return "unsigned long long" if $type eq "unsigned long long"; 2823 return "bool" if $type eq "boolean"; 2824 return "String" if $type eq "DOMString"; 2825 return "Range::CompareHow" if $type eq "CompareHow"; 2826 return "DOMTimeStamp" if $type eq "DOMTimeStamp"; 2827 return "unsigned" if $type eq "unsigned int"; 2828 return "Node*" if $type eq "EventTarget" and $isParameter; 2829 return "double" if $type eq "Date"; 2830 return "ScriptValue" if $type eq "DOMObject"; 2831 return "OptionsObject" if $type eq "OptionsObject"; 2832 2833 return "String" if $type eq "DOMUserData"; # FIXME: Temporary hack? 2834 2835 # temporary hack 2836 return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; 2837 2838 return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue"; 2839 2840 return "RefPtr<IDBKey>" if $type eq "IDBKey"; 2841 2842 # necessary as resolvers could be constructed on fly. 2843 return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver"; 2844 2845 return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; 2846 2847 return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener"; 2848 2849 return "PassRefPtr<DOMStringList>" if $type eq "DOMStringList" and $isParameter; 2850 return "RefPtr<DOMStringList>" if $type eq "DOMStringList"; 2851 2852 # Default, assume native type is a pointer with same type name as idl type 2853 return "${type}*"; 2854 } 2855 2856 sub GetNativeTypeForCallbacks 2857 { 2858 my $type = shift; 2859 return "const String&" if $type eq "DOMString"; 2860 2861 # Callbacks use raw pointers, so pass isParameter = 1 2862 return GetNativeType($type, 1); 2863 } 2864 2865 sub TranslateParameter 2866 { 2867 my $signature = shift; 2868 2869 # The IDL uses some pseudo-types which don't really exist. 2870 if ($signature->type eq "TimeoutHandler") { 2871 $signature->type("DOMString"); 2872 } 2873 } 2874 2875 sub TypeCanFailConversion 2876 { 2877 my $signature = shift; 2878 2879 my $type = GetTypeFromSignature($signature); 2880 2881 $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr"; 2882 return 1 if $type eq "Attr"; 2883 return 1 if $type eq "VoidCallback"; 2884 return 1 if $type eq "IDBKey"; 2885 return 0; 2886 } 2887 2888 sub JSValueToNative 2889 { 2890 my $signature = shift; 2891 my $value = shift; 2892 2893 my $type = GetTypeFromSignature($signature); 2894 2895 return "$value" if $type eq "JSObject"; 2896 return "$value->BooleanValue()" if $type eq "boolean"; 2897 return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double"; 2898 2899 return "toInt32($value)" if $type eq "long" or $type eq "short"; 2900 return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short"; 2901 return "toInt64($value)" if $type eq "unsigned long long" or $type eq "long long"; 2902 return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; 2903 return "toWebCoreDate($value)" if $type eq "Date"; 2904 return "v8ValueToWebCoreDOMStringList($value)" if $type eq "DOMStringList"; 2905 2906 if ($type eq "DOMString" or $type eq "DOMUserData") { 2907 return $value; 2908 } 2909 2910 die "Unexpected SerializedScriptValue" if $type eq "SerializedScriptValue"; 2911 2912 if ($type eq "IDBKey") { 2913 $implIncludes{"IDBBindingUtilities.h"} = 1; 2914 $implIncludes{"IDBKey.h"} = 1; 2915 return "createIDBKeyFromValue($value)"; 2916 } 2917 2918 if ($type eq "OptionsObject") { 2919 $implIncludes{"OptionsObject.h"} = 1; 2920 return $value; 2921 } 2922 2923 if ($type eq "DOMObject") { 2924 $implIncludes{"ScriptValue.h"} = 1; 2925 return "ScriptValue($value)"; 2926 } 2927 2928 if ($type eq "NodeFilter") { 2929 return "V8DOMWrapper::wrapNativeNodeFilter($value)"; 2930 } 2931 2932 if ($type eq "MediaQueryListListener") { 2933 $implIncludes{"MediaQueryListListener.h"} = 1; 2934 return "MediaQueryListListener::create(" . $value . ")"; 2935 } 2936 2937 # Default, assume autogenerated type conversion routines 2938 if ($type eq "EventTarget") { 2939 $implIncludes{"V8Node.h"} = 1; 2940 2941 # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget. 2942 return "V8Node::HasInstance($value) ? V8Node::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; 2943 } 2944 2945 if ($type eq "XPathNSResolver") { 2946 return "V8DOMWrapper::getXPathNSResolver($value)"; 2947 } 2948 2949 AddIncludesForType($type); 2950 2951 if (IsDOMNodeType($type)) { 2952 $implIncludes{"V8${type}.h"} = 1; 2953 2954 # Perform type checks on the parameter, if it is expected Node type, 2955 # return NULL. 2956 return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; 2957 } else { 2958 $implIncludes{"V8$type.h"} = 1; 2959 2960 # Perform type checks on the parameter, if it is expected Node type, 2961 # return NULL. 2962 return "V8${type}::HasInstance($value) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; 2963 } 2964 } 2965 2966 sub GetV8HeaderName 2967 { 2968 my $type = shift; 2969 return "V8Event.h" if $type eq "DOMTimeStamp"; 2970 return "EventListener.h" if $type eq "EventListener"; 2971 return "EventTarget.h" if $type eq "EventTarget"; 2972 return "SerializedScriptValue.h" if $type eq "SerializedScriptValue"; 2973 return "ScriptValue.h" if $type eq "DOMObject"; 2974 return "V8${type}.h"; 2975 } 2976 2977 sub CreateCustomSignature 2978 { 2979 my $function = shift; 2980 my $count = @{$function->parameters}; 2981 my $name = $function->signature->name; 2982 my $result = " const int ${name}Argc = ${count};\n" . 2983 " v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { "; 2984 my $first = 1; 2985 foreach my $parameter (@{$function->parameters}) { 2986 if ($first) { $first = 0; } 2987 else { $result .= ", "; } 2988 if (IsWrapperType($parameter->type)) { 2989 if ($parameter->type eq "XPathNSResolver") { 2990 # Special case for XPathNSResolver. All other browsers accepts a callable, 2991 # so, even though it's against IDL, accept objects here. 2992 $result .= "v8::Handle<v8::FunctionTemplate>()"; 2993 } else { 2994 my $type = $parameter->type; 2995 my $header = GetV8HeaderName($type); 2996 $implIncludes{$header} = 1; 2997 $result .= "V8${type}::GetRawTemplate()"; 2998 } 2999 } else { 3000 $result .= "v8::Handle<v8::FunctionTemplate>()"; 3001 } 3002 } 3003 $result .= " };\n"; 3004 $result .= " v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n"; 3005 return $result; 3006 } 3007 3008 3009 sub RequiresCustomSignature 3010 { 3011 my $function = shift; 3012 # No signature needed for Custom function 3013 if ($function->signature->extendedAttributes->{"Custom"} || 3014 $function->signature->extendedAttributes->{"V8Custom"}) { 3015 return 0; 3016 } 3017 # No signature needed for overloaded function 3018 if (@{$function->{overloads}} > 1) { 3019 return 0; 3020 } 3021 # Type checking is performed in the generated code 3022 if ($function->signature->extendedAttributes->{"StrictTypeChecking"}) { 3023 return 0; 3024 } 3025 foreach my $parameter (@{$function->parameters}) { 3026 if ($parameter->extendedAttributes->{"Optional"} || $parameter->extendedAttributes->{"Callback"}) { 3027 return 0; 3028 } 3029 } 3030 3031 foreach my $parameter (@{$function->parameters}) { 3032 if (IsWrapperType($parameter->type)) { 3033 return 1; 3034 } 3035 } 3036 return 0; 3037 } 3038 3039 3040 # FIXME: Sort this array. 3041 my %non_wrapper_types = ( 3042 'float' => 1, 3043 'double' => 1, 3044 'int' => 1, 3045 'unsigned int' => 1, 3046 'short' => 1, 3047 'unsigned short' => 1, 3048 'long' => 1, 3049 'unsigned long' => 1, 3050 'boolean' => 1, 3051 'long long' => 1, 3052 'unsigned long long' => 1, 3053 'DOMString' => 1, 3054 'CompareHow' => 1, 3055 'SerializedScriptValue' => 1, 3056 'DOMTimeStamp' => 1, 3057 'JSObject' => 1, 3058 'DOMObject' => 1, 3059 'EventTarget' => 1, 3060 'NodeFilter' => 1, 3061 'EventListener' => 1, 3062 'IDBKey' => 1, 3063 'OptionsObject' => 1, 3064 'Date' => 1, 3065 'MediaQueryListListener' => 1 3066 ); 3067 3068 3069 sub IsWrapperType 3070 { 3071 my $type = $codeGenerator->StripModule(shift); 3072 return !($non_wrapper_types{$type}); 3073 } 3074 3075 sub IsDOMNodeType 3076 { 3077 my $type = shift; 3078 3079 return 1 if $type eq 'Attr'; 3080 return 1 if $type eq 'CDATASection'; 3081 return 1 if $type eq 'Comment'; 3082 return 1 if $type eq 'Document'; 3083 return 1 if $type eq 'DocumentFragment'; 3084 return 1 if $type eq 'DocumentType'; 3085 return 1 if $type eq 'Element'; 3086 return 1 if $type eq 'EntityReference'; 3087 return 1 if $type eq 'HTMLCanvasElement'; 3088 return 1 if $type eq 'HTMLDocument'; 3089 return 1 if $type eq 'HTMLElement'; 3090 return 1 if $type eq 'HTMLFormElement'; 3091 return 1 if $type eq 'HTMLTableCaptionElement'; 3092 return 1 if $type eq 'HTMLTableSectionElement'; 3093 return 1 if $type eq 'Node'; 3094 return 1 if $type eq 'ProcessingInstruction'; 3095 return 1 if $type eq 'SVGElement'; 3096 return 1 if $type eq 'SVGDocument'; 3097 return 1 if $type eq 'SVGSVGElement'; 3098 return 1 if $type eq 'SVGUseElement'; 3099 return 1 if $type eq 'Text'; 3100 3101 return 0; 3102 } 3103 3104 3105 sub NativeToJSValue 3106 { 3107 my $signature = shift; 3108 my $value = shift; 3109 my $indent = shift; 3110 my $type = GetTypeFromSignature($signature); 3111 3112 return "v8Boolean($value)" if $type eq "boolean"; 3113 return "v8::Handle<v8::Value>()" if $type eq "void"; # equivalent to v8::Undefined() 3114 3115 # HTML5 says that unsigned reflected attributes should be in the range 3116 # [0, 2^31). When a value isn't in this range, a default value (or 0) 3117 # should be returned instead. 3118 if ($signature->extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) { 3119 $value =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g; 3120 return "v8::Integer::NewFromUnsigned(std::max(0, " . $value . "))"; 3121 } 3122 3123 # For all the types where we use 'int' as the representation type, 3124 # we use Integer::New which has a fast Smi conversion check. 3125 my $nativeType = GetNativeType($type); 3126 return "v8::Integer::New($value)" if $nativeType eq "int"; 3127 return "v8::Integer::NewFromUnsigned($value)" if $nativeType eq "unsigned"; 3128 3129 return "v8DateOrNull($value)" if $type eq "Date"; 3130 # long long and unsigned long long are not representable in ECMAScript. 3131 return "v8::Number::New(static_cast<double>($value))" if $type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp"; 3132 return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type); 3133 return "$value.v8Value()" if $nativeType eq "ScriptValue"; 3134 3135 if ($codeGenerator->IsStringType($type)) { 3136 my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"}; 3137 if (defined $conv) { 3138 return "v8StringOrNull($value)" if $conv eq "Null"; 3139 return "v8StringOrUndefined($value)" if $conv eq "Undefined"; 3140 return "v8StringOrFalse($value)" if $conv eq "False"; 3141 3142 die "Unknown value for ConvertNullStringTo extended attribute"; 3143 } 3144 $conv = $signature->extendedAttributes->{"ConvertScriptString"}; 3145 return "v8StringOrNull($value)" if $conv; 3146 return "v8String($value)"; 3147 } 3148 3149 AddIncludesForType($type); 3150 3151 # special case for non-DOM node interfaces 3152 if (IsDOMNodeType($type)) { 3153 return "toV8(${value}" . ($signature->extendedAttributes->{"ReturnsNew"} ? ", true)" : ")"); 3154 } 3155 3156 if ($type eq "EventTarget") { 3157 return "V8DOMWrapper::convertEventTargetToV8Object($value)"; 3158 } 3159 3160 if ($type eq "EventListener") { 3161 $implIncludes{"V8AbstractEventListener.h"} = 1; 3162 return "${value} ? v8::Handle<v8::Value>(static_cast<V8AbstractEventListener*>(${value})->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null())"; 3163 } 3164 3165 if ($type eq "SerializedScriptValue") { 3166 $implIncludes{"$type.h"} = 1; 3167 return "$value->deserialize()"; 3168 } 3169 3170 $implIncludes{"wtf/RefCounted.h"} = 1; 3171 $implIncludes{"wtf/RefPtr.h"} = 1; 3172 $implIncludes{"wtf/GetPtr.h"} = 1; 3173 3174 return "toV8($value)"; 3175 } 3176 3177 sub ReturnNativeToJSValue 3178 { 3179 return "return " . NativeToJSValue(@_); 3180 } 3181 3182 # Internal helper 3183 sub WriteData 3184 { 3185 if (defined($IMPL)) { 3186 # Write content to file. 3187 print $IMPL @implContentHeader; 3188 3189 print $IMPL @implFixedHeader; 3190 3191 foreach my $implInclude (sort keys(%implIncludes)) { 3192 my $checkType = $implInclude; 3193 $checkType =~ s/\.h//; 3194 3195 if ($implInclude =~ /wtf/) { 3196 print $IMPL "#include \<$implInclude\>\n"; 3197 } else { 3198 print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType); 3199 } 3200 } 3201 3202 print $IMPL "\n"; 3203 print $IMPL @implContentDecls; 3204 print $IMPL @implContent; 3205 close($IMPL); 3206 undef($IMPL); 3207 3208 %implIncludes = (); 3209 @implFixedHeader = (); 3210 @implHeaderContent = (); 3211 @implContentDecls = (); 3212 @implContent = (); 3213 } 3214 3215 if (defined($HEADER)) { 3216 # Write content to file. 3217 print $HEADER @headerContent; 3218 close($HEADER); 3219 undef($HEADER); 3220 3221 @headerContent = (); 3222 } 3223 } 3224 3225 sub GetVisibleInterfaceName 3226 { 3227 my $interfaceName = shift; 3228 3229 return "DOMException" if $interfaceName eq "DOMCoreException"; 3230 return "FormData" if $interfaceName eq "DOMFormData"; 3231 return $interfaceName; 3232 } 3233 3234 sub GetCallbackClassName 3235 { 3236 my $interfaceName = shift; 3237 3238 return "V8CustomVoidCallback" if $interfaceName eq "VoidCallback"; 3239 return "V8$interfaceName"; 3240 } 3241 3242 sub ConvertToV8Parameter 3243 { 3244 my $signature = shift; 3245 my $nativeType = shift; 3246 my $variableName = shift; 3247 my $value = shift; 3248 my $suffix = shift; 3249 3250 die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8Parameter/; 3251 if ($signature->type eq "DOMString") { 3252 $implIncludes{"V8BindingMacros.h"} = 1; 3253 my $macro = "STRING_TO_V8PARAMETER_EXCEPTION_BLOCK"; 3254 $macro .= "_$suffix" if $suffix; 3255 return "$macro($nativeType, $variableName, $value);" 3256 } else { 3257 # Don't know how to properly check for conversion exceptions when $parameter->type is "DOMUserData" 3258 return "$nativeType $variableName($value, true);"; 3259 } 3260 } 3261 3262 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled. 3263 sub GetRuntimeEnableFunctionName 3264 { 3265 my $signature = shift; 3266 3267 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method. 3268 return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "1"); 3269 3270 # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled(). 3271 return "RuntimeEnabledFeatures::" . $codeGenerator->WK_lcfirst($signature->name) . "Enabled"; 3272 } 3273 3274 sub DebugPrint 3275 { 3276 my $output = shift; 3277 3278 print $output; 3279 print "\n"; 3280 } 3281