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