1 # Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann (at] kde.org> 2 # Copyright (C) 2006 Anders Carlsson <andersca (at] mac.com> 3 # Copyright (C) 2006 Samuel Weinig <sam.weinig (at] gmail.com> 4 # Copyright (C) 2006 Alexey Proskuryakov <ap (at] webkit.org> 5 # Copyright (C) 2006 Apple Computer, Inc. 6 # Copyright (C) 2007, 2008, 2009, 2012 Google Inc. 7 # Copyright (C) 2009 Cameron McCormack <cam (at] mcc.id.au> 8 # Copyright (C) Research In Motion Limited 2010. All rights reserved. 9 # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) 10 # Copyright (C) 2012 Ericsson AB. All rights reserved. 11 # Copyright (C) 2013 Samsung Electronics. All rights reserved. 12 # 13 # This library is free software; you can redistribute it and/or 14 # modify it under the terms of the GNU Library General Public 15 # License as published by the Free Software Foundation; either 16 # version 2 of the License, or (at your option) any later version. 17 # 18 # This library is distributed in the hope that it will be useful, 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 # Library General Public License for more details. 22 # 23 # You should have received a copy of the GNU Library General Public License 24 # along with this library; see the file COPYING.LIB. If not, write to 25 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 26 # Boston, MA 02111-1307, USA. 27 # 28 29 package Block; 30 31 # Sample code: 32 # my $outer = new Block("Free Name 1", "namespace Foo {", "} // namespace Foo"); 33 # $outer->add(" void foo() {}"); 34 # my $inner = new Block("Free Name 2", "namespace Bar {", "} // namespace Bar"); 35 # $inner->add(" void bar() {}"); 36 # $outer->add($inner); 37 # print $outer->toString(); 38 # 39 # Output code: 40 # namespace Foo { 41 # void foo() {} 42 # namespace Bar { 43 # void bar() {} 44 # } // namespace Bar 45 # } // namespace Foo 46 47 sub new 48 { 49 my $package = shift; 50 my $name = shift || "Anonymous block"; 51 my $header = shift || ""; 52 my $footer = shift || ""; 53 54 my $object = { 55 "name" => $name, 56 "header" => [$header], 57 "footer" => [$footer], 58 "contents" => [], 59 }; 60 bless $object, $package; 61 return $object; 62 } 63 64 sub addHeader 65 { 66 my $object = shift; 67 my $header = shift || ""; 68 69 push(@{$object->{header}}, $header); 70 } 71 72 sub addFooter 73 { 74 my $object = shift; 75 my $footer = shift || ""; 76 77 push(@{$object->{footer}}, $footer); 78 } 79 80 sub add 81 { 82 my $object = shift; 83 my $content = shift || ""; 84 85 push(@{$object->{contents}}, $content); 86 } 87 88 sub toString 89 { 90 my $object = shift; 91 92 my $header = join "", @{$object->{header}}; 93 my $footer = join "", @{$object->{footer}}; 94 my $code = ""; 95 $code .= "/* BEGIN " . $object->{name} . " */\n" if $verbose; 96 $code .= $header . "\n" if $header; 97 for my $content (@{$object->{contents}}) { 98 if (ref($content) eq "Block") { 99 $code .= $content->toString(); 100 } else { 101 $code .= $content; 102 } 103 } 104 $code .= $footer . "\n" if $footer; 105 $code .= "/* END " . $object->{name} . " */\n" if $verbose; 106 return $code; 107 } 108 109 110 package deprecated_code_generator_v8; 111 112 use strict; 113 use Cwd; 114 use File::Basename; 115 use File::Find; 116 use File::Spec; 117 118 my $idlDocument; 119 my $idlDirectories; 120 my $preprocessor; 121 my $verbose; 122 my $interfaceIdlFiles; 123 my $writeFileOnlyIfChanged; 124 my $sourceRoot; 125 126 # Cache of IDL file pathnames. 127 my $idlFiles; 128 my $cachedInterfaces = {}; 129 130 my %implIncludes = (); 131 my %headerIncludes = (); 132 133 # Header code structure: 134 # Root ... Copyright, include duplication check 135 # Conditional ... #if FEATURE ... #endif (to be removed soon) 136 # Includes 137 # NameSpaceWebCore 138 # Class 139 # ClassPublic 140 # ClassPrivate 141 my %header; 142 143 # Implementation code structure: 144 # Root ... Copyright 145 # Conditional ... #if FEATURE ... #endif (to be removed soon) 146 # Includes 147 # NameSpaceWebCore 148 # NameSpaceInternal ... namespace ${implClassName}V8Internal in case of non-callback 149 my %implementation; 150 151 my %primitiveTypeHash = ("boolean" => 1, 152 "void" => 1, 153 "Date" => 1, 154 "byte" => 1, 155 "octet" => 1, 156 "short" => 1, 157 "long" => 1, 158 "long long" => 1, 159 "unsigned short" => 1, 160 "unsigned long" => 1, 161 "unsigned long long" => 1, 162 "float" => 1, 163 "double" => 1, 164 ); 165 166 my %nonWrapperTypes = ("CompareHow" => 1, 167 "DOMTimeStamp" => 1, 168 "Dictionary" => 1, 169 "EventListener" => 1, 170 "EventHandler" => 1, 171 "MediaQueryListListener" => 1, 172 "NodeFilter" => 1, 173 "SerializedScriptValue" => 1, 174 "any" => 1, 175 ); 176 177 my %typedArrayHash = ("ArrayBuffer" => [], 178 "ArrayBufferView" => [], 179 "Uint8Array" => ["unsigned char", "v8::kExternalUnsignedByteArray"], 180 "Uint8ClampedArray" => ["unsigned char", "v8::kExternalPixelArray"], 181 "Uint16Array" => ["unsigned short", "v8::kExternalUnsignedShortArray"], 182 "Uint32Array" => ["unsigned int", "v8::kExternalUnsignedIntArray"], 183 "Int8Array" => ["signed char", "v8::kExternalByteArray"], 184 "Int16Array" => ["short", "v8::kExternalShortArray"], 185 "Int32Array" => ["int", "v8::kExternalIntArray"], 186 "Float32Array" => ["float", "v8::kExternalFloatArray"], 187 "Float64Array" => ["double", "v8::kExternalDoubleArray"], 188 ); 189 190 my %callbackFunctionTypeHash = (); 191 192 my %enumTypeHash = (); 193 194 my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1, 195 "onerror" => 1, "onload" => 1, "onmousedown" => 1, 196 "onmouseenter" => 1, "onmouseleave" => 1, 197 "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1, 198 "onmouseup" => 1, "onresize" => 1, "onscroll" => 1, 199 "onunload" => 1); 200 201 my %svgTypeNeedingTearOff = ( 202 "SVGAngle" => "SVGPropertyTearOff<SVGAngle>", 203 "SVGLength" => "SVGPropertyTearOff<SVGLength>", 204 "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>", 205 "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>", 206 "SVGNumber" => "SVGPropertyTearOff<SVGNumber>", 207 "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>", 208 "SVGPathSegList" => "SVGPathSegListPropertyTearOff", 209 "SVGPoint" => "SVGPropertyTearOff<SVGPoint>", 210 "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>", 211 "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>", 212 "SVGRect" => "SVGPropertyTearOff<SVGRect>", 213 "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>", 214 "SVGTransform" => "SVGPropertyTearOff<SVGTransform>", 215 "SVGTransformList" => "SVGTransformListPropertyTearOff" 216 ); 217 218 my %svgTypeWithWritablePropertiesNeedingTearOff = ( 219 "SVGPoint" => 1, 220 "SVGMatrix" => 1 221 ); 222 223 # Default .h template 224 my $headerTemplate = <<EOF; 225 /* 226 This file is part of the Blink open source project. 227 This file has been auto-generated by CodeGeneratorV8.pm. DO NOT MODIFY! 228 229 This library is free software; you can redistribute it and/or 230 modify it under the terms of the GNU Library General Public 231 License as published by the Free Software Foundation; either 232 version 2 of the License, or (at your option) any later version. 233 234 This library is distributed in the hope that it will be useful, 235 but WITHOUT ANY WARRANTY; without even the implied warranty of 236 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 237 Library General Public License for more details. 238 239 You should have received a copy of the GNU Library General Public License 240 along with this library; see the file COPYING.LIB. If not, write to 241 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 242 Boston, MA 02111-1307, USA. 243 */ 244 EOF 245 246 sub new 247 { 248 my $object = shift; 249 my $reference = { }; 250 251 $idlDocument = shift; 252 $idlDirectories = shift; 253 $preprocessor = shift; 254 $verbose = shift; 255 $interfaceIdlFiles = shift; 256 $writeFileOnlyIfChanged = shift; 257 258 $sourceRoot = getcwd(); 259 260 bless($reference, $object); 261 return $reference; 262 } 263 264 265 sub IDLFileForInterface 266 { 267 my $interfaceName = shift; 268 269 unless ($idlFiles) { 270 my @directories = map { $_ = "$sourceRoot/$_" if -d "$sourceRoot/$_"; $_ } @$idlDirectories; 271 push(@directories, "."); 272 273 $idlFiles = { }; 274 foreach my $idlFile (@$interfaceIdlFiles) { 275 $idlFiles->{fileparse(basename($idlFile), ".idl")} = $idlFile; 276 } 277 278 my $wanted = sub { 279 $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/; 280 $File::Find::prune = 1 if /^\../; 281 }; 282 find($wanted, @directories); 283 } 284 285 return $idlFiles->{$interfaceName}; 286 } 287 288 sub ParseInterface 289 { 290 my $interfaceName = shift; 291 292 if (exists $cachedInterfaces->{$interfaceName}) { 293 return $cachedInterfaces->{$interfaceName}; 294 } 295 296 # Step #1: Find the IDL file associated with 'interface' 297 my $filename = IDLFileForInterface($interfaceName) 298 or die("Could NOT find IDL file for interface \"$interfaceName\" $!\n"); 299 300 print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose; 301 302 # Step #2: Parse the found IDL file (in quiet mode). 303 my $parser = deprecated_idl_parser->new(1); 304 my $document = $parser->Parse($filename, $preprocessor); 305 306 foreach my $interface (@{$document->interfaces}) { 307 if ($interface->name eq $interfaceName or $interface->isPartial) { 308 $cachedInterfaces->{$interfaceName} = $interface; 309 return $interface; 310 } 311 } 312 313 die("Could NOT find interface definition for $interfaceName in $filename"); 314 } 315 316 sub GenerateInterface 317 { 318 my $object = shift; 319 my $interface = shift; 320 321 %callbackFunctionTypeHash = map { $_->name => $_ } @{$idlDocument->callbackFunctions}; 322 %enumTypeHash = map { $_->name => $_->values } @{$idlDocument->enumerations}; 323 my $v8ClassName = GetV8ClassName($interface); 324 my $defineName = $v8ClassName . "_h"; 325 my $internalNamespace = GetImplName($interface) . "V8Internal"; 326 327 my $conditionalString = GenerateConditionalString($interface); 328 my $conditionalIf = ""; 329 my $conditionalEndif = ""; 330 if ($conditionalString) { 331 $conditionalIf = "#if ${conditionalString}"; 332 $conditionalEndif = "#endif // ${conditionalString}"; 333 } 334 335 $header{root} = new Block("ROOT", "", ""); 336 # FIXME: newlines should be generated by Block::toString(). 337 $header{conditional} = new Block("Conditional", "$conditionalIf", $conditionalEndif ? "$conditionalEndif\n" : ""); 338 $header{includes} = new Block("Includes", "", ""); 339 $header{nameSpaceWebCore} = new Block("Namespace WebCore", "\nnamespace WebCore {\n", "}\n"); 340 $header{class} = new Block("Class definition", "", ""); 341 $header{classPublic} = new Block("Class public:", "public:", ""); 342 $header{classPrivate} = new Block("Class private:", "private:", ""); 343 344 $header{root}->add($header{conditional}); 345 $header{conditional}->add($header{includes}); 346 $header{conditional}->add($header{nameSpaceWebCore}); 347 $header{nameSpaceWebCore}->add($header{class}); 348 $header{class}->add($header{classPublic}); 349 $header{class}->add($header{classPrivate}); 350 351 # - Add default header template 352 $header{root}->addHeader($headerTemplate . "\n"); 353 $header{root}->addHeader("#ifndef $defineName\n#define $defineName\n"); 354 $header{root}->addFooter("#endif // $defineName"); 355 356 $implementation{root} = new Block("ROOT", "", ""); 357 $conditionalEndif = "\n$conditionalEndif" if !$interface->isCallback and $conditionalEndif; 358 $implementation{conditional} = new Block("Conditional", $conditionalIf, $conditionalEndif); 359 $implementation{includes} = new Block("Includes", "", ""); 360 361 # FIXME: newlines should be generated by Block::toString(). 362 my $nameSpaceWebCoreBegin = "namespace WebCore {\n"; 363 my $nameSpaceWebCoreEnd = "} // namespace WebCore"; 364 $nameSpaceWebCoreBegin = "$nameSpaceWebCoreBegin\n" if !$interface->isCallback; 365 $nameSpaceWebCoreEnd = "\n$nameSpaceWebCoreEnd\n" if $interface->isCallback; 366 $implementation{nameSpaceWebCore} = new Block("Namespace WebCore", $nameSpaceWebCoreBegin, $nameSpaceWebCoreEnd); 367 $implementation{nameSpaceInternal} = new Block("Internal namespace", "namespace $internalNamespace {\n", "} // namespace $internalNamespace\n"); 368 369 $implementation{root}->add($implementation{conditional}); 370 $implementation{conditional}->add($implementation{includes}); 371 $implementation{conditional}->add($implementation{nameSpaceWebCore}); 372 if (!$interface->isCallback) { 373 $implementation{nameSpaceWebCore}->add($implementation{nameSpaceInternal}); 374 } 375 376 # - Add default header template 377 $implementation{root}->addHeader($headerTemplate); 378 $implementation{root}->addHeader("\n#include \"config.h\""); 379 $implementation{includes}->add("#include \"${v8ClassName}.h\"\n\n"); 380 381 # Start actual generation 382 if ($interface->isCallback) { 383 $object->GenerateCallbackHeader($interface); 384 $object->GenerateCallbackImplementation($interface); 385 } else { 386 $object->GenerateHeader($interface); 387 $object->GenerateImplementation($interface); 388 } 389 } 390 391 sub AddToImplIncludes 392 { 393 my $header = shift; 394 $implIncludes{$header} = 1; 395 } 396 397 sub AddToHeaderIncludes 398 { 399 my @includes = @_; 400 401 for my $include (@includes) { 402 $headerIncludes{$include} = 1; 403 } 404 } 405 406 sub SkipIncludeHeader 407 { 408 my $type = shift; 409 410 return 1 if IsPrimitiveType($type); 411 return 1 if IsEnumType($type); 412 return 1 if IsCallbackFunctionType($type); 413 return 1 if $type eq "DOMString"; 414 return 0; 415 } 416 417 sub AddIncludesForType 418 { 419 my $type = shift; 420 421 return if SkipIncludeHeader($type); 422 423 # Default includes 424 if ($type eq "EventListener" or $type eq "EventHandler") { 425 AddToImplIncludes("core/dom/EventListener.h"); 426 } elsif ($type eq "SerializedScriptValue") { 427 AddToImplIncludes("bindings/v8/SerializedScriptValue.h"); 428 } elsif ($type eq "any" || IsCallbackFunctionType($type)) { 429 AddToImplIncludes("bindings/v8/ScriptValue.h"); 430 } elsif (IsTypedArrayType($type)) { 431 AddToImplIncludes("bindings/v8/custom/V8${type}Custom.h"); 432 } else { 433 AddToImplIncludes("V8${type}.h"); 434 } 435 } 436 437 sub HeaderFilesForInterface 438 { 439 my $interfaceName = shift; 440 my $implClassName = shift; 441 442 my @includes = (); 443 if (IsTypedArrayType($interfaceName)) { 444 push(@includes, "wtf/${interfaceName}.h"); 445 } elsif (!SkipIncludeHeader($interfaceName)) { 446 my $idlFilename = IDLFileForInterface($interfaceName) or die("Could NOT find IDL file for interface \"$interfaceName\" $!\n"); 447 my $idlRelPath= "bindings/" . File::Spec->abs2rel($idlFilename, $sourceRoot); 448 push(@includes, dirname($idlRelPath) . "/" . $implClassName . ".h"); 449 } 450 return @includes; 451 } 452 453 sub NeedsOpaqueRootForGC 454 { 455 my $interface = shift; 456 return $interface->extendedAttributes->{"GenerateIsReachable"} || $interface->extendedAttributes->{"CustomIsReachable"}; 457 } 458 459 sub GenerateOpaqueRootForGC 460 { 461 my $interface = shift; 462 my $implClassName = GetImplName($interface); 463 my $v8ClassName = GetV8ClassName($interface); 464 465 if ($interface->extendedAttributes->{"CustomIsReachable"}) { 466 return; 467 } 468 469 my $code = <<END; 470 void* ${v8ClassName}::opaqueRootForGC(void* object, v8::Isolate* isolate) 471 { 472 ${implClassName}* impl = fromInternalPointer(object); 473 END 474 my $isReachableMethod = $interface->extendedAttributes->{"GenerateIsReachable"}; 475 if ($isReachableMethod) { 476 AddToImplIncludes("bindings/v8/V8GCController.h"); 477 AddToImplIncludes("core/dom/Element.h"); 478 $code .= <<END; 479 if (Node* owner = impl->${isReachableMethod}()) 480 return V8GCController::opaqueRootForGC(owner, isolate); 481 END 482 } 483 484 $code .= <<END; 485 return object; 486 } 487 488 END 489 $implementation{nameSpaceWebCore}->add($code); 490 } 491 492 sub GetSVGPropertyTypes 493 { 494 my $implType = shift; 495 496 my $svgPropertyType; 497 my $svgListPropertyType; 498 my $svgNativeType; 499 500 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $implType =~ /SVG/; 501 502 $svgNativeType = GetSVGTypeNeedingTearOff($implType); 503 return ($svgPropertyType, $svgListPropertyType, $svgNativeType) if not $svgNativeType; 504 505 # Append space to avoid compilation errors when using PassRefPtr<$svgNativeType> 506 $svgNativeType = "$svgNativeType "; 507 508 my $svgWrappedNativeType = GetSVGWrappedTypeNeedingTearOff($implType); 509 if ($svgNativeType =~ /SVGPropertyTearOff/) { 510 $svgPropertyType = $svgWrappedNativeType; 511 AddToHeaderIncludes("core/svg/properties/SVGAnimatedPropertyTearOff.h"); 512 } elsif ($svgNativeType =~ /SVGListPropertyTearOff/ or $svgNativeType =~ /SVGStaticListPropertyTearOff/ or $svgNativeType =~ /SVGTransformListPropertyTearOff/) { 513 $svgListPropertyType = $svgWrappedNativeType; 514 AddToHeaderIncludes("core/svg/properties/SVGAnimatedListPropertyTearOff.h"); 515 } elsif ($svgNativeType =~ /SVGPathSegListPropertyTearOff/) { 516 $svgListPropertyType = $svgWrappedNativeType; 517 AddToHeaderIncludes("core/svg/properties/SVGPathSegListPropertyTearOff.h"); 518 } 519 520 return ($svgPropertyType, $svgListPropertyType, $svgNativeType); 521 } 522 523 sub GetIndexedGetterFunction 524 { 525 my $interface = shift; 526 527 # FIXME: Expose indexed getter of CSSMixFunctionValue by removing this special case 528 # because CSSValueList(which is parent of CSSMixFunctionValue) has indexed property getter. 529 if ($interface->name eq "CSSMixFunctionValue") { 530 return 0; 531 } 532 533 return GetSpecialAccessorFunctionForType($interface, "getter", "unsigned long", 1); 534 } 535 536 sub GetIndexedSetterFunction 537 { 538 my $interface = shift; 539 540 return GetSpecialAccessorFunctionForType($interface, "setter", "unsigned long", 2); 541 } 542 543 sub GetIndexedDeleterFunction 544 { 545 my $interface = shift; 546 547 return GetSpecialAccessorFunctionForType($interface, "deleter", "unsigned long", 1); 548 } 549 550 sub GetNamedGetterFunction 551 { 552 my $interface = shift; 553 return GetSpecialAccessorFunctionForType($interface, "getter", "DOMString", 1); 554 } 555 556 sub GetNamedSetterFunction 557 { 558 my $interface = shift; 559 return GetSpecialAccessorFunctionForType($interface, "setter", "DOMString", 2); 560 } 561 562 sub GetNamedDeleterFunction 563 { 564 my $interface = shift; 565 return GetSpecialAccessorFunctionForType($interface, "deleter", "DOMString", 1); 566 } 567 568 sub GetSpecialAccessorFunctionForType 569 { 570 my $interface = shift; 571 my $special = shift; 572 my $firstParameterType = shift; 573 my $numberOfParameters = shift; 574 575 foreach my $function (@{$interface->functions}) { 576 my $specials = $function->specials; 577 my $specialExists = grep { $_ eq $special } @$specials; 578 my $parameters = $function->parameters; 579 if ($specialExists and scalar(@$parameters) == $numberOfParameters and $parameters->[0]->type eq $firstParameterType) { 580 return $function; 581 } 582 } 583 584 return 0; 585 } 586 587 sub GenerateHeader 588 { 589 my $object = shift; 590 my $interface = shift; 591 592 my $interfaceName = $interface->name; 593 my $implClassName = GetImplName($interface); 594 my $v8ClassName = GetV8ClassName($interface); 595 596 LinkOverloadedFunctions($interface); 597 598 # Ensure the IsDOMNodeType function is in sync. 599 die("IsDOMNodeType is out of date with respect to $interfaceName") if IsDOMNodeType($interfaceName) != InheritsInterface($interface, "Node"); 600 601 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName); 602 603 my $parentInterface = $interface->parent; 604 AddToHeaderIncludes("V8${parentInterface}.h") if $parentInterface; 605 AddToHeaderIncludes("bindings/v8/WrapperTypeInfo.h"); 606 AddToHeaderIncludes("bindings/v8/V8Binding.h"); 607 AddToHeaderIncludes("bindings/v8/V8DOMWrapper.h"); 608 AddToHeaderIncludes(HeaderFilesForInterface($interfaceName, $implClassName)); 609 foreach my $headerInclude (sort keys(%headerIncludes)) { 610 $header{includes}->add("#include \"${headerInclude}\"\n"); 611 } 612 613 $header{nameSpaceWebCore}->addHeader("\ntemplate<typename PropertyType> class SVGPropertyTearOff;\n") if $svgPropertyType; 614 if ($svgNativeType) { 615 if ($svgNativeType =~ /SVGStaticListPropertyTearOff/) { 616 $header{nameSpaceWebCore}->addHeader("\ntemplate<typename PropertyType> class SVGStaticListPropertyTearOff;\n"); 617 } else { 618 $header{nameSpaceWebCore}->addHeader("\ntemplate<typename PropertyType> class SVGListPropertyTearOff;\n"); 619 } 620 } 621 622 $header{nameSpaceWebCore}->addHeader("\nclass Dictionary;") if IsConstructorTemplate($interface, "Event"); 623 624 my $nativeType = GetNativeTypeForConversions($interface); 625 if ($interface->extendedAttributes->{"NamedConstructor"}) { 626 $header{nameSpaceWebCore}->addHeader(<<END); 627 628 class V8${nativeType}Constructor { 629 public: 630 static v8::Handle<v8::FunctionTemplate> GetTemplate(v8::Isolate*, WrapperWorldType); 631 static WrapperTypeInfo info; 632 }; 633 END 634 } 635 636 $header{class}->addHeader("class $v8ClassName {"); 637 $header{class}->addFooter("};"); 638 639 $header{classPublic}->add(<<END); 640 static bool HasInstance(v8::Handle<v8::Value>, v8::Isolate*, WrapperWorldType); 641 static bool HasInstanceInAnyWorld(v8::Handle<v8::Value>, v8::Isolate*); 642 static v8::Handle<v8::FunctionTemplate> GetTemplate(v8::Isolate*, WrapperWorldType); 643 static ${nativeType}* toNative(v8::Handle<v8::Object> object) 644 { 645 return fromInternalPointer(object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex)); 646 } 647 static void derefObject(void*); 648 static WrapperTypeInfo info; 649 END 650 651 if (NeedsOpaqueRootForGC($interface)) { 652 $header{classPublic}->add(" static void* opaqueRootForGC(void*, v8::Isolate*);\n"); 653 } 654 655 if (InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 656 $header{classPublic}->add(" static ActiveDOMObject* toActiveDOMObject(v8::Handle<v8::Object>);\n"); 657 } 658 659 if (InheritsInterface($interface, "EventTarget")) { 660 $header{classPublic}->add(" static EventTarget* toEventTarget(v8::Handle<v8::Object>);\n"); 661 } 662 663 if ($interfaceName eq "Window") { 664 $header{classPublic}->add(<<END); 665 static v8::Handle<v8::ObjectTemplate> GetShadowObjectTemplate(v8::Isolate*, WrapperWorldType); 666 END 667 } 668 669 my @enabledPerContextFunctions; 670 foreach my $function (@{$interface->functions}) { 671 my $name = $function->name; 672 next if $name eq ""; 673 my $attrExt = $function->extendedAttributes; 674 675 if (HasCustomMethod($attrExt) && $function->{overloadIndex} == 1) { 676 my $conditionalString = GenerateConditionalString($function); 677 $header{classPublic}->add("#if ${conditionalString}\n") if $conditionalString; 678 $header{classPublic}->add(<<END); 679 static void ${name}MethodCustom(const v8::FunctionCallbackInfo<v8::Value>&); 680 END 681 $header{classPublic}->add("#endif // ${conditionalString}\n") if $conditionalString; 682 } 683 if ($attrExt->{"EnabledPerContext"}) { 684 push(@enabledPerContextFunctions, $function); 685 } 686 } 687 688 if (IsConstructable($interface)) { 689 $header{classPublic}->add(" static void constructorCallback(const v8::FunctionCallbackInfo<v8::Value>&);\n"); 690 END 691 } 692 if (HasCustomConstructor($interface)) { 693 $header{classPublic}->add(" static void constructorCustom(const v8::FunctionCallbackInfo<v8::Value>&);\n"); 694 } 695 696 my @enabledPerContextAttributes; 697 foreach my $attribute (@{$interface->attributes}) { 698 my $name = $attribute->name; 699 my $attrExt = $attribute->extendedAttributes; 700 my $conditionalString = GenerateConditionalString($attribute); 701 if (HasCustomGetter($attrExt) && !$attrExt->{"ImplementedBy"}) { 702 $header{classPublic}->add("#if ${conditionalString}\n") if $conditionalString; 703 $header{classPublic}->add(<<END); 704 static void ${name}AttrGetterCustom(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>&); 705 END 706 $header{classPublic}->add("#endif // ${conditionalString}\n") if $conditionalString; 707 } 708 if (HasCustomSetter($attrExt) && !$attrExt->{"ImplementedBy"}) { 709 $header{classPublic}->add("#if ${conditionalString}\n") if $conditionalString; 710 $header{classPublic}->add(<<END); 711 static void ${name}AttrSetterCustom(v8::Local<v8::String> name, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<void>&); 712 END 713 $header{classPublic}->add("#endif // ${conditionalString}\n") if $conditionalString; 714 } 715 if ($attrExt->{"EnabledPerContext"}) { 716 push(@enabledPerContextAttributes, $attribute); 717 } 718 } 719 720 GenerateHeaderNamedAndIndexedPropertyAccessors($interface); 721 GenerateHeaderLegacyCall($interface); 722 GenerateHeaderCustomInternalFieldIndices($interface); 723 724 my $toWrappedType; 725 my $fromWrappedType; 726 if ($interface->parent) { 727 my $v8ParentClassName = "V8" . $interface->parent; 728 $toWrappedType = "${v8ParentClassName}::toInternalPointer(impl)"; 729 $fromWrappedType = "static_cast<${nativeType}*>(${v8ParentClassName}::fromInternalPointer(object))"; 730 } else { 731 $toWrappedType = "impl"; 732 $fromWrappedType = "static_cast<${nativeType}*>(object)"; 733 } 734 735 $header{classPublic}->add(<<END); 736 static inline void* toInternalPointer(${nativeType}* impl) 737 { 738 return $toWrappedType; 739 } 740 741 static inline ${nativeType}* fromInternalPointer(void* object) 742 { 743 return $fromWrappedType; 744 } 745 END 746 747 if ($interface->name eq "Window") { 748 $header{classPublic}->add(<<END); 749 static bool namedSecurityCheckCustom(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType, v8::Local<v8::Value> data); 750 static bool indexedSecurityCheckCustom(v8::Local<v8::Object> host, uint32_t index, v8::AccessType, v8::Local<v8::Value> data); 751 END 752 } 753 754 if (@enabledPerContextAttributes) { 755 $header{classPublic}->add(<<END); 756 static void installPerContextProperties(v8::Handle<v8::Object>, ${nativeType}*, v8::Isolate*); 757 END 758 } else { 759 $header{classPublic}->add(<<END); 760 static void installPerContextProperties(v8::Handle<v8::Object>, ${nativeType}*, v8::Isolate*) { } 761 END 762 } 763 764 if (@enabledPerContextFunctions) { 765 $header{classPublic}->add(<<END); 766 static void installPerContextPrototypeProperties(v8::Handle<v8::Object>, v8::Isolate*); 767 END 768 } else { 769 $header{classPublic}->add(<<END); 770 static void installPerContextPrototypeProperties(v8::Handle<v8::Object>, v8::Isolate*) { } 771 END 772 } 773 774 if ($interfaceName eq "HTMLElement") { 775 $header{classPublic}->add(<<END); 776 friend v8::Handle<v8::Object> createV8HTMLWrapper(HTMLElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 777 friend v8::Handle<v8::Object> createV8HTMLDirectWrapper(HTMLElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 778 END 779 } elsif ($interfaceName eq "SVGElement") { 780 $header{classPublic}->add(<<END); 781 friend v8::Handle<v8::Object> createV8SVGWrapper(SVGElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 782 friend v8::Handle<v8::Object> createV8SVGDirectWrapper(SVGElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 783 friend v8::Handle<v8::Object> createV8SVGFallbackWrapper(SVGElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 784 END 785 } elsif ($interfaceName eq "HTMLUnknownElement") { 786 $header{classPublic}->add(<<END); 787 friend v8::Handle<v8::Object> createV8HTMLFallbackWrapper(HTMLUnknownElement*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 788 END 789 } elsif ($interfaceName eq "Element") { 790 $header{classPublic}->add(<<END); 791 // This is a performance optimization hack. See V8Element::wrap. 792 friend v8::Handle<v8::Object> wrap(Node*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 793 END 794 } 795 796 my $noToV8 = $interface->extendedAttributes->{"DoNotGenerateToV8"}; 797 my $noWrap = $interface->extendedAttributes->{"DoNotGenerateWrap"} || $noToV8; 798 if (!$noWrap) { 799 my $createWrapperArgumentType = GetPassRefPtrType($nativeType); 800 $header{classPrivate}->add(<<END); 801 friend v8::Handle<v8::Object> wrap(${nativeType}*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 802 static v8::Handle<v8::Object> createWrapper(${createWrapperArgumentType}, v8::Handle<v8::Object> creationContext, v8::Isolate*); 803 END 804 } 805 806 $header{nameSpaceWebCore}->add(<<END); 807 808 template<> 809 class WrapperTypeTraits<${nativeType} > { 810 public: 811 static WrapperTypeInfo* info() { return &${v8ClassName}::info; } 812 }; 813 814 END 815 816 my $customWrap = $interface->extendedAttributes->{"CustomToV8"}; 817 if ($noToV8) { 818 die "Can't suppress toV8 for subclass\n" if $interface->parent; 819 } elsif ($noWrap) { 820 die "Must have custom toV8\n" if !$customWrap; 821 $header{nameSpaceWebCore}->add(<<END); 822 class ${nativeType}; 823 v8::Handle<v8::Value> toV8(${nativeType}*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 824 v8::Handle<v8::Value> toV8ForMainWorld(${nativeType}*, v8::Handle<v8::Object> creationContext, v8::Isolate*); 825 826 template<class CallbackInfo, class Wrappable> 827 inline v8::Handle<v8::Value> toV8Fast(${nativeType}* impl, const CallbackInfo& callbackInfo, Wrappable*) 828 { 829 return toV8(impl, callbackInfo.Holder(), callbackInfo.GetIsolate()); 830 } 831 832 END 833 } else { 834 835 my $createWrapperCall = $customWrap ? "${v8ClassName}::wrap" : "${v8ClassName}::createWrapper"; 836 837 if ($customWrap) { 838 $header{nameSpaceWebCore}->add(<<END); 839 840 v8::Handle<v8::Object> wrap(${nativeType}* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*); 841 END 842 } else { 843 $header{nameSpaceWebCore}->add(<<END); 844 845 inline v8::Handle<v8::Object> wrap(${nativeType}* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 846 { 847 ASSERT(impl); 848 ASSERT(DOMDataStore::getWrapper<${v8ClassName}>(impl, isolate).IsEmpty()); 849 return $createWrapperCall(impl, creationContext, isolate); 850 } 851 END 852 } 853 854 $header{nameSpaceWebCore}->add(<<END); 855 856 inline v8::Handle<v8::Value> toV8(${nativeType}* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 857 { 858 if (UNLIKELY(!impl)) 859 return v8NullWithCheck(isolate); 860 v8::Handle<v8::Value> wrapper = DOMDataStore::getWrapper<${v8ClassName}>(impl, isolate); 861 if (!wrapper.IsEmpty()) 862 return wrapper; 863 return wrap(impl, creationContext, isolate); 864 } 865 866 inline v8::Handle<v8::Value> toV8ForMainWorld(${nativeType}* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 867 { 868 ASSERT(worldType(isolate) == MainWorld); 869 if (UNLIKELY(!impl)) 870 return v8::Null(isolate); 871 v8::Handle<v8::Value> wrapper = DOMDataStore::getWrapperForMainWorld<${v8ClassName}>(impl); 872 if (!wrapper.IsEmpty()) 873 return wrapper; 874 return wrap(impl, creationContext, isolate); 875 } 876 877 template<class CallbackInfo, class Wrappable> 878 inline v8::Handle<v8::Value> toV8Fast(${nativeType}* impl, const CallbackInfo& callbackInfo, Wrappable* wrappable) 879 { 880 if (UNLIKELY(!impl)) 881 return v8::Null(callbackInfo.GetIsolate()); 882 v8::Handle<v8::Object> wrapper = DOMDataStore::getWrapperFast<${v8ClassName}>(impl, callbackInfo, wrappable); 883 if (!wrapper.IsEmpty()) 884 return wrapper; 885 return wrap(impl, callbackInfo.Holder(), callbackInfo.GetIsolate()); 886 } 887 888 inline v8::Handle<v8::Value> toV8ForMainWorld(PassRefPtr< ${nativeType} > impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 889 { 890 return toV8ForMainWorld(impl.get(), creationContext, isolate); 891 } 892 893 END 894 } 895 896 $header{nameSpaceWebCore}->add(<<END); 897 898 template<class CallbackInfo, class Wrappable> 899 inline v8::Handle<v8::Value> toV8Fast(PassRefPtr< ${nativeType} > impl, const CallbackInfo& callbackInfo, Wrappable* wrappable) 900 { 901 return toV8Fast(impl.get(), callbackInfo, wrappable); 902 } 903 904 inline v8::Handle<v8::Value> toV8(PassRefPtr< ${nativeType} > impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 905 { 906 return toV8(impl.get(), creationContext, isolate); 907 } 908 909 END 910 911 if (IsConstructorTemplate($interface, "Event")) { 912 $header{nameSpaceWebCore}->add("bool fill${implClassName}Init(${implClassName}Init&, const Dictionary&);\n\n"); 913 } 914 } 915 916 sub GetInternalFields 917 { 918 my $interface = shift; 919 920 my @customInternalFields = (); 921 # Event listeners on DOM nodes are explicitly supported in the GC controller. 922 if (!InheritsInterface($interface, "Node") && 923 InheritsInterface($interface, "EventTarget")) { 924 push(@customInternalFields, "eventListenerCacheIndex"); 925 } 926 return @customInternalFields; 927 } 928 929 sub GenerateHeaderCustomInternalFieldIndices 930 { 931 my $interface = shift; 932 my @customInternalFields = GetInternalFields($interface); 933 my $customFieldCounter = 0; 934 foreach my $customInternalField (@customInternalFields) { 935 $header{classPublic}->add(<<END); 936 static const int ${customInternalField} = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; 937 END 938 $customFieldCounter++; 939 } 940 $header{classPublic}->add(<<END); 941 static const int internalFieldCount = v8DefaultWrapperInternalFieldCount + ${customFieldCounter}; 942 END 943 } 944 945 sub GenerateHeaderNamedAndIndexedPropertyAccessors 946 { 947 my $interface = shift; 948 949 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 950 my $hasCustomIndexedGetter = $indexedGetterFunction && $indexedGetterFunction->extendedAttributes->{"Custom"}; 951 952 my $indexedSetterFunction = GetIndexedSetterFunction($interface); 953 my $hasCustomIndexedSetter = $indexedSetterFunction && $indexedSetterFunction->extendedAttributes->{"Custom"}; 954 955 my $indexedDeleterFunction = GetIndexedDeleterFunction($interface); 956 my $hasCustomIndexedDeleters = $indexedDeleterFunction && $indexedDeleterFunction->extendedAttributes->{"Custom"}; 957 958 my $namedGetterFunction = GetNamedGetterFunction($interface); 959 my $hasCustomNamedGetter = $namedGetterFunction && $namedGetterFunction->extendedAttributes->{"Custom"}; 960 961 my $namedSetterFunction = GetNamedSetterFunction($interface); 962 my $hasCustomNamedSetter = $namedSetterFunction && $namedSetterFunction->extendedAttributes->{"Custom"}; 963 964 my $namedDeleterFunction = GetNamedDeleterFunction($interface); 965 my $hasCustomNamedDeleter = $namedDeleterFunction && $namedDeleterFunction->extendedAttributes->{"Custom"}; 966 967 my $namedEnumeratorFunction = $namedGetterFunction && !$namedGetterFunction->extendedAttributes->{"NotEnumerable"}; 968 my $hasCustomNamedEnumerator = $namedGetterFunction && $namedGetterFunction->extendedAttributes->{"CustomEnumerateProperty"}; 969 970 if ($hasCustomIndexedGetter) { 971 $header{classPublic}->add(" static void indexedPropertyGetterCustom(uint32_t, const v8::PropertyCallbackInfo<v8::Value>&);\n"); 972 } 973 974 if ($hasCustomIndexedSetter) { 975 $header{classPublic}->add(" static void indexedPropertySetterCustom(uint32_t, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<v8::Value>&);\n"); 976 } 977 978 if ($hasCustomIndexedDeleters) { 979 $header{classPublic}->add(" static void indexedPropertyDeleterCustom(uint32_t, const v8::PropertyCallbackInfo<v8::Boolean>&);\n"); 980 } 981 982 if ($hasCustomNamedGetter) { 983 $header{classPublic}->add(" static void namedPropertyGetterCustom(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value>&);\n"); 984 } 985 986 if ($hasCustomNamedSetter) { 987 $header{classPublic}->add(" static void namedPropertySetterCustom(v8::Local<v8::String>, v8::Local<v8::Value>, const v8::PropertyCallbackInfo<v8::Value>&);\n"); 988 } 989 990 if ($hasCustomNamedDeleter) { 991 $header{classPublic}->add(" static void namedPropertyDeleterCustom(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Boolean>&);\n"); 992 } 993 994 if ($hasCustomNamedEnumerator) { 995 $header{classPublic}->add(" static void namedPropertyEnumeratorCustom(const v8::PropertyCallbackInfo<v8::Array>&);\n"); 996 $header{classPublic}->add(" static void namedPropertyQueryCustom(v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Integer>&);\n"); 997 } 998 } 999 1000 sub GenerateHeaderLegacyCall 1001 { 1002 my $interface = shift; 1003 1004 if ($interface->extendedAttributes->{"CustomLegacyCall"}) { 1005 $header{classPublic}->add(" static void legacyCallCustom(const v8::FunctionCallbackInfo<v8::Value>&);\n"); 1006 } 1007 } 1008 1009 sub HasActivityLogging 1010 { 1011 my $forMainWorldSuffix = shift; 1012 my $attrExt = shift; 1013 my $access = shift; 1014 1015 if (!$attrExt->{"ActivityLog"}) { 1016 return 0; 1017 } 1018 my $logAllAccess = ($attrExt->{"ActivityLog"} =~ /^Access/); 1019 my $logGetter = ($attrExt->{"ActivityLog"} =~ /^Getter/); 1020 my $logSetter = ($attrExt->{"ActivityLog"} =~ /^Setter/); 1021 my $logOnlyIsolatedWorlds = ($attrExt->{"ActivityLog"} =~ /ForIsolatedWorlds$/); 1022 1023 if ($logOnlyIsolatedWorlds && $forMainWorldSuffix eq "ForMainWorld") { 1024 return 0; 1025 } 1026 return $logAllAccess || ($logGetter && $access eq "Getter") || ($logSetter && $access eq "Setter"); 1027 } 1028 1029 sub IsConstructable 1030 { 1031 my $interface = shift; 1032 1033 return $interface->extendedAttributes->{"CustomConstructor"} || $interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"ConstructorTemplate"}; 1034 } 1035 1036 sub HasCustomConstructor 1037 { 1038 my $interface = shift; 1039 1040 return $interface->extendedAttributes->{"CustomConstructor"}; 1041 } 1042 1043 sub HasCustomGetter 1044 { 1045 my $attrExt = shift; 1046 return $attrExt->{"Custom"} || $attrExt->{"CustomGetter"}; 1047 } 1048 1049 sub HasCustomSetter 1050 { 1051 my $attrExt = shift; 1052 return $attrExt->{"Custom"} || $attrExt->{"CustomSetter"}; 1053 } 1054 1055 sub HasCustomMethod 1056 { 1057 my $attrExt = shift; 1058 return $attrExt->{"Custom"}; 1059 } 1060 1061 sub IsReadonly 1062 { 1063 my $attribute = shift; 1064 my $attrExt = $attribute->extendedAttributes; 1065 return $attribute->isReadOnly && !$attrExt->{"Replaceable"}; 1066 } 1067 1068 sub GetV8ClassName 1069 { 1070 my $interface = shift; 1071 return "V8" . $interface->name; 1072 } 1073 1074 sub GetImplName 1075 { 1076 my $interfaceOrAttributeOrFunction = shift; 1077 return $interfaceOrAttributeOrFunction->extendedAttributes->{"ImplementedAs"} || $interfaceOrAttributeOrFunction->name; 1078 } 1079 1080 sub GetImplNameFromImplementedBy 1081 { 1082 my $implementedBy = shift; 1083 1084 my $interface = ParseInterface($implementedBy); 1085 1086 return $interface->extendedAttributes->{"ImplementedAs"} || $implementedBy; 1087 } 1088 1089 sub GenerateDomainSafeFunctionGetter 1090 { 1091 my $function = shift; 1092 my $interface = shift; 1093 1094 my $implClassName = GetImplName($interface); 1095 my $v8ClassName = GetV8ClassName($interface); 1096 my $funcName = $function->name; 1097 1098 my $functionLength = GetFunctionLength($function); 1099 my $signature = "v8::Signature::New(V8PerIsolateData::from(info.GetIsolate())->rawTemplate(&" . $v8ClassName . "::info, currentWorldType))"; 1100 if ($function->extendedAttributes->{"DoNotCheckSignature"}) { 1101 $signature = "v8::Local<v8::Signature>()"; 1102 } 1103 1104 my $newTemplateParams = "${implClassName}V8Internal::${funcName}MethodCallback, v8Undefined(), $signature"; 1105 1106 AddToImplIncludes("core/page/Frame.h"); 1107 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 1108 $implementation{nameSpaceInternal}->add(<<END); 1109 static void ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) 1110 { 1111 // This is only for getting a unique pointer which we can pass to privateTemplate. 1112 static const char* privateTemplateUniqueKey = "${funcName}PrivateTemplate"; 1113 WrapperWorldType currentWorldType = worldType(info.GetIsolate()); 1114 V8PerIsolateData* data = V8PerIsolateData::from(info.GetIsolate()); 1115 v8::Handle<v8::FunctionTemplate> privateTemplate = data->privateTemplate(currentWorldType, &privateTemplateUniqueKey, $newTemplateParams, $functionLength); 1116 1117 v8::Handle<v8::Object> holder = info.This()->FindInstanceInPrototypeChain(${v8ClassName}::GetTemplate(info.GetIsolate(), currentWorldType)); 1118 if (holder.IsEmpty()) { 1119 // can only reach here by 'object.__proto__.func', and it should passed 1120 // domain security check already 1121 v8SetReturnValue(info, privateTemplate->GetFunction()); 1122 return; 1123 } 1124 ${implClassName}* imp = ${v8ClassName}::toNative(holder); 1125 if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame(), DoNotReportSecurityError)) { 1126 static const char* sharedTemplateUniqueKey = "${funcName}SharedTemplate"; 1127 v8::Handle<v8::FunctionTemplate> sharedTemplate = data->privateTemplate(currentWorldType, &sharedTemplateUniqueKey, $newTemplateParams, $functionLength); 1128 v8SetReturnValue(info, sharedTemplate->GetFunction()); 1129 return; 1130 } 1131 1132 v8::Local<v8::Value> hiddenValue = info.This()->GetHiddenValue(name); 1133 if (!hiddenValue.IsEmpty()) { 1134 v8SetReturnValue(info, hiddenValue); 1135 return; 1136 } 1137 1138 v8SetReturnValue(info, privateTemplate->GetFunction()); 1139 } 1140 1141 END 1142 $implementation{nameSpaceInternal}->add(<<END); 1143 static void ${funcName}AttrGetterCallback(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) 1144 { 1145 TRACE_EVENT_SET_SAMPLING_STATE("Blink", "DOMGetter"); 1146 ${implClassName}V8Internal::${funcName}AttrGetter(name, info); 1147 TRACE_EVENT_SET_SAMPLING_STATE("V8", "Execution"); 1148 } 1149 1150 END 1151 } 1152 1153 sub GenerateDomainSafeFunctionSetter 1154 { 1155 my $interface = shift; 1156 1157 my $implClassName = GetImplName($interface); 1158 my $v8ClassName = GetV8ClassName($interface); 1159 1160 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 1161 $implementation{nameSpaceInternal}->add(<<END); 1162 static void ${implClassName}DomainSafeFunctionSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) 1163 { 1164 v8::Handle<v8::Object> holder = info.This()->FindInstanceInPrototypeChain(${v8ClassName}::GetTemplate(info.GetIsolate(), worldType(info.GetIsolate()))); 1165 if (holder.IsEmpty()) 1166 return; 1167 ${implClassName}* imp = ${v8ClassName}::toNative(holder); 1168 if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame())) 1169 return; 1170 1171 info.This()->SetHiddenValue(name, value); 1172 } 1173 1174 END 1175 } 1176 1177 sub GenerateConstructorGetter 1178 { 1179 my $interface = shift; 1180 my $implClassName = GetImplName($interface); 1181 1182 $implementation{nameSpaceInternal}->add(<<END); 1183 static void ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) 1184 { 1185 v8::Handle<v8::Value> data = info.Data(); 1186 ASSERT(data->IsExternal()); 1187 V8PerContextData* perContextData = V8PerContextData::from(info.Holder()->CreationContext()); 1188 if (!perContextData) 1189 return; 1190 v8SetReturnValue(info, perContextData->constructorForType(WrapperTypeInfo::unwrap(data))); 1191 } 1192 END 1193 } 1194 1195 sub GenerateFeatureObservation 1196 { 1197 my $measureAs = shift; 1198 1199 if ($measureAs) { 1200 AddToImplIncludes("core/page/UseCounter.h"); 1201 return " UseCounter::count(activeDOMWindow(), UseCounter::${measureAs});\n"; 1202 } 1203 1204 return ""; 1205 } 1206 1207 sub GenerateDeprecationNotification 1208 { 1209 my $deprecateAs = shift; 1210 if ($deprecateAs) { 1211 AddToImplIncludes("core/page/PageConsole.h"); 1212 AddToImplIncludes("core/page/UseCounter.h"); 1213 return " UseCounter::countDeprecation(activeDOMWindow(), UseCounter::${deprecateAs});\n"; 1214 } 1215 return ""; 1216 } 1217 1218 sub GenerateActivityLogging 1219 { 1220 my $accessType = shift; 1221 my $interface = shift; 1222 my $propertyName = shift; 1223 1224 my $interfaceName = $interface->name; 1225 1226 AddToImplIncludes("bindings/v8/V8Binding.h"); 1227 AddToImplIncludes("bindings/v8/V8DOMActivityLogger.h"); 1228 AddToImplIncludes("wtf/Vector.h"); 1229 1230 my $code = ""; 1231 if ($accessType eq "Method") { 1232 $code .= <<END; 1233 V8PerContextData* contextData = V8PerContextData::from(args.GetIsolate()->GetCurrentContext()); 1234 if (contextData && contextData->activityLogger()) { 1235 Vector<v8::Handle<v8::Value> > loggerArgs = toVectorOfArguments(args); 1236 contextData->activityLogger()->log("${interfaceName}.${propertyName}", args.Length(), loggerArgs.data(), "${accessType}"); 1237 } 1238 END 1239 } elsif ($accessType eq "Setter") { 1240 $code .= <<END; 1241 V8PerContextData* contextData = V8PerContextData::from(info.GetIsolate()->GetCurrentContext()); 1242 if (contextData && contextData->activityLogger()) { 1243 v8::Handle<v8::Value> loggerArg[] = { value }; 1244 contextData->activityLogger()->log("${interfaceName}.${propertyName}", 1, &loggerArg[0], "${accessType}"); 1245 } 1246 END 1247 } elsif ($accessType eq "Getter") { 1248 $code .= <<END; 1249 V8PerContextData* contextData = V8PerContextData::from(info.GetIsolate()->GetCurrentContext()); 1250 if (contextData && contextData->activityLogger()) 1251 contextData->activityLogger()->log("${interfaceName}.${propertyName}", 0, 0, "${accessType}"); 1252 END 1253 } else { 1254 die "Unrecognized activity logging access type"; 1255 } 1256 1257 return $code; 1258 } 1259 1260 sub GenerateNormalAttrGetterCallback 1261 { 1262 my $attribute = shift; 1263 my $interface = shift; 1264 my $forMainWorldSuffix = shift; 1265 1266 my $implClassName = GetImplName($interface); 1267 my $v8ClassName = GetV8ClassName($interface); 1268 my $attrExt = $attribute->extendedAttributes; 1269 my $attrName = $attribute->name; 1270 1271 my $conditionalString = GenerateConditionalString($attribute); 1272 my $code = ""; 1273 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 1274 1275 $code .= "static void ${attrName}AttrGetterCallback${forMainWorldSuffix}(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 1276 $code .= "{\n"; 1277 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMGetter\");\n"; 1278 $code .= GenerateFeatureObservation($attrExt->{"MeasureAs"}); 1279 $code .= GenerateDeprecationNotification($attrExt->{"DeprecateAs"}); 1280 if (HasActivityLogging($forMainWorldSuffix, $attrExt, "Getter")) { 1281 $code .= GenerateActivityLogging("Getter", $interface, "${attrName}"); 1282 } 1283 if (HasCustomGetter($attrExt)) { 1284 $code .= " ${v8ClassName}::${attrName}AttrGetterCustom(name, info);\n"; 1285 } else { 1286 $code .= " ${implClassName}V8Internal::${attrName}AttrGetter${forMainWorldSuffix}(name, info);\n"; 1287 } 1288 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 1289 $code .= "}\n\n"; 1290 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1291 1292 $implementation{nameSpaceInternal}->add($code); 1293 } 1294 1295 sub GenerateNormalAttrGetter 1296 { 1297 my $attribute = shift; 1298 my $interface = shift; 1299 my $forMainWorldSuffix = shift; 1300 1301 my $interfaceName = $interface->name; 1302 my $implClassName = GetImplName($interface); 1303 my $v8ClassName = GetV8ClassName($interface); 1304 my $attrExt = $attribute->extendedAttributes; 1305 my $attrName = $attribute->name; 1306 my $attrType = $attribute->type; 1307 1308 if (HasCustomGetter($attrExt)) { 1309 return; 1310 } 1311 1312 AssertNotSequenceType($attrType); 1313 my $nativeType = GetNativeType($attribute->type, $attribute->extendedAttributes, ""); 1314 my $svgNativeType = GetSVGTypeNeedingTearOff($interfaceName); 1315 1316 my $conditionalString = GenerateConditionalString($attribute); 1317 my $code = ""; 1318 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 1319 $code .= <<END; 1320 static void ${attrName}AttrGetter${forMainWorldSuffix}(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) 1321 { 1322 END 1323 if ($svgNativeType) { 1324 my $svgWrappedNativeType = GetSVGWrappedTypeNeedingTearOff($interfaceName); 1325 if ($svgWrappedNativeType =~ /List/) { 1326 $code .= <<END; 1327 $svgNativeType* imp = ${v8ClassName}::toNative(info.Holder()); 1328 END 1329 } else { 1330 $code .= <<END; 1331 $svgNativeType* wrapper = ${v8ClassName}::toNative(info.Holder()); 1332 $svgWrappedNativeType& impInstance = wrapper->propertyReference(); 1333 $svgWrappedNativeType* imp = &impInstance; 1334 END 1335 } 1336 } elsif ($attrExt->{"OnProto"} || $attrExt->{"Unforgeable"}) { 1337 if ($interfaceName eq "Window") { 1338 $code .= <<END; 1339 v8::Handle<v8::Object> holder = info.Holder(); 1340 END 1341 } else { 1342 # perform lookup first 1343 $code .= <<END; 1344 v8::Handle<v8::Object> holder = info.This()->FindInstanceInPrototypeChain(${v8ClassName}::GetTemplate(info.GetIsolate(), worldType(info.GetIsolate()))); 1345 if (holder.IsEmpty()) 1346 return; 1347 END 1348 } 1349 $code .= <<END; 1350 ${implClassName}* imp = ${v8ClassName}::toNative(holder); 1351 END 1352 } else { 1353 my $reflect = $attribute->extendedAttributes->{"Reflect"}; 1354 my $url = $attribute->extendedAttributes->{"URL"}; 1355 if ($reflect && !$url && InheritsInterface($interface, "Node") && $attrType eq "DOMString") { 1356 # Generate super-compact call for regular attribute getter: 1357 my ($functionName, @arguments) = GetterExpression($interfaceName, $attribute); 1358 $code .= " Element* imp = V8Element::toNative(info.Holder());\n"; 1359 $code .= " v8SetReturnValueString(info, imp->${functionName}(" . join(", ", @arguments) . "), info.GetIsolate());\n"; 1360 $code .= " return;\n"; 1361 $code .= "}\n\n"; 1362 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1363 $implementation{nameSpaceInternal}->add($code); 1364 return; 1365 # Skip the rest of the function! 1366 } 1367 if ($attribute->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) { 1368 $code .= <<END; 1369 v8::Handle<v8::String> propertyName = v8::String::NewSymbol("${attrName}"); 1370 v8::Handle<v8::Value> value = info.Holder()->GetHiddenValue(propertyName); 1371 if (!value.IsEmpty()) { 1372 v8SetReturnValue(info, value); 1373 return; 1374 } 1375 END 1376 } 1377 if (!$attribute->isStatic) { 1378 $code .= <<END; 1379 ${implClassName}* imp = ${v8ClassName}::toNative(info.Holder()); 1380 END 1381 } 1382 } 1383 1384 # Generate security checks if necessary 1385 if ($attribute->extendedAttributes->{"CheckSecurityForNode"}) { 1386 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 1387 $code .= " if (!BindingSecurity::shouldAllowAccessToNode(imp->" . GetImplName($attribute) . "())) {\n"; 1388 $code .= " v8SetReturnValueNull(info);\n"; 1389 $code .= " return;\n"; 1390 $code .= " }\n"; 1391 } 1392 1393 my $useExceptions = 1 if $attribute->extendedAttributes->{"GetterRaisesException"} || $attribute->extendedAttributes->{"RaisesException"}; 1394 my $isNullable = $attribute->isNullable; 1395 if ($useExceptions) { 1396 AddToImplIncludes("bindings/v8/ExceptionState.h"); 1397 $code .= " ExceptionState es(info.GetIsolate());\n"; 1398 } 1399 1400 if ($isNullable) { 1401 $code .= " bool isNull = false;\n"; 1402 } 1403 1404 my $returnType = $attribute->type; 1405 my $getterString; 1406 1407 my ($functionName, @arguments) = GetterExpression($interfaceName, $attribute); 1408 push(@arguments, "isNull") if $isNullable; 1409 push(@arguments, "es") if $useExceptions; 1410 if ($attribute->extendedAttributes->{"ImplementedBy"}) { 1411 my $implementedBy = $attribute->extendedAttributes->{"ImplementedBy"}; 1412 my $implementedByImplName = GetImplNameFromImplementedBy($implementedBy); 1413 AddToImplIncludes(HeaderFilesForInterface($implementedBy, $implementedByImplName)); 1414 unshift(@arguments, "imp") if !$attribute->isStatic; 1415 $functionName = "${implementedByImplName}::${functionName}"; 1416 } elsif ($attribute->isStatic) { 1417 $functionName = "${implClassName}::${functionName}"; 1418 } else { 1419 $functionName = "imp->${functionName}"; 1420 } 1421 my ($arg, $subCode) = GenerateCallWith($attribute->extendedAttributes->{"CallWith"}, " ", 0); 1422 $code .= $subCode; 1423 unshift(@arguments, @$arg); 1424 $getterString = "${functionName}(" . join(", ", @arguments) . ")"; 1425 1426 my $expression; 1427 if ($attribute->type eq "EventHandler" && $interface->name eq "Window") { 1428 $code .= " if (!imp->document())\n"; 1429 $code .= " return;\n"; 1430 } 1431 1432 if ($useExceptions || $isNullable) { 1433 if ($nativeType =~ /^V8StringResource/) { 1434 $code .= " " . ConvertToV8StringResource($attribute, $nativeType, "v", $getterString) . ";\n"; 1435 } else { 1436 $code .= " $nativeType v = $getterString;\n"; 1437 } 1438 1439 if ($isNullable) { 1440 $code .= " if (isNull) {\n"; 1441 $code .= " v8SetReturnValueNull(info);\n"; 1442 $code .= " return;\n"; 1443 $code .= " }\n"; 1444 } 1445 1446 if ($useExceptions) { 1447 if ($useExceptions) { 1448 $code .= " if (UNLIKELY(es.throwIfNeeded()))\n"; 1449 $code .= " return;\n"; 1450 } 1451 1452 if (ExtendedAttributeContains($attribute->extendedAttributes->{"CallWith"}, "ScriptState")) { 1453 $code .= " if (state.hadException()) {\n"; 1454 $code .= " throwError(state.exception());\n"; 1455 $code .= " return;\n"; 1456 $code .= " }\n"; 1457 } 1458 } 1459 1460 $expression = "v"; 1461 $expression .= ".release()" if (IsRefPtrType($returnType)); 1462 } else { 1463 # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary 1464 $expression = $getterString; 1465 # Fix amigious conversion problem, by casting to the base type first ($getterString returns a type that inherits from SVGAnimatedEnumeration, not the base class directly). 1466 $expression = "static_pointer_cast<SVGAnimatedEnumeration>($expression)" if $returnType eq "SVGAnimatedEnumeration"; 1467 } 1468 1469 if (ShouldKeepAttributeAlive($interface, $attribute, $returnType)) { 1470 my $arrayType = GetArrayType($returnType); 1471 if ($arrayType) { 1472 AddIncludeForType("V8$arrayType.h"); 1473 $code .= " v8SetReturnValue(info, v8Array(${getterString}, info.GetIsolate()));\n"; 1474 $code .= " return;\n"; 1475 $code .= "}\n\n"; 1476 $implementation{nameSpaceInternal}->add($code); 1477 return; 1478 } 1479 1480 AddIncludesForType($returnType); 1481 AddToImplIncludes("bindings/v8/V8HiddenPropertyName.h"); 1482 # Check for a wrapper in the wrapper cache. If there is one, we know that a hidden reference has already 1483 # been created. If we don't find a wrapper, we create both a wrapper and a hidden reference. 1484 my $nativeReturnType = GetNativeType($returnType); 1485 my $v8ReturnType = "V8" . $returnType; 1486 $code .= " $nativeReturnType result = ${getterString};\n"; 1487 if ($forMainWorldSuffix) { 1488 $code .= " v8::Handle<v8::Value> wrapper = result.get() ? v8::Handle<v8::Value>(DOMDataStore::getWrapper${forMainWorldSuffix}<${v8ReturnType}>(result.get())) : v8Undefined();\n"; 1489 } else { 1490 $code .= " v8::Handle<v8::Value> wrapper = result.get() ? v8::Handle<v8::Value>(DOMDataStore::getWrapper<${v8ReturnType}>(result.get(), info.GetIsolate())) : v8Undefined();\n"; 1491 } 1492 $code .= " if (wrapper.IsEmpty()) {\n"; 1493 $code .= " wrapper = toV8(result.get(), info.Holder(), info.GetIsolate());\n"; # FIXME: Could use wrap here since the wrapper is empty. 1494 $code .= " if (!wrapper.IsEmpty())\n"; 1495 $code .= " V8HiddenPropertyName::setNamedHiddenReference(info.Holder(), \"${attrName}\", wrapper);\n"; 1496 $code .= " }\n"; 1497 $code .= " v8SetReturnValue(info, wrapper);\n"; 1498 $code .= " return;\n"; 1499 $code .= "}\n\n"; 1500 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1501 $implementation{nameSpaceInternal}->add($code); 1502 return; 1503 } 1504 1505 if ((IsSVGAnimatedType($interfaceName) or $interfaceName eq "SVGViewSpec") and IsSVGTypeNeedingTearOff($attrType)) { 1506 AddToImplIncludes("V8$attrType.h"); 1507 my $svgNativeType = GetSVGTypeNeedingTearOff($attrType); 1508 # Convert from abstract SVGProperty to real type, so the right toJS() method can be invoked. 1509 if ($forMainWorldSuffix eq "ForMainWorld") { 1510 $code .= " v8SetReturnValue(info, toV8ForMainWorld(static_cast<$svgNativeType*>($expression), info.Holder(), info.GetIsolate()));\n"; 1511 } else { 1512 $code .= " v8SetReturnValue(info, toV8Fast(static_cast<$svgNativeType*>($expression), info, imp));\n"; 1513 } 1514 $code .= " return;\n"; 1515 } elsif (IsSVGTypeNeedingTearOff($attrType) and not $interfaceName =~ /List$/) { 1516 AddToImplIncludes("V8$attrType.h"); 1517 AddToImplIncludes("core/svg/properties/SVGPropertyTearOff.h"); 1518 my $tearOffType = GetSVGTypeNeedingTearOff($attrType); 1519 my $wrappedValue; 1520 if (IsSVGTypeWithWritablePropertiesNeedingTearOff($attrType) and not defined $attribute->extendedAttributes->{"Immutable"}) { 1521 my $getter = $expression; 1522 $getter =~ s/imp->//; 1523 $getter =~ s/\(\)//; 1524 1525 my $updateMethod = "&${implClassName}::update" . FirstLetterToUpperCase($getter); 1526 1527 my $selfIsTearOffType = IsSVGTypeNeedingTearOff($interfaceName); 1528 if ($selfIsTearOffType) { 1529 AddToImplIncludes("core/svg/properties/SVGMatrixTearOff.h"); 1530 # FIXME: Don't create a new one everytime we access the matrix property. This means, e.g, === won't work. 1531 $wrappedValue = "WTF::getPtr(SVGMatrixTearOff::create(wrapper, $expression))"; 1532 } else { 1533 AddToImplIncludes("core/svg/properties/SVGStaticPropertyTearOff.h"); 1534 $tearOffType =~ s/SVGPropertyTearOff</SVGStaticPropertyTearOff<$implClassName, /; 1535 1536 $wrappedValue = "WTF::getPtr(${tearOffType}::create(imp, $expression, $updateMethod))"; 1537 } 1538 } elsif ($tearOffType =~ /SVGStaticListPropertyTearOff/) { 1539 $wrappedValue = "WTF::getPtr(${tearOffType}::create(imp, $expression))"; 1540 } elsif ($tearOffType =~ /SVG(Point|PathSeg)List/) { 1541 $wrappedValue = "WTF::getPtr($expression)"; 1542 } else { 1543 $wrappedValue = "WTF::getPtr(${tearOffType}::create($expression))"; 1544 } 1545 if ($forMainWorldSuffix eq "ForMainWorld") { 1546 $code .= " v8SetReturnValue(info, toV8ForMainWorld($wrappedValue, info.Holder(), info.GetIsolate()));\n"; 1547 } else { 1548 $code .= " v8SetReturnValue(info, toV8Fast($wrappedValue, info, imp));\n"; 1549 } 1550 $code .= " return;\n"; 1551 } elsif ($attribute->type eq "SerializedScriptValue" && $attrExt->{"CachedAttribute"}) { 1552 my $getterFunc = ToMethodName($attribute->name); 1553 $code .= <<END; 1554 RefPtr<SerializedScriptValue> serialized = imp->${getterFunc}(); 1555 value = serialized ? serialized->deserialize() : v8::Handle<v8::Value>(v8::Null(info.GetIsolate())); 1556 info.Holder()->SetHiddenValue(propertyName, value); 1557 v8SetReturnValue(info, value); 1558 return; 1559 END 1560 } elsif ($attribute->type eq "EventHandler") { 1561 AddToImplIncludes("bindings/v8/V8AbstractEventListener.h"); 1562 my $getterFunc = ToMethodName($attribute->name); 1563 # FIXME: Pass the main world ID for main-world-only getters. 1564 $code .= " EventListener* listener = imp->${getterFunc}(isolatedWorldForIsolate(info.GetIsolate()));\n"; 1565 $code .= " v8SetReturnValue(info, listener ? v8::Handle<v8::Value>(V8AbstractEventListener::cast(listener)->getListenerObject(imp->scriptExecutionContext())) : v8::Handle<v8::Value>(v8::Null(info.GetIsolate())));\n"; 1566 $code .= " return;\n"; 1567 } else { 1568 my $nativeValue = NativeToJSValue($attribute->type, $attribute->extendedAttributes, $expression, " ", "", "info.Holder()", "info.GetIsolate()", "info", "imp", $forMainWorldSuffix, "return"); 1569 $code .= "${nativeValue}\n"; 1570 $code .= " return;\n"; 1571 } 1572 1573 $code .= "}\n\n"; # end of getter 1574 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1575 $implementation{nameSpaceInternal}->add($code); 1576 } 1577 1578 sub ShouldKeepAttributeAlive 1579 { 1580 my ($interface, $attribute, $returnType) = @_; 1581 my $attrName = $attribute->name; 1582 1583 return 1 if $attribute->extendedAttributes->{"KeepAttributeAliveForGC"}; 1584 1585 # Basically, for readonly or replaceable attributes, we have to guarantee 1586 # that JS wrappers don't get garbage-collected prematually when their 1587 # lifetime is strongly tied to their owner. 1588 return 0 if !IsWrapperType($returnType); 1589 return 0 if !IsReadonly($attribute) && !$attribute->extendedAttributes->{"Replaceable"}; 1590 1591 # However, there are a couple of exceptions. 1592 1593 # Node lifetime is managed by object grouping. 1594 return 0 if InheritsInterface($interface, "Node"); 1595 return 0 if IsDOMNodeType($returnType); 1596 1597 # To avoid adding a reference to itself. 1598 # FIXME: Introduce [DoNotKeepAttributeAliveForGC] and remove this hack 1599 # depending on the attribute name. 1600 return 0 if $attrName eq "self"; 1601 1602 # FIXME: Remove these hard-coded hacks. 1603 return 0 if $returnType eq "EventTarget"; 1604 return 0 if $returnType eq "SerializedScriptValue"; 1605 return 0 if $returnType eq "Window"; 1606 return 0 if $returnType =~ /SVG/; 1607 return 0 if $returnType =~ /HTML/; 1608 1609 return 1; 1610 } 1611 1612 sub GenerateReplaceableAttrSetterCallback 1613 { 1614 my $interface = shift; 1615 my $implClassName = GetImplName($interface); 1616 1617 my $code = ""; 1618 $code .= "static void ${implClassName}ReplaceableAttrSetterCallback(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info)\n"; 1619 $code .= "{\n"; 1620 $code .= GenerateFeatureObservation($interface->extendedAttributes->{"MeasureAs"}); 1621 $code .= GenerateDeprecationNotification($interface->extendedAttributes->{"DeprecateAs"}); 1622 $code .= GenerateCustomElementInvocationScopeIfNeeded($interface->extendedAttributes); 1623 if (HasActivityLogging("", $interface->extendedAttributes, "Setter")) { 1624 die "IDL error: ActivityLog attribute cannot exist on a ReplacableAttrSetterCallback"; 1625 } 1626 $code .= " ${implClassName}V8Internal::${implClassName}ReplaceableAttrSetter(name, value, info);\n"; 1627 $code .= "}\n\n"; 1628 $implementation{nameSpaceInternal}->add($code); 1629 } 1630 1631 sub GenerateReplaceableAttrSetter 1632 { 1633 my $interface = shift; 1634 1635 my $implClassName = GetImplName($interface); 1636 my $v8ClassName = GetV8ClassName($interface); 1637 1638 my $code = ""; 1639 $code .= <<END; 1640 static void ${implClassName}ReplaceableAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) 1641 { 1642 END 1643 if ($interface->extendedAttributes->{"CheckSecurity"}) { 1644 AddToImplIncludes("core/page/Frame.h"); 1645 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 1646 $code .= <<END; 1647 ${implClassName}* imp = ${v8ClassName}::toNative(info.Holder()); 1648 if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame())) 1649 return; 1650 END 1651 } 1652 1653 $code .= <<END; 1654 info.This()->ForceSet(name, value); 1655 } 1656 1657 END 1658 $implementation{nameSpaceInternal}->add($code); 1659 } 1660 1661 sub GenerateCustomElementInvocationScopeIfNeeded 1662 { 1663 my $code = ""; 1664 my $ext = shift; 1665 my $annotation = $ext->{"CustomElementCallbacks"} || ""; 1666 1667 if ($annotation eq "None") { 1668 # Explicit CustomElementCallbacks=None overrides any other 1669 # heuristic. 1670 return $code; 1671 } 1672 1673 if ($annotation eq "Enable" or $ext->{"Reflect"}) { 1674 AddToImplIncludes("core/dom/CustomElementCallbackDispatcher.h"); 1675 $code .= <<END; 1676 CustomElementCallbackDispatcher::CallbackDeliveryScope deliveryScope; 1677 END 1678 } 1679 return $code; 1680 } 1681 1682 sub GenerateNormalAttrSetterCallback 1683 { 1684 my $attribute = shift; 1685 my $interface = shift; 1686 my $forMainWorldSuffix = shift; 1687 1688 my $implClassName = GetImplName($interface); 1689 my $v8ClassName = GetV8ClassName($interface); 1690 my $attrExt = $attribute->extendedAttributes; 1691 my $attrName = $attribute->name; 1692 1693 my $conditionalString = GenerateConditionalString($attribute); 1694 my $code = ""; 1695 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 1696 1697 $code .= "static void ${attrName}AttrSetterCallback${forMainWorldSuffix}(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info)\n"; 1698 $code .= "{\n"; 1699 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMSetter\");\n"; 1700 $code .= GenerateFeatureObservation($attrExt->{"MeasureAs"}); 1701 $code .= GenerateDeprecationNotification($attrExt->{"DeprecateAs"}); 1702 if (HasActivityLogging($forMainWorldSuffix, $attrExt, "Setter")) { 1703 $code .= GenerateActivityLogging("Setter", $interface, "${attrName}"); 1704 } 1705 $code .= GenerateCustomElementInvocationScopeIfNeeded($attrExt); 1706 if (HasCustomSetter($attrExt)) { 1707 $code .= " ${v8ClassName}::${attrName}AttrSetterCustom(name, value, info);\n"; 1708 } else { 1709 $code .= " ${implClassName}V8Internal::${attrName}AttrSetter${forMainWorldSuffix}(name, value, info);\n"; 1710 } 1711 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 1712 $code .= "}\n\n"; 1713 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1714 $implementation{nameSpaceInternal}->add($code); 1715 } 1716 1717 sub GenerateNormalAttrSetter 1718 { 1719 my $attribute = shift; 1720 my $interface = shift; 1721 my $forMainWorldSuffix = shift; 1722 1723 my $interfaceName = $interface->name; 1724 my $implClassName = GetImplName($interface); 1725 my $v8ClassName = GetV8ClassName($interface); 1726 my $attrName = $attribute->name; 1727 my $attrExt = $attribute->extendedAttributes; 1728 my $attrType = $attribute->type; 1729 1730 if (HasCustomSetter($attrExt)) { 1731 return; 1732 } 1733 1734 my $conditionalString = GenerateConditionalString($attribute); 1735 my $code = ""; 1736 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 1737 $code .= "static void ${attrName}AttrSetter${forMainWorldSuffix}(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info)\n"; 1738 $code .= "{\n"; 1739 1740 # If the "StrictTypeChecking" extended attribute is present, and the attribute's type is an 1741 # interface type, then if the incoming value does not implement that interface, a TypeError is 1742 # thrown rather than silently passing NULL to the C++ code. 1743 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted to both 1744 # strings and numbers, so do not throw TypeError if the attribute is of these types. 1745 if ($attribute->extendedAttributes->{"StrictTypeChecking"}) { 1746 my $argType = $attribute->type; 1747 if (IsWrapperType($argType)) { 1748 $code .= " if (!isUndefinedOrNull(value) && !V8${argType}::HasInstance(value, info.GetIsolate(), worldType(info.GetIsolate()))) {\n"; 1749 $code .= " throwTypeError(info.GetIsolate());\n"; 1750 $code .= " return;\n"; 1751 $code .= " }\n"; 1752 } 1753 } 1754 1755 my $svgNativeType = GetSVGTypeNeedingTearOff($interfaceName); 1756 if ($svgNativeType) { 1757 my $svgWrappedNativeType = GetSVGWrappedTypeNeedingTearOff($interfaceName); 1758 if ($svgWrappedNativeType =~ /List$/) { 1759 $code .= <<END; 1760 $svgNativeType* imp = ${v8ClassName}::toNative(info.Holder()); 1761 END 1762 } else { 1763 AddToImplIncludes("bindings/v8/ExceptionState.h"); 1764 $code .= " $svgNativeType* wrapper = ${v8ClassName}::toNative(info.Holder());\n"; 1765 $code .= " if (wrapper->isReadOnly()) {\n"; 1766 $code .= " setDOMException(NoModificationAllowedError, info.GetIsolate());\n"; 1767 $code .= " return;\n"; 1768 $code .= " }\n"; 1769 $code .= " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"; 1770 $code .= " $svgWrappedNativeType* imp = &impInstance;\n"; 1771 } 1772 } elsif ($attrExt->{"OnProto"}) { 1773 $code .= <<END; 1774 ${implClassName}* imp = ${v8ClassName}::toNative(info.Holder()); 1775 END 1776 } else { 1777 my $reflect = $attribute->extendedAttributes->{"Reflect"}; 1778 if ($reflect && InheritsInterface($interface, "Node") && $attrType eq "DOMString") { 1779 # Generate super-compact call for regular attribute setter: 1780 my $contentAttributeName = $reflect eq "VALUE_IS_MISSING" ? lc $attrName : $reflect; 1781 my $namespace = NamespaceForAttributeName($interfaceName, $contentAttributeName); 1782 AddToImplIncludes("${namespace}.h"); 1783 $code .= " Element* imp = V8Element::toNative(info.Holder());\n"; 1784 $code .= " V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<WithNullCheck>, stringResource, value);\n"; 1785 $code .= " imp->setAttribute(${namespace}::${contentAttributeName}Attr, stringResource);\n"; 1786 $code .= "}\n\n"; 1787 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1788 $implementation{nameSpaceInternal}->add($code); 1789 return; 1790 # Skip the rest of the function! 1791 } 1792 1793 if (!$attribute->isStatic) { 1794 $code .= <<END; 1795 ${implClassName}* imp = ${v8ClassName}::toNative(info.Holder()); 1796 END 1797 } 1798 } 1799 1800 my $nativeType = GetNativeType($attribute->type, $attribute->extendedAttributes, "parameter"); 1801 if ($attribute->type eq "EventHandler") { 1802 if ($interface->name eq "Window") { 1803 $code .= " if (!imp->document())\n"; 1804 $code .= " return;\n"; 1805 } 1806 } else { 1807 $code .= JSValueToNativeStatement($attribute->type, $attribute->extendedAttributes, "value", "v", " ", "info.GetIsolate()"); 1808 } 1809 1810 if (IsEnumType($attrType)) { 1811 # setter ignores invalid enumeration values 1812 my @enumValues = ValidEnumValues($attrType); 1813 my @validEqualities = (); 1814 foreach my $enumValue (@enumValues) { 1815 push(@validEqualities, "string == \"$enumValue\""); 1816 } 1817 my $enumValidationExpression = join(" || ", @validEqualities); 1818 $code .= <<END; 1819 String string = v; 1820 if (!($enumValidationExpression)) 1821 return; 1822 END 1823 } 1824 1825 my $expression = "v"; 1826 my $returnType = $attribute->type; 1827 if (IsRefPtrType($returnType) && !GetArrayType($returnType)) { 1828 $expression = "WTF::getPtr(" . $expression . ")"; 1829 } 1830 1831 $code .= GenerateCustomElementInvocationScopeIfNeeded($attribute->extendedAttributes); 1832 1833 my $useExceptions = 1 if $attribute->extendedAttributes->{"SetterRaisesException"} || $attribute->extendedAttributes->{"RaisesException"}; 1834 1835 if ($useExceptions) { 1836 AddToImplIncludes("bindings/v8/ExceptionState.h"); 1837 $code .= " ExceptionState es(info.GetIsolate());\n"; 1838 } 1839 1840 if ($attribute->type eq "EventHandler") { 1841 my $implSetterFunctionName = FirstLetterToUpperCase($attrName); 1842 AddToImplIncludes("bindings/v8/V8AbstractEventListener.h"); 1843 # Non callable input should be treated as null 1844 $code .= " if (!value->IsNull() && !value->IsFunction())\n"; 1845 $code .= " value = v8::Null(info.GetIsolate());\n"; 1846 if (!InheritsInterface($interface, "Node")) { 1847 my $attrImplName = GetImplName($attribute); 1848 $code .= " transferHiddenDependency(info.Holder(), imp->${attrImplName}(isolatedWorldForIsolate(info.GetIsolate())), value, ${v8ClassName}::eventListenerCacheIndex, info.GetIsolate());\n"; 1849 } 1850 AddToImplIncludes("bindings/v8/V8EventListenerList.h"); 1851 if (($interfaceName eq "Window" or $interfaceName eq "WorkerGlobalScope") and $attribute->name eq "onerror") { 1852 AddToImplIncludes("bindings/v8/V8ErrorHandler.h"); 1853 $code .= " imp->set$implSetterFunctionName(V8EventListenerList::findOrCreateWrapper<V8ErrorHandler>(value, true), isolatedWorldForIsolate(info.GetIsolate()));\n"; 1854 } else { 1855 $code .= " imp->set$implSetterFunctionName(V8EventListenerList::getEventListener(value, true, ListenerFindOrCreate), isolatedWorldForIsolate(info.GetIsolate()));\n"; 1856 } 1857 } else { 1858 my ($functionName, @arguments) = SetterExpression($interfaceName, $attribute); 1859 push(@arguments, $expression); 1860 push(@arguments, "es") if $useExceptions; 1861 if ($attribute->extendedAttributes->{"ImplementedBy"}) { 1862 my $implementedBy = $attribute->extendedAttributes->{"ImplementedBy"}; 1863 my $implementedByImplName = GetImplNameFromImplementedBy($implementedBy); 1864 AddToImplIncludes(HeaderFilesForInterface($implementedBy, $implementedByImplName)); 1865 unshift(@arguments, "imp") if !$attribute->isStatic; 1866 $functionName = "${implementedByImplName}::${functionName}"; 1867 } elsif ($attribute->isStatic) { 1868 $functionName = "${implClassName}::${functionName}"; 1869 } else { 1870 $functionName = "imp->${functionName}"; 1871 } 1872 my ($arg, $subCode) = GenerateCallWith($attribute->extendedAttributes->{"SetterCallWith"} || $attribute->extendedAttributes->{"CallWith"}, " ", 1); 1873 $code .= $subCode; 1874 unshift(@arguments, @$arg); 1875 $code .= " ${functionName}(" . join(", ", @arguments) . ");\n"; 1876 } 1877 1878 if ($useExceptions) { 1879 $code .= " es.throwIfNeeded();\n"; 1880 } 1881 1882 if (ExtendedAttributeContains($attribute->extendedAttributes->{"CallWith"}, "ScriptState")) { 1883 $code .= " if (state.hadException())\n"; 1884 $code .= " throwError(state.exception());\n"; 1885 } 1886 1887 if ($svgNativeType) { 1888 if ($useExceptions) { 1889 $code .= " if (!es.hadException())\n"; 1890 $code .= " wrapper->commitChange();\n"; 1891 } else { 1892 $code .= " wrapper->commitChange();\n"; 1893 } 1894 } 1895 1896 if ($attribute->type eq "SerializedScriptValue" && $attribute->extendedAttributes->{"CachedAttribute"}) { 1897 $code .= <<END; 1898 info.Holder()->DeleteHiddenValue(v8::String::NewSymbol("${attrName}")); // Invalidate the cached value. 1899 END 1900 } 1901 1902 $code .= " return;\n"; 1903 $code .= "}\n\n"; # end of setter 1904 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 1905 $implementation{nameSpaceInternal}->add($code); 1906 } 1907 1908 sub GenerateParametersCheckExpression 1909 { 1910 my $numParameters = shift; 1911 my $function = shift; 1912 1913 my @andExpression = (); 1914 push(@andExpression, "args.Length() == $numParameters"); 1915 my $parameterIndex = 0; 1916 foreach my $parameter (@{$function->parameters}) { 1917 last if $parameterIndex >= $numParameters; 1918 my $value = "args[$parameterIndex]"; 1919 my $type = $parameter->type; 1920 1921 # Only DOMString or wrapper types are checked. 1922 # For DOMString with StrictTypeChecking only Null, Undefined and Object 1923 # are accepted for compatibility. Otherwise, no restrictions are made to 1924 # match the non-overloaded behavior. 1925 # FIXME: Implement WebIDL overload resolution algorithm. 1926 if ($type eq "DOMString") { 1927 if ($parameter->extendedAttributes->{"StrictTypeChecking"}) { 1928 push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())"); 1929 } 1930 } elsif (IsCallbackInterface($parameter->type)) { 1931 # For Callbacks only checks if the value is null or object. 1932 push(@andExpression, "(${value}->IsNull() || ${value}->IsFunction())"); 1933 } elsif (GetArrayOrSequenceType($type)) { 1934 if ($parameter->isNullable) { 1935 push(@andExpression, "(${value}->IsNull() || ${value}->IsArray())"); 1936 } else { 1937 push(@andExpression, "(${value}->IsArray())"); 1938 } 1939 } elsif (IsWrapperType($type)) { 1940 if ($parameter->isNullable) { 1941 push(@andExpression, "(${value}->IsNull() || V8${type}::HasInstance($value, args.GetIsolate(), worldType(args.GetIsolate())))"); 1942 } else { 1943 push(@andExpression, "(V8${type}::HasInstance($value, args.GetIsolate(), worldType(args.GetIsolate())))"); 1944 } 1945 } 1946 1947 $parameterIndex++; 1948 } 1949 my $res = join(" && ", @andExpression); 1950 $res = "($res)" if @andExpression > 1; 1951 return $res; 1952 } 1953 1954 # As per Web IDL specification, the length of a function Object is 1955 # its number of mandatory parameters. 1956 sub GetFunctionLength 1957 { 1958 my $function = shift; 1959 1960 my $numMandatoryParams = 0; 1961 foreach my $parameter (@{$function->parameters}) { 1962 # Abort as soon as we find the first optional parameter as no mandatory 1963 # parameter can follow an optional one. 1964 last if $parameter->isOptional; 1965 $numMandatoryParams++; 1966 } 1967 return $numMandatoryParams; 1968 } 1969 1970 sub GenerateFunctionParametersCheck 1971 { 1972 my $function = shift; 1973 1974 my @orExpression = (); 1975 my $numParameters = 0; 1976 my $hasVariadic = 0; 1977 my $numMandatoryParams = @{$function->parameters}; 1978 foreach my $parameter (@{$function->parameters}) { 1979 if ($parameter->isOptional) { 1980 push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); 1981 $numMandatoryParams--; 1982 } 1983 if ($parameter->isVariadic) { 1984 $hasVariadic = 1; 1985 last; 1986 } 1987 $numParameters++; 1988 } 1989 if (!$hasVariadic) { 1990 push(@orExpression, GenerateParametersCheckExpression($numParameters, $function)); 1991 } 1992 return ($numMandatoryParams, join(" || ", @orExpression)); 1993 } 1994 1995 sub GenerateOverloadedFunction 1996 { 1997 my $function = shift; 1998 my $interface = shift; 1999 my $forMainWorldSuffix = shift; 2000 2001 # Generate code for choosing the correct overload to call. Overloads are 2002 # chosen based on the total number of arguments passed and the type of 2003 # values passed in non-primitive argument slots. When more than a single 2004 # overload is applicable, precedence is given according to the order of 2005 # declaration in the IDL. 2006 2007 my $name = $function->name; 2008 2009 my $conditionalString = GenerateConditionalString($function); 2010 my $leastNumMandatoryParams = 255; 2011 my $code = ""; 2012 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 2013 $code .= <<END; 2014 static void ${name}Method${forMainWorldSuffix}(const v8::FunctionCallbackInfo<v8::Value>& args) 2015 { 2016 END 2017 $code .= GenerateFeatureObservation($function->extendedAttributes->{"MeasureAs"}); 2018 $code .= GenerateDeprecationNotification($function->extendedAttributes->{"DeprecateAs"}); 2019 2020 foreach my $overload (@{$function->{overloads}}) { 2021 my ($numMandatoryParams, $parametersCheck) = GenerateFunctionParametersCheck($overload); 2022 $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams); 2023 $code .= " if ($parametersCheck) {\n"; 2024 my $overloadedIndexString = $overload->{overloadIndex}; 2025 $code .= " ${name}${overloadedIndexString}Method${forMainWorldSuffix}(args);\n"; 2026 $code .= " return;\n"; 2027 $code .= " }\n"; 2028 } 2029 if ($leastNumMandatoryParams >= 1) { 2030 $code .= " if (args.Length() < $leastNumMandatoryParams) {\n"; 2031 $code .= " throwNotEnoughArgumentsError(args.GetIsolate());\n"; 2032 $code .= " return;\n"; 2033 $code .= " }\n"; 2034 } 2035 $code .= <<END; 2036 throwTypeError(args.GetIsolate()); 2037 END 2038 $code .= "}\n\n"; 2039 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 2040 $implementation{nameSpaceInternal}->add($code); 2041 } 2042 2043 sub GenerateFunctionCallback 2044 { 2045 my $function = shift; 2046 my $interface = shift; 2047 my $forMainWorldSuffix = shift; 2048 2049 my $implClassName = GetImplName($interface); 2050 my $v8ClassName = GetV8ClassName($interface); 2051 my $name = $function->name; 2052 2053 if ($name eq "") { 2054 return; 2055 } 2056 2057 my $conditionalString = GenerateConditionalString($function); 2058 my $code = ""; 2059 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 2060 $code .= <<END; 2061 static void ${name}MethodCallback${forMainWorldSuffix}(const v8::FunctionCallbackInfo<v8::Value>& args) 2062 { 2063 END 2064 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMMethod\");\n"; 2065 $code .= GenerateFeatureObservation($function->extendedAttributes->{"MeasureAs"}); 2066 $code .= GenerateDeprecationNotification($function->extendedAttributes->{"DeprecateAs"}); 2067 if (HasActivityLogging($forMainWorldSuffix, $function->extendedAttributes, "Access")) { 2068 $code .= GenerateActivityLogging("Method", $interface, "${name}"); 2069 } 2070 if (HasCustomMethod($function->extendedAttributes)) { 2071 $code .= " ${v8ClassName}::${name}MethodCustom(args);\n"; 2072 } else { 2073 $code .= " ${implClassName}V8Internal::${name}Method${forMainWorldSuffix}(args);\n"; 2074 } 2075 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 2076 $code .= "}\n\n"; 2077 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 2078 $implementation{nameSpaceInternal}->add($code); 2079 } 2080 2081 sub GenerateFunction 2082 { 2083 my $function = shift; 2084 my $interface = shift; 2085 my $forMainWorldSuffix = shift; 2086 2087 my $interfaceName = $interface->name; 2088 my $implClassName = GetImplName($interface); 2089 my $v8ClassName = GetV8ClassName($interface); 2090 my $name = $function->name; 2091 my $implName = GetImplName($function); 2092 my $funcExt = $function->extendedAttributes; 2093 2094 if (HasCustomMethod($funcExt) || $name eq "") { 2095 return; 2096 } 2097 2098 if (@{$function->{overloads}} > 1) { 2099 # Append a number to an overloaded method's name to make it unique: 2100 $name = $name . $function->{overloadIndex}; 2101 } 2102 2103 my $conditionalString = GenerateConditionalString($function); 2104 my $code = ""; 2105 $code .= "#if ${conditionalString}\n\n" if $conditionalString; 2106 $code .= "static void ${name}Method${forMainWorldSuffix}(const v8::FunctionCallbackInfo<v8::Value>& args)\n"; 2107 $code .= "{\n"; 2108 2109 if ($name eq "addEventListener" || $name eq "removeEventListener") { 2110 my $lookupType = ($name eq "addEventListener") ? "OrCreate" : "Only"; 2111 my $passRefPtrHandling = ($name eq "addEventListener") ? "" : ".get()"; 2112 my $hiddenDependencyAction = ($name eq "addEventListener") ? "create" : "remove"; 2113 2114 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 2115 AddToImplIncludes("bindings/v8/V8EventListenerList.h"); 2116 AddToImplIncludes("core/page/DOMWindow.h"); 2117 $code .= <<END; 2118 EventTarget* impl = ${v8ClassName}::toNative(args.Holder()); 2119 if (DOMWindow* window = impl->toDOMWindow()) { 2120 if (!BindingSecurity::shouldAllowAccessToFrame(window->frame())) 2121 return; 2122 2123 if (!window->document()) 2124 return; 2125 } 2126 2127 RefPtr<EventListener> listener = V8EventListenerList::getEventListener(args[1], false, ListenerFind${lookupType}); 2128 if (listener) { 2129 V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<WithNullCheck>, stringResource, args[0]); 2130 impl->${implName}(stringResource, listener${passRefPtrHandling}, args[2]->BooleanValue()); 2131 if (!impl->toNode()) 2132 ${hiddenDependencyAction}HiddenDependency(args.Holder(), args[1], ${v8ClassName}::eventListenerCacheIndex, args.GetIsolate()); 2133 } 2134 } 2135 2136 END 2137 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 2138 $implementation{nameSpaceInternal}->add($code); 2139 return; 2140 } 2141 2142 $code .= GenerateArgumentsCountCheck($function, $interface); 2143 2144 if ($name eq "set" and IsConstructorTemplate($interface, "TypedArray")) { 2145 AddToImplIncludes("bindings/v8/custom/V8ArrayBufferViewCustom.h"); 2146 $code .= <<END; 2147 setWebGLArrayHelper<$implClassName, ${v8ClassName}>(args); 2148 } 2149 2150 END 2151 $implementation{nameSpaceInternal}->add($code); 2152 return; 2153 } 2154 2155 my ($svgPropertyType, $svgListPropertyType, $svgNativeType) = GetSVGPropertyTypes($interfaceName); 2156 2157 if ($svgNativeType) { 2158 my $nativeClassName = GetNativeType($interfaceName); 2159 if ($interfaceName =~ /List$/) { 2160 $code .= " $nativeClassName imp = ${v8ClassName}::toNative(args.Holder());\n"; 2161 } else { 2162 AddToImplIncludes("bindings/v8/ExceptionState.h"); 2163 AddToImplIncludes("core/dom/ExceptionCode.h"); 2164 $code .= " $nativeClassName wrapper = ${v8ClassName}::toNative(args.Holder());\n"; 2165 $code .= " if (wrapper->isReadOnly()) {\n"; 2166 $code .= " setDOMException(NoModificationAllowedError, args.GetIsolate());\n"; 2167 $code .= " return;\n"; 2168 $code .= " }\n"; 2169 my $svgWrappedNativeType = GetSVGWrappedTypeNeedingTearOff($interfaceName); 2170 $code .= " $svgWrappedNativeType& impInstance = wrapper->propertyReference();\n"; 2171 $code .= " $svgWrappedNativeType* imp = &impInstance;\n"; 2172 } 2173 } elsif (!$function->isStatic) { 2174 $code .= <<END; 2175 ${implClassName}* imp = ${v8ClassName}::toNative(args.Holder()); 2176 END 2177 } 2178 2179 $code .= GenerateCustomElementInvocationScopeIfNeeded($funcExt); 2180 2181 # Check domain security if needed 2182 if ($interface->extendedAttributes->{"CheckSecurity"} && !$function->extendedAttributes->{"DoNotCheckSecurity"}) { 2183 # We have not find real use cases yet. 2184 AddToImplIncludes("core/page/Frame.h"); 2185 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 2186 $code .= <<END; 2187 if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame())) 2188 return; 2189 END 2190 } 2191 2192 my $raisesExceptions = $function->extendedAttributes->{"RaisesException"}; 2193 if (!$raisesExceptions) { 2194 foreach my $parameter (@{$function->parameters}) { 2195 if ($parameter->extendedAttributes->{"IsIndex"}) { 2196 $raisesExceptions = 1; 2197 } 2198 } 2199 } 2200 2201 if ($raisesExceptions) { 2202 AddToImplIncludes("bindings/v8/ExceptionState.h"); 2203 $code .= " ExceptionState es(args.GetIsolate());\n"; 2204 } 2205 2206 if ($function->extendedAttributes->{"CheckSecurityForNode"}) { 2207 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 2208 $code .= " if (!BindingSecurity::shouldAllowAccessToNode(imp->" . GetImplName($function) . "(es))) {\n"; 2209 $code .= " v8SetReturnValueNull(args);\n"; 2210 $code .= " return;\n"; 2211 $code .= " }\n"; 2212 END 2213 } 2214 2215 my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $interface, $forMainWorldSuffix); 2216 $code .= $parameterCheckString; 2217 2218 # Build the function call string. 2219 $code .= GenerateFunctionCallString($function, $paramIndex, " ", $interface, $forMainWorldSuffix, %replacements); 2220 $code .= "}\n\n"; 2221 $code .= "#endif // ${conditionalString}\n\n" if $conditionalString; 2222 $implementation{nameSpaceInternal}->add($code); 2223 } 2224 2225 sub GenerateCallWith 2226 { 2227 my $callWith = shift; 2228 return ([], "") unless $callWith; 2229 my $indent = shift; 2230 my $returnVoid = shift; 2231 my $function = shift; 2232 my $code = ""; 2233 2234 my @callWithArgs; 2235 if (ExtendedAttributeContains($callWith, "ScriptState")) { 2236 $code .= $indent . "ScriptState* currentState = ScriptState::current();\n"; 2237 $code .= $indent . "if (!currentState)\n"; 2238 $code .= $indent . " return" . ($returnVoid ? "" : " v8Undefined()") . ";\n"; 2239 $code .= $indent . "ScriptState& state = *currentState;\n"; 2240 push(@callWithArgs, "&state"); 2241 } 2242 if (ExtendedAttributeContains($callWith, "ScriptExecutionContext")) { 2243 $code .= $indent . "ScriptExecutionContext* scriptContext = getScriptExecutionContext();\n"; 2244 push(@callWithArgs, "scriptContext"); 2245 } 2246 if ($function and ExtendedAttributeContains($callWith, "ScriptArguments")) { 2247 $code .= $indent . "RefPtr<ScriptArguments> scriptArguments(createScriptArguments(args, " . @{$function->parameters} . "));\n"; 2248 push(@callWithArgs, "scriptArguments.release()"); 2249 AddToImplIncludes("bindings/v8/ScriptCallStackFactory.h"); 2250 AddToImplIncludes("core/inspector/ScriptArguments.h"); 2251 } 2252 if (ExtendedAttributeContains($callWith, "ActiveWindow")) { 2253 push(@callWithArgs, "activeDOMWindow()"); 2254 } 2255 if (ExtendedAttributeContains($callWith, "FirstWindow")) { 2256 push(@callWithArgs, "firstDOMWindow()"); 2257 } 2258 return ([@callWithArgs], $code); 2259 } 2260 2261 sub GenerateArgumentsCountCheck 2262 { 2263 my $function = shift; 2264 my $interface = shift; 2265 2266 my $numMandatoryParams = 0; 2267 my $allowNonOptional = 1; 2268 foreach my $param (@{$function->parameters}) { 2269 if ($param->isOptional or $param->isVariadic) { 2270 $allowNonOptional = 0; 2271 } else { 2272 die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if !$allowNonOptional; 2273 $numMandatoryParams++; 2274 } 2275 } 2276 2277 my $argumentsCountCheckString = ""; 2278 if ($numMandatoryParams >= 1) { 2279 $argumentsCountCheckString .= " if (args.Length() < $numMandatoryParams) {\n"; 2280 $argumentsCountCheckString .= " throwNotEnoughArgumentsError(args.GetIsolate());\n"; 2281 $argumentsCountCheckString .= " return;\n"; 2282 $argumentsCountCheckString .= " }\n"; 2283 } 2284 return $argumentsCountCheckString; 2285 } 2286 2287 sub GenerateParametersCheck 2288 { 2289 my $function = shift; 2290 my $interface = shift; 2291 my $forMainWorldSuffix = shift; 2292 my $style = shift || "new"; 2293 2294 my $parameterCheckString = ""; 2295 my $paramIndex = 0; 2296 my %replacements = (); 2297 2298 foreach my $parameter (@{$function->parameters}) { 2299 my $nativeType = GetNativeType($parameter->type, $parameter->extendedAttributes, "parameter"); 2300 2301 # Optional arguments without [Default=...] should generate an early call with fewer arguments. 2302 # Optional arguments with [Optional=...] should not generate the early call. 2303 # Optional Dictionary arguments always considered to have default of empty dictionary. 2304 if ($parameter->isOptional && !$parameter->extendedAttributes->{"Default"} && $nativeType ne "Dictionary" && !IsCallbackInterface($parameter->type)) { 2305 $parameterCheckString .= " if (args.Length() <= $paramIndex)"; 2306 my $functionCall = GenerateFunctionCallString($function, $paramIndex, " " x 2, $interface, $forMainWorldSuffix, %replacements); 2307 my $multiLine = ($functionCall =~ tr/\n//) > 1; 2308 $parameterCheckString .= $multiLine ? " {\n" : "\n"; 2309 $parameterCheckString .= $functionCall; 2310 $parameterCheckString .= $multiLine ? " }\n" : "\n"; 2311 } 2312 2313 my $parameterName = $parameter->name; 2314 AddToImplIncludes("bindings/v8/ExceptionState.h"); 2315 if (IsCallbackInterface($parameter->type)) { 2316 my $v8ClassName = "V8" . $parameter->type; 2317 AddToImplIncludes("$v8ClassName.h"); 2318 if ($parameter->isOptional) { 2319 $parameterCheckString .= " RefPtr<" . $parameter->type . "> $parameterName;\n"; 2320 $parameterCheckString .= " if (args.Length() > $paramIndex && !args[$paramIndex]->IsNull() && !args[$paramIndex]->IsUndefined()) {\n"; 2321 $parameterCheckString .= " if (!args[$paramIndex]->IsFunction()) {\n"; 2322 $parameterCheckString .= " throwTypeError(args.GetIsolate());\n"; 2323 $parameterCheckString .= " return;\n"; 2324 $parameterCheckString .= " }\n"; 2325 $parameterCheckString .= " $parameterName = ${v8ClassName}::create(args[$paramIndex], getScriptExecutionContext());\n"; 2326 $parameterCheckString .= " }\n"; 2327 } else { 2328 $parameterCheckString .= " if (args.Length() <= $paramIndex || "; 2329 if ($parameter->isNullable) { 2330 $parameterCheckString .= "!(args[$paramIndex]->IsFunction() || args[$paramIndex]->IsNull())"; 2331 } else { 2332 $parameterCheckString .= "!args[$paramIndex]->IsFunction()"; 2333 } 2334 $parameterCheckString .= ") {\n"; 2335 $parameterCheckString .= " throwTypeError(args.GetIsolate());\n"; 2336 $parameterCheckString .= " return;\n"; 2337 $parameterCheckString .= " }\n"; 2338 $parameterCheckString .= " RefPtr<" . $parameter->type . "> $parameterName = "; 2339 $parameterCheckString .= "args[$paramIndex]->IsNull() ? 0 : " if $parameter->isNullable; 2340 $parameterCheckString .= "${v8ClassName}::create(args[$paramIndex], getScriptExecutionContext());\n"; 2341 } 2342 } elsif ($parameter->extendedAttributes->{"Clamp"}) { 2343 my $nativeValue = "${parameterName}NativeValue"; 2344 my $paramType = $parameter->type; 2345 $parameterCheckString .= " $paramType $parameterName = 0;\n"; 2346 $parameterCheckString .= " V8TRYCATCH_VOID(double, $nativeValue, args[$paramIndex]->NumberValue());\n"; 2347 $parameterCheckString .= " if (!std::isnan($nativeValue))\n"; 2348 $parameterCheckString .= " $parameterName = clampTo<$paramType>($nativeValue);\n"; 2349 } elsif ($parameter->type eq "SerializedScriptValue") { 2350 AddToImplIncludes("bindings/v8/SerializedScriptValue.h"); 2351 $parameterCheckString .= " bool ${parameterName}DidThrow = false;\n"; 2352 $parameterCheckString .= " $nativeType $parameterName = SerializedScriptValue::create(args[$paramIndex], 0, 0, ${parameterName}DidThrow, args.GetIsolate());\n"; 2353 $parameterCheckString .= " if (${parameterName}DidThrow)\n"; 2354 $parameterCheckString .= " return;\n"; 2355 } elsif ($parameter->isVariadic) { 2356 my $nativeElementType = GetNativeType($parameter->type); 2357 if ($nativeElementType =~ />$/) { 2358 $nativeElementType .= " "; 2359 } 2360 2361 my $argType = $parameter->type; 2362 if (IsWrapperType($argType)) { 2363 $parameterCheckString .= " Vector<$nativeElementType> $parameterName;\n"; 2364 $parameterCheckString .= " for (int i = $paramIndex; i < args.Length(); ++i) {\n"; 2365 $parameterCheckString .= " if (!V8${argType}::HasInstance(args[i], args.GetIsolate(), worldType(args.GetIsolate()))) {\n"; 2366 $parameterCheckString .= " throwTypeError(args.GetIsolate());\n"; 2367 $parameterCheckString .= " return;\n"; 2368 $parameterCheckString .= " }\n"; 2369 $parameterCheckString .= " $parameterName.append(V8${argType}::toNative(v8::Handle<v8::Object>::Cast(args[i])));\n"; 2370 $parameterCheckString .= " }\n"; 2371 } else { 2372 $parameterCheckString .= " V8TRYCATCH_VOID(Vector<$nativeElementType>, $parameterName, toNativeArguments<$nativeElementType>(args, $paramIndex));\n"; 2373 } 2374 } elsif ($nativeType =~ /^V8StringResource/) { 2375 my $default = defined $parameter->extendedAttributes->{"Default"} ? $parameter->extendedAttributes->{"Default"} : ""; 2376 my $jsValue = $parameter->isOptional && $default eq "NullString" ? "argumentOrNull(args, $paramIndex)" : "args[$paramIndex]"; 2377 $parameterCheckString .= JSValueToNativeStatement($parameter->type, $parameter->extendedAttributes, $jsValue, $parameterName, " ", "args.GetIsolate()"); 2378 if (IsEnumType($parameter->type)) { 2379 my @enumValues = ValidEnumValues($parameter->type); 2380 my @validEqualities = (); 2381 foreach my $enumValue (@enumValues) { 2382 push(@validEqualities, "string == \"$enumValue\""); 2383 } 2384 my $enumValidationExpression = join(" || ", @validEqualities); 2385 $parameterCheckString .= " String string = $parameterName;\n"; 2386 $parameterCheckString .= " if (!($enumValidationExpression)) {\n"; 2387 $parameterCheckString .= " throwTypeError(args.GetIsolate());\n"; 2388 $parameterCheckString .= " return;\n"; 2389 $parameterCheckString .= " }\n"; 2390 } 2391 } else { 2392 # If the "StrictTypeChecking" extended attribute is present, and the argument's type is an 2393 # interface type, then if the incoming value does not implement that interface, a TypeError 2394 # is thrown rather than silently passing NULL to the C++ code. 2395 # Per the Web IDL and ECMAScript specifications, incoming values can always be converted 2396 # to both strings and numbers, so do not throw TypeError if the argument is of these 2397 # types. 2398 if ($function->extendedAttributes->{"StrictTypeChecking"}) { 2399 my $argValue = "args[$paramIndex]"; 2400 my $argType = $parameter->type; 2401 if (IsWrapperType($argType)) { 2402 $parameterCheckString .= " if (args.Length() > $paramIndex && !isUndefinedOrNull($argValue) && !V8${argType}::HasInstance($argValue, args.GetIsolate(), worldType(args.GetIsolate()))) {\n"; 2403 $parameterCheckString .= " throwTypeError(args.GetIsolate());\n"; 2404 $parameterCheckString .= " return;\n"; 2405 $parameterCheckString .= " }\n"; 2406 } 2407 } 2408 my $default = defined $parameter->extendedAttributes->{"Default"} ? $parameter->extendedAttributes->{"Default"} : ""; 2409 my $jsValue = $parameter->isOptional && $default eq "NullString" ? "argumentOrNull(args, $paramIndex)" : "args[$paramIndex]"; 2410 $parameterCheckString .= JSValueToNativeStatement($parameter->type, $parameter->extendedAttributes, $jsValue, $parameterName, " ", "args.GetIsolate()"); 2411 if ($nativeType eq 'Dictionary') { 2412 $parameterCheckString .= " if (!$parameterName.isUndefinedOrNull() && !$parameterName.isObject()) {\n"; 2413 $parameterCheckString .= " throwTypeError(\"Not an object.\", args.GetIsolate());\n"; 2414 $parameterCheckString .= " return;\n"; 2415 $parameterCheckString .= " }\n"; 2416 } 2417 } 2418 2419 if ($parameter->extendedAttributes->{"IsIndex"}) { 2420 AddToImplIncludes("core/dom/ExceptionCode.h"); 2421 $parameterCheckString .= " if (UNLIKELY($parameterName < 0)) {\n"; 2422 $parameterCheckString .= " setDOMException(IndexSizeError, args.GetIsolate());\n"; 2423 $parameterCheckString .= " return;\n"; 2424 $parameterCheckString .= " }\n"; 2425 } 2426 2427 $paramIndex++; 2428 } 2429 return ($parameterCheckString, $paramIndex, %replacements); 2430 } 2431 2432 sub GenerateOverloadedConstructorCallback 2433 { 2434 my $interface = shift; 2435 my $implClassName = GetImplName($interface); 2436 2437 my $code = ""; 2438 $code .= <<END; 2439 static void constructor(const v8::FunctionCallbackInfo<v8::Value>& args) 2440 { 2441 END 2442 my $leastNumMandatoryParams = 255; 2443 foreach my $constructor (@{$interface->constructors}) { 2444 my $name = "constructor" . $constructor->overloadedIndex; 2445 my ($numMandatoryParams, $parametersCheck) = GenerateFunctionParametersCheck($constructor); 2446 $leastNumMandatoryParams = $numMandatoryParams if ($numMandatoryParams < $leastNumMandatoryParams); 2447 $code .= " if ($parametersCheck) {\n"; 2448 $code .= " ${implClassName}V8Internal::${name}(args);\n"; 2449 $code .= " return;\n"; 2450 $code .= " }\n"; 2451 } 2452 if ($leastNumMandatoryParams >= 1) { 2453 $code .= " if (args.Length() < $leastNumMandatoryParams) {\n"; 2454 $code .= " throwNotEnoughArgumentsError(args.GetIsolate());\n"; 2455 $code .= " return;\n"; 2456 $code .= " }\n"; 2457 } 2458 $code .= <<END; 2459 throwTypeError(args.GetIsolate()); 2460 return; 2461 END 2462 $code .= "}\n\n"; 2463 $implementation{nameSpaceInternal}->add($code); 2464 } 2465 2466 sub GenerateSingleConstructorCallback 2467 { 2468 my $interface = shift; 2469 my $function = shift; 2470 2471 my $implClassName = GetImplName($interface); 2472 my $v8ClassName = GetV8ClassName($interface); 2473 my $overloadedIndexString = ""; 2474 if ($function->overloadedIndex > 0) { 2475 $overloadedIndexString .= $function->overloadedIndex; 2476 } 2477 2478 my $raisesExceptions = $function->extendedAttributes->{"RaisesException"}; 2479 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2480 $raisesExceptions = 1; 2481 } 2482 if (!$raisesExceptions) { 2483 foreach my $parameter (@{$function->parameters}) { 2484 if ($parameter->extendedAttributes->{"IsIndex"}) { 2485 $raisesExceptions = 1; 2486 } 2487 } 2488 } 2489 2490 my @beforeArgumentList; 2491 my @afterArgumentList; 2492 my $code = ""; 2493 $code .= <<END; 2494 static void constructor${overloadedIndexString}(const v8::FunctionCallbackInfo<v8::Value>& args) 2495 { 2496 END 2497 2498 if ($function->overloadedIndex == 0) { 2499 $code .= GenerateArgumentsCountCheck($function, $interface); 2500 } 2501 2502 if ($raisesExceptions) { 2503 AddToImplIncludes("bindings/v8/ExceptionState.h"); 2504 $code .= " ExceptionState es(args.GetIsolate());\n"; 2505 } 2506 2507 # FIXME: Currently [Constructor(...)] does not yet support optional arguments without [Default=...] 2508 my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $interface, ""); 2509 $code .= $parameterCheckString; 2510 2511 if ($interface->extendedAttributes->{"ConstructorCallWith"}) { 2512 if ($interface->extendedAttributes->{"ConstructorCallWith"} eq "ScriptExecutionContext") { 2513 push(@beforeArgumentList, "context"); 2514 $code .= "\n"; 2515 $code .= " ScriptExecutionContext* context = getScriptExecutionContext();"; 2516 } elsif ($interface->extendedAttributes->{"ConstructorCallWith"} eq "Document") { 2517 push(@beforeArgumentList, "document"); 2518 $code .= "\n"; 2519 $code .= " Document* document = toDocument(getScriptExecutionContext());"; 2520 } 2521 } 2522 2523 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2524 push(@afterArgumentList, "es"); 2525 } 2526 2527 my @argumentList; 2528 my $index = 0; 2529 foreach my $parameter (@{$function->parameters}) { 2530 last if $index eq $paramIndex; 2531 if ($replacements{$parameter->name}) { 2532 push(@argumentList, $replacements{$parameter->name}); 2533 } else { 2534 push(@argumentList, $parameter->name); 2535 } 2536 $index++; 2537 } 2538 2539 my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList); 2540 $code .= "\n"; 2541 $code .= " RefPtr<${implClassName}> impl = ${implClassName}::create(${argumentString});\n"; 2542 $code .= " v8::Handle<v8::Object> wrapper = args.Holder();\n"; 2543 2544 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2545 $code .= " if (es.throwIfNeeded())\n"; 2546 $code .= " return;\n"; 2547 } 2548 2549 $code .= <<END; 2550 2551 V8DOMWrapper::associateObjectWithWrapper<${v8ClassName}>(impl.release(), &${v8ClassName}::info, wrapper, args.GetIsolate(), WrapperConfiguration::Dependent); 2552 args.GetReturnValue().Set(wrapper); 2553 } 2554 2555 END 2556 $implementation{nameSpaceInternal}->add($code); 2557 } 2558 2559 # The Web IDL specification states that Interface objects for interfaces MUST have a property named 2560 # "length" that returns the length of the shortest argument list of the entries in the effective 2561 # overload set for constructors. In other words, use the lowest number of mandatory arguments among 2562 # all constructors. 2563 sub GetInterfaceLength 2564 { 2565 my $interface = shift; 2566 2567 my $leastConstructorLength = 0; 2568 if (IsConstructorTemplate($interface, "Event") || IsConstructorTemplate($interface, "TypedArray")) { 2569 $leastConstructorLength = 1; 2570 } elsif ($interface->extendedAttributes->{"Constructor"} || $interface->extendedAttributes->{"CustomConstructor"}) { 2571 my @constructors = @{$interface->constructors}; 2572 my @customConstructors = @{$interface->customConstructors}; 2573 $leastConstructorLength = 255; 2574 foreach my $constructor (@constructors, @customConstructors) { 2575 my $constructorLength = GetFunctionLength($constructor); 2576 $leastConstructorLength = $constructorLength if ($constructorLength < $leastConstructorLength); 2577 } 2578 } 2579 2580 return $leastConstructorLength; 2581 } 2582 2583 sub GenerateConstructorCallback 2584 { 2585 my $interface = shift; 2586 2587 my $implClassName = GetImplName($interface); 2588 my $v8ClassName = GetV8ClassName($interface); 2589 my $code = ""; 2590 $code .= "void ${v8ClassName}::constructorCallback(const v8::FunctionCallbackInfo<v8::Value>& args)\n"; 2591 $code .= "{\n"; 2592 $code .= " TRACE_EVENT_SCOPED_SAMPLING_STATE(\"Blink\", \"DOMConstructor\");\n"; 2593 $code .= GenerateFeatureObservation($interface->extendedAttributes->{"MeasureAs"}); 2594 $code .= GenerateDeprecationNotification($interface->extendedAttributes->{"DeprecateAs"}); 2595 $code .= GenerateConstructorHeader(); 2596 if (HasCustomConstructor($interface)) { 2597 $code .= " ${v8ClassName}::constructorCustom(args);\n"; 2598 } else { 2599 $code .= " ${implClassName}V8Internal::constructor(args);\n"; 2600 } 2601 $code .= "}\n\n"; 2602 $implementation{nameSpaceWebCore}->add($code); 2603 } 2604 2605 sub GenerateConstructor 2606 { 2607 my $interface = shift; 2608 2609 if (@{$interface->constructors} == 1) { 2610 GenerateSingleConstructorCallback($interface, @{$interface->constructors}[0]); 2611 } else { 2612 foreach my $constructor (@{$interface->constructors}) { 2613 GenerateSingleConstructorCallback($interface, $constructor); 2614 } 2615 GenerateOverloadedConstructorCallback($interface); 2616 } 2617 } 2618 2619 sub GenerateEventConstructor 2620 { 2621 my $interface = shift; 2622 my $implClassName = GetImplName($interface); 2623 my $v8ClassName = GetV8ClassName($interface); 2624 2625 my @anyAttributeNames; 2626 my @serializableAnyAttributeNames; 2627 foreach my $attribute (@{$interface->attributes}) { 2628 if ($attribute->type eq "any") { 2629 push(@anyAttributeNames, $attribute->name); 2630 if (!$attribute->extendedAttributes->{"Unserializable"}) { 2631 push(@serializableAnyAttributeNames, $attribute->name); 2632 } 2633 } 2634 } 2635 2636 AddToImplIncludes("bindings/v8/Dictionary.h"); 2637 $implementation{nameSpaceInternal}->add(<<END); 2638 static void constructor(const v8::FunctionCallbackInfo<v8::Value>& args) 2639 { 2640 if (args.Length() < 1) { 2641 throwNotEnoughArgumentsError(args.GetIsolate()); 2642 return; 2643 } 2644 2645 V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID(V8StringResource<>, type, args[0]); 2646 END 2647 2648 foreach my $attrName (@anyAttributeNames) { 2649 $implementation{nameSpaceInternal}->add(" v8::Local<v8::Value> ${attrName};\n"); 2650 } 2651 2652 $implementation{nameSpaceInternal}->add(<<END); 2653 ${implClassName}Init eventInit; 2654 if (args.Length() >= 2) { 2655 V8TRYCATCH_VOID(Dictionary, options, Dictionary(args[1], args.GetIsolate())); 2656 if (!fill${implClassName}Init(eventInit, options)) 2657 return; 2658 END 2659 2660 # Store 'any'-typed properties on the wrapper to avoid leaking them between isolated worlds. 2661 foreach my $attrName (@anyAttributeNames) { 2662 $implementation{nameSpaceInternal}->add(<<END); 2663 options.get("${attrName}", ${attrName}); 2664 if (!${attrName}.IsEmpty()) 2665 args.Holder()->SetHiddenValue(V8HiddenPropertyName::${attrName}(), ${attrName}); 2666 END 2667 } 2668 2669 $implementation{nameSpaceInternal}->add(<<END); 2670 } 2671 2672 RefPtr<${implClassName}> event = ${implClassName}::create(type, eventInit); 2673 END 2674 2675 if (@serializableAnyAttributeNames) { 2676 # If we're in an isolated world, create a SerializedScriptValue and store it in the event for 2677 # later cloning if the property is accessed from another world. 2678 # The main world case is handled lazily (in Custom code). 2679 $implementation{nameSpaceInternal}->add(" if (isolatedWorldForIsolate(args.GetIsolate())) {\n"); 2680 foreach my $attrName (@serializableAnyAttributeNames) { 2681 my $setter = "setSerialized" . FirstLetterToUpperCase($attrName); 2682 $implementation{nameSpaceInternal}->add(<<END); 2683 if (!${attrName}.IsEmpty()) 2684 event->${setter}(SerializedScriptValue::createAndSwallowExceptions(${attrName}, args.GetIsolate())); 2685 END 2686 } 2687 $implementation{nameSpaceInternal}->add(" }\n\n"); 2688 } 2689 2690 $implementation{nameSpaceInternal}->add(<<END); 2691 v8::Handle<v8::Object> wrapper = args.Holder(); 2692 V8DOMWrapper::associateObjectWithWrapper<${v8ClassName}>(event.release(), &${v8ClassName}::info, wrapper, args.GetIsolate(), WrapperConfiguration::Dependent); 2693 v8SetReturnValue(args, wrapper); 2694 } 2695 END 2696 2697 my $code = ""; 2698 $code .= <<END; 2699 bool fill${implClassName}Init(${implClassName}Init& eventInit, const Dictionary& options) 2700 { 2701 END 2702 2703 if ($interface->parent) { 2704 my $interfaceBase = $interface->parent; 2705 $code .= <<END; 2706 if (!fill${interfaceBase}Init(eventInit, options)) 2707 return false; 2708 2709 END 2710 } 2711 2712 foreach my $attribute (@{$interface->attributes}) { 2713 if ($attribute->extendedAttributes->{"InitializedByEventConstructor"}) { 2714 if ($attribute->type ne "any") { 2715 my $attributeName = $attribute->name; 2716 my $attributeImplName = GetImplName($attribute); 2717 my $deprecation = $attribute->extendedAttributes->{"DeprecateAs"}; 2718 my $dictionaryGetter = "options.get(\"$attributeName\", eventInit.$attributeImplName)"; 2719 if ($attribute->extendedAttributes->{"DeprecateAs"}) { 2720 $code .= " if ($dictionaryGetter)\n"; 2721 $code .= " " . GenerateDeprecationNotification($attribute->extendedAttributes->{"DeprecateAs"}); 2722 } else { 2723 $code .= " $dictionaryGetter;\n"; 2724 } 2725 } 2726 } 2727 } 2728 2729 $code .= <<END; 2730 return true; 2731 } 2732 2733 END 2734 $implementation{nameSpaceWebCore}->add($code); 2735 } 2736 2737 sub GenerateNamedConstructor 2738 { 2739 my $function = shift; 2740 my $interface = shift; 2741 2742 my $implClassName = GetImplName($interface); 2743 my $v8ClassName = GetV8ClassName($interface); 2744 my $raisesExceptions = $function->extendedAttributes->{"RaisesException"}; 2745 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2746 $raisesExceptions = 1; 2747 } 2748 if (!$raisesExceptions) { 2749 foreach my $parameter (@{$function->parameters}) { 2750 if ($parameter->extendedAttributes->{"IsIndex"}) { 2751 $raisesExceptions = 1; 2752 } 2753 } 2754 } 2755 2756 my $maybeObserveFeature = GenerateFeatureObservation($function->extendedAttributes->{"MeasureAs"}); 2757 my $maybeDeprecateFeature = GenerateDeprecationNotification($function->extendedAttributes->{"DeprecateAs"}); 2758 2759 my @beforeArgumentList; 2760 my @afterArgumentList; 2761 2762 my $toActiveDOMObject = "0"; 2763 if (InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 2764 $toActiveDOMObject = "${v8ClassName}::toActiveDOMObject"; 2765 } 2766 2767 my $toEventTarget = "0"; 2768 if (InheritsInterface($interface, "EventTarget")) { 2769 $toEventTarget = "${v8ClassName}::toEventTarget"; 2770 } 2771 2772 AddToImplIncludes("core/page/Frame.h"); 2773 $implementation{nameSpaceWebCore}->add(<<END); 2774 WrapperTypeInfo ${v8ClassName}Constructor::info = { ${v8ClassName}Constructor::GetTemplate, ${v8ClassName}::derefObject, $toActiveDOMObject, $toEventTarget, 0, ${v8ClassName}::installPerContextPrototypeProperties, 0, WrapperTypeObjectPrototype }; 2775 2776 END 2777 2778 my $code = ""; 2779 $code .= <<END; 2780 static void ${v8ClassName}ConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& args) 2781 { 2782 END 2783 $code .= $maybeObserveFeature if $maybeObserveFeature; 2784 $code .= $maybeDeprecateFeature if $maybeDeprecateFeature; 2785 $code .= GenerateConstructorHeader(); 2786 AddToImplIncludes("V8Document.h"); 2787 $code .= <<END; 2788 Document* document = currentDocument(); 2789 2790 // Make sure the document is added to the DOM Node map. Otherwise, the ${implClassName} instance 2791 // may end up being the only node in the map and get garbage-collected prematurely. 2792 toV8(document, args.Holder(), args.GetIsolate()); 2793 2794 END 2795 2796 $code .= GenerateArgumentsCountCheck($function, $interface); 2797 2798 if ($raisesExceptions) { 2799 AddToImplIncludes("bindings/v8/ExceptionState.h"); 2800 $code .= " ExceptionState es(args.GetIsolate());\n"; 2801 } 2802 2803 my ($parameterCheckString, $paramIndex, %replacements) = GenerateParametersCheck($function, $interface); 2804 $code .= $parameterCheckString; 2805 2806 push(@beforeArgumentList, "document"); 2807 2808 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2809 push(@afterArgumentList, "es"); 2810 } 2811 2812 my @argumentList; 2813 my $index = 0; 2814 foreach my $parameter (@{$function->parameters}) { 2815 last if $index eq $paramIndex; 2816 if ($replacements{$parameter->name}) { 2817 push(@argumentList, $replacements{$parameter->name}); 2818 } else { 2819 push(@argumentList, $parameter->name); 2820 } 2821 $index++; 2822 } 2823 2824 my $argumentString = join(", ", @beforeArgumentList, @argumentList, @afterArgumentList); 2825 $code .= "\n"; 2826 $code .= " RefPtr<${implClassName}> impl = ${implClassName}::createForJSConstructor(${argumentString});\n"; 2827 $code .= " v8::Handle<v8::Object> wrapper = args.Holder();\n"; 2828 2829 if ($interface->extendedAttributes->{"ConstructorRaisesException"}) { 2830 $code .= " if (es.throwIfNeeded())\n"; 2831 $code .= " return;\n"; 2832 } 2833 2834 $code .= <<END; 2835 2836 V8DOMWrapper::associateObjectWithWrapper<${v8ClassName}>(impl.release(), &${v8ClassName}Constructor::info, wrapper, args.GetIsolate(), WrapperConfiguration::Dependent); 2837 args.GetReturnValue().Set(wrapper); 2838 } 2839 2840 END 2841 $implementation{nameSpaceWebCore}->add($code); 2842 2843 $code = <<END; 2844 v8::Handle<v8::FunctionTemplate> ${v8ClassName}Constructor::GetTemplate(v8::Isolate* isolate, WrapperWorldType currentWorldType) 2845 { 2846 // This is only for getting a unique pointer which we can pass to privateTemplate. 2847 static const char* privateTemplateUniqueKey = "${v8ClassName}Constructor::GetTemplatePrivateTemplate"; 2848 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 2849 v8::Handle<v8::FunctionTemplate> result = data->privateTemplateIfExists(currentWorldType, &privateTemplateUniqueKey); 2850 if (!result.IsEmpty()) 2851 return result; 2852 2853 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink\", \"BuildDOMTemplate"); 2854 v8::HandleScope scope(isolate); 2855 result = v8::FunctionTemplate::New(${v8ClassName}ConstructorCallback); 2856 2857 v8::Local<v8::ObjectTemplate> instance = result->InstanceTemplate(); 2858 instance->SetInternalFieldCount(${v8ClassName}::internalFieldCount); 2859 result->SetClassName(v8::String::NewSymbol("${implClassName}")); 2860 result->Inherit(${v8ClassName}::GetTemplate(isolate, currentWorldType)); 2861 data->setPrivateTemplate(currentWorldType, &privateTemplateUniqueKey, result); 2862 2863 return scope.Close(result); 2864 } 2865 2866 END 2867 $implementation{nameSpaceWebCore}->add($code); 2868 } 2869 2870 sub GenerateConstructorHeader 2871 { 2872 AddToImplIncludes("bindings/v8/V8ObjectConstructor.h"); 2873 my $content = <<END; 2874 if (!args.IsConstructCall()) { 2875 throwTypeError("DOM object constructor cannot be called as a function.", args.GetIsolate()); 2876 return; 2877 } 2878 2879 if (ConstructorMode::current() == ConstructorMode::WrapExistingObject) { 2880 args.GetReturnValue().Set(args.Holder()); 2881 return; 2882 } 2883 2884 END 2885 return $content; 2886 } 2887 2888 sub GenerateBatchedAttributeData 2889 { 2890 my $interface = shift; 2891 my $attributes = shift; 2892 my $code = ""; 2893 2894 foreach my $attribute (@$attributes) { 2895 my $conditionalString = GenerateConditionalString($attribute); 2896 my $subCode = ""; 2897 $subCode .= "#if ${conditionalString}\n" if $conditionalString; 2898 $subCode .= GenerateSingleBatchedAttribute($interface, $attribute, ",", ""); 2899 $subCode .= "#endif // ${conditionalString}\n" if $conditionalString; 2900 $code .= $subCode; 2901 } 2902 return $code; 2903 } 2904 2905 sub GenerateSingleBatchedAttribute 2906 { 2907 my $interface = shift; 2908 my $attribute = shift; 2909 my $delimiter = shift; 2910 my $indent = shift; 2911 my $code = ""; 2912 my $attrName = $attribute->name; 2913 my $attrExt = $attribute->extendedAttributes; 2914 my $implClassName = GetImplName($interface); 2915 2916 my $accessControl = "v8::DEFAULT"; 2917 if ($attrExt->{"DoNotCheckSecurityOnGetter"}) { 2918 $accessControl = "v8::ALL_CAN_READ"; 2919 } elsif ($attrExt->{"DoNotCheckSecurityOnSetter"}) { 2920 $accessControl = "v8::ALL_CAN_WRITE"; 2921 } elsif ($attrExt->{"DoNotCheckSecurity"}) { 2922 $accessControl = "v8::ALL_CAN_READ"; 2923 if (!IsReadonly($attribute)) { 2924 $accessControl .= " | v8::ALL_CAN_WRITE"; 2925 } 2926 } 2927 if ($attrExt->{"Unforgeable"}) { 2928 $accessControl .= " | v8::PROHIBITS_OVERWRITING"; 2929 } 2930 $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")"; 2931 2932 my $customAccessor = HasCustomGetter($attrExt) || HasCustomSetter($attrExt) || ""; 2933 if ($customAccessor eq "VALUE_IS_MISSING") { 2934 # use the naming convension, interface + (capitalize) attr name 2935 $customAccessor = $implClassName . "::" . $attrName; 2936 } 2937 2938 my $getter; 2939 my $setter; 2940 my $getterForMainWorld; 2941 my $setterForMainWorld; 2942 my $propAttr = "v8::None"; 2943 2944 my $isConstructor = ($attribute->type =~ /Constructor$/); 2945 2946 # Check attributes. 2947 # As per Web IDL specification, constructor properties on the ECMAScript global object should be 2948 # configurable and should not be enumerable. 2949 if ($attrExt->{"NotEnumerable"} || $isConstructor) { 2950 $propAttr .= " | v8::DontEnum"; 2951 } 2952 if ($attrExt->{"Unforgeable"} && !$isConstructor) { 2953 $propAttr .= " | v8::DontDelete"; 2954 } 2955 2956 my $on_proto = "0 /* on instance */"; 2957 my $data = "0 /* no data */"; 2958 2959 # Constructor 2960 if ($isConstructor) { 2961 my $constructorType = $attribute->type; 2962 $constructorType =~ s/Constructor$//; 2963 # $constructorType ~= /Constructor$/ indicates that it is NamedConstructor. 2964 # We do not generate the header file for NamedConstructor of class XXXX, 2965 # since we generate the NamedConstructor declaration into the header file of class XXXX. 2966 if ($constructorType !~ /Constructor$/ || $attribute->extendedAttributes->{"CustomConstructor"}) { 2967 AddToImplIncludes("V8${constructorType}.h"); 2968 } 2969 $data = "&V8${constructorType}::info"; 2970 $getter = "${implClassName}V8Internal::${implClassName}ConstructorGetter"; 2971 $setter = "${implClassName}V8Internal::${implClassName}ReplaceableAttrSetterCallback"; 2972 $getterForMainWorld = "0"; 2973 $setterForMainWorld = "0"; 2974 } else { 2975 # Default Getter and Setter 2976 $getter = "${implClassName}V8Internal::${attrName}AttrGetterCallback"; 2977 $setter = "${implClassName}V8Internal::${attrName}AttrSetterCallback"; 2978 $getterForMainWorld = "${getter}ForMainWorld"; 2979 $setterForMainWorld = "${setter}ForMainWorld"; 2980 2981 if (!HasCustomSetter($attrExt) && $attrExt->{"Replaceable"}) { 2982 $setter = "${implClassName}V8Internal::${implClassName}ReplaceableAttrSetterCallback"; 2983 $setterForMainWorld = "0"; 2984 } 2985 } 2986 2987 # Read only attributes 2988 if (IsReadonly($attribute)) { 2989 $setter = "0"; 2990 $setterForMainWorld = "0"; 2991 } 2992 2993 # An accessor can be installed on the proto 2994 if ($attrExt->{"OnProto"}) { 2995 $on_proto = "1 /* on proto */"; 2996 } 2997 2998 if (!$attrExt->{"PerWorldBindings"}) { 2999 $getterForMainWorld = "0"; 3000 $setterForMainWorld = "0"; 3001 } 3002 3003 my $commentInfo = "Attribute '$attrName'"; 3004 3005 $code .= $indent . " \/\/ $commentInfo\n"; 3006 $code .= $indent . " {\"$attrName\", $getter, $setter, $getterForMainWorld, $setterForMainWorld, $data, $accessControl, static_cast<v8::PropertyAttribute>($propAttr), $on_proto}" . $delimiter . "\n"; 3007 return $code; 3008 } 3009 3010 sub IsStandardFunction 3011 { 3012 my $interface = shift; 3013 my $function = shift; 3014 3015 my $interfaceName = $interface->name; 3016 my $attrExt = $function->extendedAttributes; 3017 return 0 if $attrExt->{"Unforgeable"}; 3018 return 0 if $function->isStatic; 3019 return 0 if $attrExt->{"EnabledAtRuntime"}; 3020 return 0 if $attrExt->{"EnabledPerContext"}; 3021 return 0 if RequiresCustomSignature($function); 3022 return 0 if $attrExt->{"DoNotCheckSignature"}; 3023 return 0 if ($attrExt->{"DoNotCheckSecurity"} && ($interface->extendedAttributes->{"CheckSecurity"} || $interfaceName eq "Window")); 3024 return 0 if $attrExt->{"NotEnumerable"}; 3025 return 0 if $attrExt->{"ReadOnly"}; 3026 return 1; 3027 } 3028 3029 sub GenerateNonStandardFunction 3030 { 3031 my $interface = shift; 3032 my $function = shift; 3033 my $code = ""; 3034 3035 my $implClassName = GetImplName($interface); 3036 my $attrExt = $function->extendedAttributes; 3037 my $name = $function->name; 3038 3039 my $property_attributes = "v8::DontDelete"; 3040 if ($attrExt->{"NotEnumerable"}) { 3041 $property_attributes .= " | v8::DontEnum"; 3042 } 3043 if ($attrExt->{"ReadOnly"}) { 3044 $property_attributes .= " | v8::ReadOnly"; 3045 } 3046 3047 my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; 3048 3049 my $template = "proto"; 3050 if ($attrExt->{"Unforgeable"}) { 3051 $template = "instance"; 3052 } 3053 if ($function->isStatic) { 3054 $template = "desc"; 3055 } 3056 3057 my $conditional = ""; 3058 if ($attrExt->{"EnabledAtRuntime"}) { 3059 # Only call Set()/SetAccessor() if this method should be enabled 3060 my $enable_function = GetRuntimeEnableFunctionName($function); 3061 $conditional = "if (${enable_function}())\n "; 3062 } 3063 if ($attrExt->{"EnabledPerContext"}) { 3064 # Only call Set()/SetAccessor() if this method should be enabled 3065 my $enable_function = GetContextEnableFunction($function); 3066 $conditional = "if (${enable_function}(impl->document()))\n "; 3067 } 3068 3069 if ($interface->extendedAttributes->{"CheckSecurity"} && $attrExt->{"DoNotCheckSecurity"}) { 3070 my $setter = $attrExt->{"ReadOnly"} ? "0" : "${implClassName}V8Internal::${implClassName}DomainSafeFunctionSetter"; 3071 # Functions that are marked DoNotCheckSecurity are always readable but if they are changed 3072 # and then accessed on a different domain we do not return the underlying value but instead 3073 # return a new copy of the original function. This is achieved by storing the changed value 3074 # as hidden property. 3075 $code .= <<END; 3076 3077 // $commentInfo 3078 ${conditional}$template->SetAccessor(v8::String::NewSymbol("$name"), ${implClassName}V8Internal::${name}AttrGetterCallback, ${setter}, v8Undefined(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>($property_attributes)); 3079 END 3080 return $code; 3081 } 3082 3083 my $signature = "defaultSignature"; 3084 if ($attrExt->{"DoNotCheckSignature"} || $function->isStatic) { 3085 $signature = "v8::Local<v8::Signature>()"; 3086 } 3087 3088 my $conditionalString = GenerateConditionalString($function); 3089 $code .= "#if ${conditionalString}\n" if $conditionalString; 3090 if (RequiresCustomSignature($function)) { 3091 $signature = "${name}Signature"; 3092 $code .= "\n // Custom Signature '$name'\n" . CreateCustomSignature($function); 3093 } 3094 3095 if ($property_attributes eq "v8::DontDelete") { 3096 $property_attributes = ""; 3097 } else { 3098 $property_attributes = ", static_cast<v8::PropertyAttribute>($property_attributes)"; 3099 } 3100 3101 if ($template eq "proto" && $conditional eq "" && $signature eq "defaultSignature" && $property_attributes eq "") { 3102 die "This shouldn't happen: Class '$implClassName' $commentInfo\n"; 3103 } 3104 3105 my $functionLength = GetFunctionLength($function); 3106 3107 if ($function->extendedAttributes->{"PerWorldBindings"}) { 3108 $code .= " if (currentWorldType == MainWorld) {\n"; 3109 $code .= " ${conditional}$template->Set(v8::String::NewSymbol(\"$name\"), v8::FunctionTemplate::New(${implClassName}V8Internal::${name}MethodCallbackForMainWorld, v8Undefined(), ${signature}, $functionLength)$property_attributes);\n"; 3110 $code .= " } else {\n"; 3111 $code .= " ${conditional}$template->Set(v8::String::NewSymbol(\"$name\"), v8::FunctionTemplate::New(${implClassName}V8Internal::${name}MethodCallback, v8Undefined(), ${signature}, $functionLength)$property_attributes);\n"; 3112 $code .= " }\n"; 3113 } else { 3114 $code .= " ${conditional}$template->Set(v8::String::NewSymbol(\"$name\"), v8::FunctionTemplate::New(${implClassName}V8Internal::${name}MethodCallback, v8Undefined(), ${signature}, $functionLength)$property_attributes);\n"; 3115 } 3116 $code .= "#endif // ${conditionalString}\n" if $conditionalString; 3117 return $code; 3118 } 3119 3120 sub GenerateIsNullExpression 3121 { 3122 my $type = shift; 3123 my $variableName = shift; 3124 if (IsUnionType($type)) { 3125 my $types = $type->unionMemberTypes; 3126 my @expression = (); 3127 for my $i (0 .. scalar(@$types)-1) { 3128 my $unionMemberType = $types->[$i]; 3129 my $unionMemberVariable = $variableName . $i; 3130 my $isNull = GenerateIsNullExpression($unionMemberType, $unionMemberVariable); 3131 push @expression, $isNull; 3132 } 3133 return join " && ", @expression; 3134 } 3135 if (IsRefPtrType($type)) { 3136 return "!${variableName}"; 3137 } elsif ($type eq "DOMString") { 3138 return "${variableName}.isNull()"; 3139 } else { 3140 return ""; 3141 } 3142 } 3143 3144 sub GenerateIfElseStatement 3145 { 3146 my $type = shift; 3147 my $outputVariableName = shift; 3148 my $conditions = shift; 3149 my $statements = shift; 3150 3151 my $code = ""; 3152 if (@$conditions == 1) { 3153 $code .= " ${type} ${outputVariableName} = " . $statements->[0] . "\n"; 3154 } else { 3155 $code .= " ${type} ${outputVariableName};\n"; 3156 for my $i (0 .. @$conditions - 1) { 3157 my $token = "else if"; 3158 $token = "if" if $i == 0; 3159 $token = "else" if $i == @$conditions - 1; 3160 $code .= " ${token}"; 3161 $code .= " (" . $conditions->[$i] . ")" if $conditions->[$i]; 3162 $code .= "\n"; 3163 $code .= " ${outputVariableName} = " . $statements->[$i] . "\n"; 3164 } 3165 } 3166 return $code; 3167 } 3168 3169 sub GenerateImplementationIndexedPropertyAccessors 3170 { 3171 my $interface = shift; 3172 my $interfaceName = $interface->name; 3173 my $implClassName = GetImplName($interface); 3174 my $v8ClassName = GetV8ClassName($interface); 3175 3176 my $indexedGetterFunction = GetIndexedGetterFunction($interface); 3177 if ($indexedGetterFunction) { 3178 my $hasCustomIndexedGetter = $indexedGetterFunction->extendedAttributes->{"Custom"}; 3179 if (!$hasCustomIndexedGetter) { 3180 GenerateImplementationIndexedPropertyGetter($interface, $indexedGetterFunction); 3181 } 3182 GenerateImplementationIndexedPropertyGetterCallback($interface, $hasCustomIndexedGetter); 3183 } 3184 3185 my $indexedSetterFunction = GetIndexedSetterFunction($interface); 3186 if ($indexedSetterFunction) { 3187 my $hasCustomIndexedSetter = $indexedSetterFunction->extendedAttributes->{"Custom"}; 3188 if (!$hasCustomIndexedSetter) { 3189 GenerateImplementationIndexedPropertySetter($interface, $indexedSetterFunction); 3190 } 3191 GenerateImplementationIndexedPropertySetterCallback($interface, $hasCustomIndexedSetter); 3192 } 3193 3194 my $indexedDeleterFunction = GetIndexedDeleterFunction($interface); 3195 if ($indexedDeleterFunction) { 3196 my $hasCustomIndexedDeleter = $indexedDeleterFunction->extendedAttributes->{"Custom"}; 3197 if (!$hasCustomIndexedDeleter) { 3198 GenerateImplementationIndexedPropertyDeleter($interface, $indexedDeleterFunction); 3199 } 3200 GenerateImplementationIndexedPropertyDeleterCallback($interface, $hasCustomIndexedDeleter); 3201 } 3202 3203 my $indexedEnumeratorFunction = $indexedGetterFunction; 3204 $indexedEnumeratorFunction = 0 if $indexedGetterFunction && $indexedGetterFunction->extendedAttributes->{"NotEnumerable"}; 3205 3206 my $indexedQueryFunction = 0; 3207 # If there is an enumerator, there MUST be a query method to properly communicate property attributes. 3208 my $hasQuery = $indexedQueryFunction || $indexedEnumeratorFunction; 3209 3210 my $setOn = "Instance"; 3211 3212 # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on Window 3213 # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to 3214 # get implementation straight out of the Window prototype regardless of what prototype is actually set 3215 # on the object. 3216 if ($interfaceName eq "Window") { 3217 $setOn = "Prototype"; 3218 } 3219 3220 my $code = ""; 3221 if ($indexedGetterFunction || $indexedSetterFunction || $indexedDeleterFunction || $indexedEnumeratorFunction || $hasQuery) { 3222 $code .= " desc->${setOn}Template()->SetIndexedPropertyHandler(${implClassName}V8Internal::indexedPropertyGetterCallback"; 3223 $code .= $indexedSetterFunction ? ", ${implClassName}V8Internal::indexedPropertySetterCallback" : ", 0"; 3224 $code .= ", 0"; # IndexedPropertyQuery -- not being used at the moment. 3225 $code .= $indexedDeleterFunction ? ", ${implClassName}V8Internal::indexedPropertyDeleterCallback" : ", 0"; 3226 $code .= $indexedEnumeratorFunction ? ", indexedPropertyEnumerator<${implClassName}>" : ", 0"; 3227 $code .= ");\n"; 3228 } 3229 3230 return $code; 3231 } 3232 3233 sub GenerateImplementationIndexedPropertyGetter 3234 { 3235 my $interface = shift; 3236 my $indexedGetterFunction = shift; 3237 my $implClassName = GetImplName($interface); 3238 my $v8ClassName = GetV8ClassName($interface); 3239 my $methodName = GetImplName($indexedGetterFunction); 3240 3241 my $returnType = $indexedGetterFunction->type; 3242 my $nativeType = GetNativeType($returnType); 3243 my $nativeValue = "element"; 3244 $nativeValue .= ".release()" if (IsRefPtrType($returnType)); 3245 my $isNull = GenerateIsNullExpression($returnType, "element"); 3246 my $returnJSValueCode = NativeToJSValue($indexedGetterFunction->type, $indexedGetterFunction->extendedAttributes, $nativeValue, " ", "", "info.Holder()", "info.GetIsolate()", "info", "collection", "", "return"); 3247 my $raisesExceptions = $indexedGetterFunction->extendedAttributes->{"RaisesException"}; 3248 my $methodCallCode = GenerateMethodCall($returnType, "element", "collection->${methodName}", "index", $raisesExceptions); 3249 my $getterCode = "static void indexedPropertyGetter(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3250 $getterCode .= "{\n"; 3251 $getterCode .= " ASSERT(V8DOMWrapper::maybeDOMWrapper(info.Holder()));\n"; 3252 $getterCode .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3253 if ($raisesExceptions) { 3254 $getterCode .= " ExceptionState es(info.GetIsolate());\n"; 3255 } 3256 $getterCode .= $methodCallCode . "\n"; 3257 if ($raisesExceptions) { 3258 $getterCode .= " if (es.throwIfNeeded())\n"; 3259 $getterCode .= " return;\n"; 3260 } 3261 if (IsUnionType($returnType)) { 3262 $getterCode .= "${returnJSValueCode}\n"; 3263 $getterCode .= " return;\n"; 3264 } else { 3265 $getterCode .= " if (${isNull})\n"; 3266 $getterCode .= " return;\n"; 3267 $getterCode .= $returnJSValueCode . "\n"; 3268 } 3269 $getterCode .= "}\n\n"; 3270 $implementation{nameSpaceInternal}->add($getterCode); 3271 } 3272 3273 sub GenerateImplementationIndexedPropertyGetterCallback 3274 { 3275 my $interface = shift; 3276 my $hasCustom = shift; 3277 my $implClassName = GetImplName($interface); 3278 my $v8ClassName = GetV8ClassName($interface); 3279 3280 my $code = "static void indexedPropertyGetterCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3281 $code .= "{\n"; 3282 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMIndexedProperty\");\n"; 3283 if ($hasCustom) { 3284 $code .= " ${v8ClassName}::indexedPropertyGetterCustom(index, info);\n"; 3285 } else { 3286 $code .= " ${implClassName}V8Internal::indexedPropertyGetter(index, info);\n"; 3287 } 3288 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3289 $code .= "}\n\n"; 3290 $implementation{nameSpaceInternal}->add($code); 3291 } 3292 3293 sub GenerateImplementationIndexedPropertySetterCallback 3294 { 3295 my $interface = shift; 3296 my $hasCustom = shift; 3297 my $implClassName = GetImplName($interface); 3298 my $v8ClassName = GetV8ClassName($interface); 3299 3300 my $code = "static void indexedPropertySetterCallback(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3301 $code .= "{\n"; 3302 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMIndexedProperty\");\n"; 3303 if ($hasCustom) { 3304 $code .= " ${v8ClassName}::indexedPropertySetterCustom(index, value, info);\n"; 3305 } else { 3306 $code .= " ${implClassName}V8Internal::indexedPropertySetter(index, value, info);\n"; 3307 } 3308 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3309 $code .= "}\n\n"; 3310 $implementation{nameSpaceInternal}->add($code); 3311 } 3312 3313 sub GenerateImplementationIndexedPropertyDeleterCallback 3314 { 3315 my $interface = shift; 3316 my $hasCustom = shift; 3317 my $implClassName = GetImplName($interface); 3318 my $v8ClassName = GetV8ClassName($interface); 3319 3320 my $code = "static void indexedPropertyDeleterCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean>& info)\n"; 3321 $code .= "{\n"; 3322 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMIndexedProperty\");\n"; 3323 if ($hasCustom) { 3324 $code .= " ${v8ClassName}::indexedPropertyDeleterCustom(index, info);\n"; 3325 } else { 3326 $code .= " ${implClassName}V8Internal::indexedPropertyDeleter(index, info);\n"; 3327 } 3328 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3329 $code .= "}\n\n"; 3330 $implementation{nameSpaceInternal}->add($code); 3331 } 3332 3333 sub GenerateImplementationIndexedPropertySetter 3334 { 3335 my $interface = shift; 3336 my $indexedSetterFunction = shift; 3337 my $implClassName = GetImplName($interface); 3338 my $v8ClassName = GetV8ClassName($interface); 3339 my $methodName = GetImplName($indexedSetterFunction); 3340 3341 my $type = $indexedSetterFunction->parameters->[1]->type; 3342 my $raisesExceptions = $indexedSetterFunction->extendedAttributes->{"RaisesException"}; 3343 my $treatNullAs = $indexedSetterFunction->parameters->[1]->extendedAttributes->{"TreatNullAs"}; 3344 my $treatUndefinedAs = $indexedSetterFunction->parameters->[1]->extendedAttributes->{"TreatUndefinedAs"}; 3345 my $code = "static void indexedPropertySetter(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3346 $code .= "{\n"; 3347 $code .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3348 $code .= JSValueToNativeStatement($indexedSetterFunction->parameters->[1]->type, $indexedSetterFunction->extendedAttributes, "value", "propertyValue", " ", "info.GetIsolate()"); 3349 3350 my $extraArguments = ""; 3351 if ($raisesExceptions) { 3352 $code .= " ExceptionState es(info.GetIsolate());\n"; 3353 $extraArguments = ", es"; 3354 } 3355 my @conditions = (); 3356 my @statements = (); 3357 if ($treatNullAs && $treatNullAs ne "NullString") { 3358 push @conditions, "value->IsNull()"; 3359 push @statements, "collection->${treatNullAs}(index$extraArguments);"; 3360 } 3361 if ($treatUndefinedAs && $treatUndefinedAs ne "NullString") { 3362 push @conditions, "value->IsUndefined()"; 3363 push @statements, "collection->${treatUndefinedAs}(index$extraArguments);"; 3364 } 3365 push @conditions, ""; 3366 push @statements, "collection->${methodName}(index, propertyValue$extraArguments);"; 3367 $code .= GenerateIfElseStatement("bool", "result", \@conditions, \@statements); 3368 3369 $code .= " if (!result)\n"; 3370 $code .= " return;\n"; 3371 if ($raisesExceptions) { 3372 $code .= " if (es.throwIfNeeded())\n"; 3373 $code .= " return;\n"; 3374 } 3375 $code .= " v8SetReturnValue(info, value);\n"; 3376 $code .= "}\n\n"; 3377 $implementation{nameSpaceInternal}->add($code); 3378 } 3379 3380 sub GenerateImplementationNamedPropertyAccessors 3381 { 3382 my $interface = shift; 3383 3384 my $interfaceName = $interface->name; 3385 my $implClassName = GetImplName($interface); 3386 my $v8ClassName = GetV8ClassName($interface); 3387 3388 my $namedGetterFunction = GetNamedGetterFunction($interface); 3389 if ($namedGetterFunction) { 3390 my $hasCustomNamedGetter = $namedGetterFunction->extendedAttributes->{"Custom"}; 3391 if (!$hasCustomNamedGetter) { 3392 GenerateImplementationNamedPropertyGetter($interface, $namedGetterFunction); 3393 } 3394 GenerateImplementationNamedPropertyGetterCallback($interface, $hasCustomNamedGetter); 3395 } 3396 3397 my $namedSetterFunction = GetNamedSetterFunction($interface); 3398 if ($namedSetterFunction) { 3399 my $hasCustomNamedSetter = $namedSetterFunction->extendedAttributes->{"Custom"}; 3400 if (!$hasCustomNamedSetter) { 3401 GenerateImplementationNamedPropertySetter($interface, $namedSetterFunction); 3402 } 3403 GenerateImplementationNamedPropertySetterCallback($interface, $hasCustomNamedSetter); 3404 } 3405 3406 my $namedDeleterFunction = GetNamedDeleterFunction($interface); 3407 if ($namedDeleterFunction) { 3408 my $hasCustomNamedDeleter = $namedDeleterFunction->extendedAttributes->{"Custom"}; 3409 if (!$hasCustomNamedDeleter) { 3410 GenerateImplementationNamedPropertyDeleter($interface, $namedDeleterFunction); 3411 } 3412 GenerateImplementationNamedPropertyDeleterCallback($interface, $hasCustomNamedDeleter); 3413 } 3414 3415 my $namedEnumeratorFunction = $namedGetterFunction && !$namedGetterFunction->extendedAttributes->{"NotEnumerable"}; 3416 if ($namedEnumeratorFunction) { 3417 my $hasCustomNamedEnumerator = $namedGetterFunction->extendedAttributes->{"CustomEnumerateProperty"}; 3418 if (!$hasCustomNamedEnumerator) { 3419 GenerateImplementationNamedPropertyEnumerator($interface); 3420 GenerateImplementationNamedPropertyQuery($interface); 3421 } 3422 GenerateImplementationNamedPropertyEnumeratorCallback($interface, $hasCustomNamedEnumerator); 3423 GenerateImplementationNamedPropertyQueryCallback($interface, $hasCustomNamedEnumerator); 3424 } 3425 3426 my $subCode = ""; 3427 if ($namedGetterFunction || $namedSetterFunction || $namedDeleterFunction || $namedEnumeratorFunction) { 3428 my $setOn = "Instance"; 3429 3430 # V8 has access-check callback API (see ObjectTemplate::SetAccessCheckCallbacks) and it's used on Window 3431 # instead of deleters or enumerators. In addition, the getter should be set on prototype template, to 3432 # get implementation straight out of the Window prototype regardless of what prototype is actually set 3433 # on the object. 3434 if ($interfaceName eq "Window") { 3435 $setOn = "Prototype"; 3436 } 3437 3438 $subCode .= " desc->${setOn}Template()->SetNamedPropertyHandler("; 3439 $subCode .= $namedGetterFunction ? "${implClassName}V8Internal::namedPropertyGetterCallback, " : "0, "; 3440 $subCode .= $namedSetterFunction ? "${implClassName}V8Internal::namedPropertySetterCallback, " : "0, "; 3441 $subCode .= $namedEnumeratorFunction ? "${implClassName}V8Internal::namedPropertyQueryCallback, " : "0, "; 3442 $subCode .= $namedDeleterFunction ? "${implClassName}V8Internal::namedPropertyDeleterCallback, " : "0, "; 3443 $subCode .= $namedEnumeratorFunction ? "${implClassName}V8Internal::namedPropertyEnumeratorCallback" : "0"; 3444 $subCode .= ");\n"; 3445 } 3446 3447 return $subCode; 3448 } 3449 3450 sub GenerateImplementationNamedPropertyGetterCallback 3451 { 3452 my $interface = shift; 3453 my $hasCustom = shift; 3454 my $implClassName = GetImplName($interface); 3455 my $v8ClassName = GetV8ClassName($interface); 3456 3457 my $code = "static void namedPropertyGetterCallback(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3458 $code .= "{\n"; 3459 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMNamedProperty\");\n"; 3460 if ($hasCustom) { 3461 $code .= " ${v8ClassName}::namedPropertyGetterCustom(name, info);\n"; 3462 } else { 3463 $code .= " ${implClassName}V8Internal::namedPropertyGetter(name, info);\n"; 3464 } 3465 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3466 $code .= "}\n\n"; 3467 $implementation{nameSpaceInternal}->add($code); 3468 } 3469 3470 sub GenerateImplementationNamedPropertySetterCallback 3471 { 3472 my $interface = shift; 3473 my $hasCustom = shift; 3474 my $implClassName = GetImplName($interface); 3475 my $v8ClassName = GetV8ClassName($interface); 3476 3477 my $code = "static void namedPropertySetterCallback(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3478 $code .= "{\n"; 3479 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMNamedProperty\");\n"; 3480 if ($hasCustom) { 3481 $code .= " ${v8ClassName}::namedPropertySetterCustom(name, value, info);\n"; 3482 } else { 3483 $code .= " ${implClassName}V8Internal::namedPropertySetter(name, value, info);\n"; 3484 } 3485 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3486 $code .= "}\n\n"; 3487 $implementation{nameSpaceInternal}->add($code); 3488 } 3489 3490 sub GenerateImplementationNamedPropertyDeleterCallback 3491 { 3492 my $interface = shift; 3493 my $hasCustom = shift; 3494 my $implClassName = GetImplName($interface); 3495 my $v8ClassName = GetV8ClassName($interface); 3496 3497 my $code = "static void namedPropertyDeleterCallback(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Boolean>& info)\n"; 3498 $code .= "{\n"; 3499 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMNamedProperty\");\n"; 3500 if ($hasCustom) { 3501 $code .= " ${v8ClassName}::namedPropertyDeleterCustom(name, info);\n"; 3502 } else { 3503 $code .= " ${implClassName}V8Internal::namedPropertyDeleter(name, info);\n"; 3504 } 3505 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3506 $code .= "}\n\n"; 3507 $implementation{nameSpaceInternal}->add($code); 3508 } 3509 3510 sub GenerateImplementationNamedPropertyEnumeratorCallback 3511 { 3512 my $interface = shift; 3513 my $hasCustom = shift; 3514 my $implClassName = GetImplName($interface); 3515 my $v8ClassName = GetV8ClassName($interface); 3516 3517 my $code = "static void namedPropertyEnumeratorCallback(const v8::PropertyCallbackInfo<v8::Array>& info)\n"; 3518 $code .= "{\n"; 3519 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMNamedProperty\");\n"; 3520 if ($hasCustom) { 3521 $code .= " ${v8ClassName}::namedPropertyEnumeratorCustom(info);\n"; 3522 } else { 3523 $code .= " ${implClassName}V8Internal::namedPropertyEnumerator(info);\n"; 3524 } 3525 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3526 $code .= "}\n\n"; 3527 $implementation{nameSpaceInternal}->add($code); 3528 } 3529 3530 sub GenerateImplementationNamedPropertyQueryCallback 3531 { 3532 my $interface = shift; 3533 my $hasCustom = shift; 3534 my $implClassName = GetImplName($interface); 3535 my $v8ClassName = GetV8ClassName($interface); 3536 3537 my $code = "static void namedPropertyQueryCallback(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Integer>& info)\n"; 3538 $code .= "{\n"; 3539 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"Blink\", \"DOMNamedProperty\");\n"; 3540 if ($hasCustom) { 3541 $code .= " ${v8ClassName}::namedPropertyQueryCustom(name, info);\n"; 3542 } else { 3543 $code .= " ${implClassName}V8Internal::namedPropertyQuery(name, info);\n"; 3544 } 3545 $code .= " TRACE_EVENT_SET_SAMPLING_STATE(\"V8\", \"Execution\");\n"; 3546 $code .= "}\n\n"; 3547 $implementation{nameSpaceInternal}->add($code); 3548 } 3549 3550 sub GenerateMethodCall 3551 { 3552 my $returnType = shift; # string or UnionType 3553 my $returnName = shift; 3554 my $functionExpression = shift; 3555 my $firstArgument = shift; 3556 my $raisesExceptions = shift; 3557 3558 my @arguments = (); 3559 push @arguments, $firstArgument; 3560 if ($raisesExceptions) { 3561 push @arguments, "es"; 3562 } 3563 3564 if (IsUnionType($returnType)) { 3565 my $code = ""; 3566 my @extraArguments = (); 3567 for my $i (0..scalar(@{$returnType->unionMemberTypes})-1) { 3568 my $unionMemberType = $returnType->unionMemberTypes->[$i]; 3569 my $nativeType = GetNativeType($unionMemberType); 3570 my $unionMemberVariable = $returnName . $i; 3571 my $unionMemberEnabledVariable = $returnName . $i . "Enabled"; 3572 $code .= " bool ${unionMemberEnabledVariable} = false;\n"; 3573 $code .= " ${nativeType} ${unionMemberVariable};\n"; 3574 push @extraArguments, $unionMemberEnabledVariable; 3575 push @extraArguments, $unionMemberVariable; 3576 } 3577 push @arguments, @extraArguments; 3578 $code .= " ${functionExpression}(" . (join ", ", @arguments) . ");"; 3579 return $code; 3580 } else { 3581 my $nativeType = GetNativeType($returnType); 3582 return " ${nativeType} element = ${functionExpression}(" . (join ", ", @arguments) . ");" 3583 } 3584 } 3585 3586 sub GenerateImplementationNamedPropertyGetter 3587 { 3588 my $interface = shift; 3589 my $namedGetterFunction = shift; 3590 my $implClassName = GetImplName($interface); 3591 my $v8ClassName = GetV8ClassName($interface); 3592 my $methodName = GetImplName($namedGetterFunction); 3593 3594 my $returnType = $namedGetterFunction->type; 3595 my $isNull = GenerateIsNullExpression($returnType, "element"); 3596 my $nativeValue = "element"; 3597 $nativeValue .= ".release()" if (IsRefPtrType($returnType)); 3598 my $returnJSValueCode = NativeToJSValue($namedGetterFunction->type, $namedGetterFunction->extendedAttributes, $nativeValue, " ", "", "info.Holder()", "info.GetIsolate()", "info", "collection", "", "return"); 3599 my $raisesExceptions = $namedGetterFunction->extendedAttributes->{"RaisesException"}; 3600 my $methodCallCode = GenerateMethodCall($returnType, "element", "collection->${methodName}", "propertyName", $raisesExceptions); 3601 3602 my $code = "static void namedPropertyGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3603 $code .= "{\n"; 3604 if (!$namedGetterFunction->extendedAttributes->{"OverrideBuiltins"}) { 3605 $code .= " if (!info.Holder()->GetRealNamedPropertyInPrototypeChain(name).IsEmpty())\n"; 3606 $code .= " return;\n"; 3607 $code .= " if (info.Holder()->HasRealNamedCallbackProperty(name))\n"; 3608 $code .= " return;\n"; 3609 $code .= " if (info.Holder()->HasRealNamedProperty(name))\n"; 3610 $code .= " return;\n"; 3611 } 3612 $code .= "\n"; 3613 $code .= " ASSERT(V8DOMWrapper::maybeDOMWrapper(info.Holder()));\n"; 3614 $code .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3615 $code .= " AtomicString propertyName = toWebCoreAtomicString(name);\n"; 3616 if ($raisesExceptions) { 3617 $code .= " ExceptionState es(info.GetIsolate());\n"; 3618 } 3619 $code .= $methodCallCode . "\n"; 3620 if ($raisesExceptions) { 3621 $code .= " if (es.throwIfNeeded())\n"; 3622 $code .= " return;\n"; 3623 } 3624 if (IsUnionType($returnType)) { 3625 $code .= "${returnJSValueCode}\n"; 3626 $code .= " return;\n"; 3627 } else { 3628 $code .= " if (${isNull})\n"; 3629 $code .= " return;\n"; 3630 $code .= $returnJSValueCode . "\n"; 3631 } 3632 $code .= "}\n\n"; 3633 $implementation{nameSpaceInternal}->add($code); 3634 } 3635 3636 sub GenerateImplementationNamedPropertySetter 3637 { 3638 my $interface = shift; 3639 my $namedSetterFunction = shift; 3640 my $implClassName = GetImplName($interface); 3641 my $v8ClassName = GetV8ClassName($interface); 3642 my $methodName = GetImplName($namedSetterFunction); 3643 3644 my $raisesExceptions = $namedSetterFunction->extendedAttributes->{"RaisesException"}; 3645 my $treatNullAs = $namedSetterFunction->parameters->[1]->extendedAttributes->{"TreatNullAs"}; 3646 my $treatUndefinedAs = $namedSetterFunction->parameters->[1]->extendedAttributes->{"TreatUndefinedAs"}; 3647 3648 my $code = "static void namedPropertySetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info)\n"; 3649 $code .= "{\n"; 3650 if (!$namedSetterFunction->extendedAttributes->{"OverrideBuiltins"}) { 3651 $code .= " if (!info.Holder()->GetRealNamedPropertyInPrototypeChain(name).IsEmpty())\n"; 3652 $code .= " return;\n"; 3653 $code .= " if (info.Holder()->HasRealNamedCallbackProperty(name))\n"; 3654 $code .= " return;\n"; 3655 $code .= " if (info.Holder()->HasRealNamedProperty(name))\n"; 3656 $code .= " return;\n"; 3657 } 3658 $code .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3659 $code .= JSValueToNativeStatement($namedSetterFunction->parameters->[0]->type, $namedSetterFunction->extendedAttributes, "name", "propertyName", " ", "info.GetIsolate()"); 3660 $code .= JSValueToNativeStatement($namedSetterFunction->parameters->[1]->type, $namedSetterFunction->extendedAttributes, "value", "propertyValue", " ", "info.GetIsolate()"); 3661 my $extraArguments = ""; 3662 if ($raisesExceptions) { 3663 $code .= " ExceptionState es(info.GetIsolate());\n"; 3664 $extraArguments = ", es"; 3665 } 3666 3667 my @conditions = (); 3668 my @statements = (); 3669 if ($treatNullAs && $treatNullAs ne "NullString") { 3670 push @conditions, "value->IsNull()"; 3671 push @statements, "collection->${treatNullAs}(propertyName$extraArguments);"; 3672 } 3673 if ($treatUndefinedAs && $treatUndefinedAs ne "NullString") { 3674 push @conditions, "value->IsUndefined()"; 3675 push @statements, "collection->${treatUndefinedAs}(propertyName$extraArguments);"; 3676 } 3677 push @conditions, ""; 3678 push @statements, "collection->${methodName}(propertyName, propertyValue$extraArguments);"; 3679 $code .= GenerateIfElseStatement("bool", "result", \@conditions, \@statements); 3680 3681 $code .= " if (!result)\n"; 3682 $code .= " return;\n"; 3683 if ($raisesExceptions) { 3684 $code .= " if (es.throwIfNeeded())\n"; 3685 $code .= " return;\n"; 3686 } 3687 $code .= " v8SetReturnValue(info, value);\n"; 3688 $code .= "}\n\n"; 3689 $implementation{nameSpaceInternal}->add($code); 3690 } 3691 3692 sub GenerateImplementationIndexedPropertyDeleter 3693 { 3694 my $interface = shift; 3695 my $indexedDeleterFunction = shift; 3696 my $implClassName = GetImplName($interface); 3697 my $v8ClassName = GetV8ClassName($interface); 3698 my $methodName = GetImplName($indexedDeleterFunction); 3699 3700 my $raisesExceptions = $indexedDeleterFunction->extendedAttributes->{"RaisesException"}; 3701 3702 my $code = "static void indexedPropertyDeleter(unsigned index, const v8::PropertyCallbackInfo<v8::Boolean>& info)\n"; 3703 $code .= "{\n"; 3704 $code .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3705 my $extraArguments = ""; 3706 if ($raisesExceptions) { 3707 $code .= " ExceptionState es(info.GetIsolate());\n"; 3708 $extraArguments = ", es"; 3709 } 3710 $code .= " bool result = collection->${methodName}(index$extraArguments);\n"; 3711 if ($raisesExceptions) { 3712 $code .= " if (es.throwIfNeeded())\n"; 3713 $code .= " return;\n"; 3714 } 3715 $code .= " return v8SetReturnValueBool(info, result);\n"; 3716 $code .= "}\n\n"; 3717 $implementation{nameSpaceInternal}->add($code); 3718 } 3719 3720 sub GenerateImplementationNamedPropertyDeleter 3721 { 3722 my $interface = shift; 3723 my $namedDeleterFunction = shift; 3724 my $implClassName = GetImplName($interface); 3725 my $v8ClassName = GetV8ClassName($interface); 3726 my $methodName = GetImplName($namedDeleterFunction); 3727 3728 my $raisesExceptions = $namedDeleterFunction->extendedAttributes->{"RaisesException"}; 3729 3730 my $code = "static void namedPropertyDeleter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Boolean>& info)\n"; 3731 $code .= "{\n"; 3732 $code .= " ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder());\n"; 3733 $code .= " AtomicString propertyName = toWebCoreAtomicString(name);\n"; 3734 my $extraArguments = ""; 3735 if ($raisesExceptions) { 3736 $code .= " ExceptionState es(info.GetIsolate());\n"; 3737 $extraArguments = ", es"; 3738 } 3739 $code .= " bool result = collection->${methodName}(propertyName$extraArguments);\n"; 3740 if ($raisesExceptions) { 3741 $code .= " if (es.throwIfNeeded())\n"; 3742 $code .= " return;\n"; 3743 } 3744 $code .= " return v8SetReturnValueBool(info, result);\n"; 3745 $code .= "}\n\n"; 3746 $implementation{nameSpaceInternal}->add($code); 3747 } 3748 3749 sub GenerateImplementationNamedPropertyEnumerator 3750 { 3751 my $interface = shift; 3752 my $implClassName = GetImplName($interface); 3753 my $v8ClassName = GetV8ClassName($interface); 3754 3755 $implementation{nameSpaceInternal}->add(<<END); 3756 static void namedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) 3757 { 3758 ExceptionState es(info.GetIsolate()); 3759 ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder()); 3760 Vector<String> names; 3761 collection->namedPropertyEnumerator(names, es); 3762 if (es.throwIfNeeded()) 3763 return; 3764 v8::Handle<v8::Array> v8names = v8::Array::New(names.size()); 3765 for (size_t i = 0; i < names.size(); ++i) 3766 v8names->Set(v8::Integer::New(i, info.GetIsolate()), v8String(names[i], info.GetIsolate())); 3767 v8SetReturnValue(info, v8names); 3768 } 3769 3770 END 3771 } 3772 3773 sub GenerateImplementationNamedPropertyQuery 3774 { 3775 my $interface = shift; 3776 my $implClassName = GetImplName($interface); 3777 my $v8ClassName = GetV8ClassName($interface); 3778 3779 $implementation{nameSpaceInternal}->add(<<END); 3780 static void namedPropertyQuery(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Integer>& info) 3781 { 3782 ${implClassName}* collection = ${v8ClassName}::toNative(info.Holder()); 3783 AtomicString propertyName = toWebCoreAtomicString(name); 3784 ExceptionState es(info.GetIsolate()); 3785 bool result = collection->namedPropertyQuery(propertyName, es); 3786 if (es.throwIfNeeded()) 3787 return; 3788 if (!result) 3789 return; 3790 v8SetReturnValueInt(info, v8::None); 3791 } 3792 3793 END 3794 } 3795 3796 sub GenerateImplementationLegacyCall 3797 { 3798 my $interface = shift; 3799 my $code = ""; 3800 3801 my $v8ClassName = GetV8ClassName($interface); 3802 3803 if ($interface->extendedAttributes->{"CustomLegacyCall"}) { 3804 $code .= " desc->InstanceTemplate()->SetCallAsFunctionHandler(${v8ClassName}::legacyCallCustom);\n"; 3805 } 3806 return $code; 3807 } 3808 3809 sub GenerateImplementationMasqueradesAsUndefined 3810 { 3811 my $interface = shift; 3812 my $code = ""; 3813 3814 if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) 3815 { 3816 $code .= " desc->InstanceTemplate()->MarkAsUndetectable();\n"; 3817 } 3818 return $code; 3819 } 3820 3821 sub GenerateImplementation 3822 { 3823 my $object = shift; 3824 my $interface = shift; 3825 my $interfaceName = $interface->name; 3826 my $implClassName = GetImplName($interface); 3827 my $v8ClassName = GetV8ClassName($interface); 3828 my $nativeType = GetNativeTypeForConversions($interface); 3829 3830 AddToImplIncludes("bindings/v8/V8Binding.h"); 3831 AddToImplIncludes("bindings/v8/V8DOMWrapper.h"); 3832 AddToImplIncludes("core/dom/ContextFeatures.h"); 3833 AddToImplIncludes("core/dom/Document.h"); 3834 AddToImplIncludes("RuntimeEnabledFeatures.h"); 3835 AddToImplIncludes("core/platform/chromium/TraceEvent.h"); 3836 3837 AddIncludesForType($interfaceName); 3838 3839 my $toActiveDOMObject = InheritsExtendedAttribute($interface, "ActiveDOMObject") ? "${v8ClassName}::toActiveDOMObject" : "0"; 3840 my $toEventTarget = InheritsInterface($interface, "EventTarget") ? "${v8ClassName}::toEventTarget" : "0"; 3841 my $rootForGC = NeedsOpaqueRootForGC($interface) ? "${v8ClassName}::opaqueRootForGC" : "0"; 3842 3843 # Find the super descriptor. 3844 my $parentClass = ""; 3845 my $parentClassTemplate = ""; 3846 if ($interface->parent) { 3847 my $parent = $interface->parent; 3848 AddToImplIncludes("V8${parent}.h"); 3849 $parentClass = "V8" . $parent; 3850 $parentClassTemplate = $parentClass . "::GetTemplate(isolate, currentWorldType)"; 3851 } 3852 3853 my $parentClassInfo = $parentClass ? "&${parentClass}::info" : "0"; 3854 my $WrapperTypePrototype = $interface->isException ? "WrapperTypeErrorPrototype" : "WrapperTypeObjectPrototype"; 3855 3856 if (!IsSVGTypeNeedingTearOff($interfaceName)) { 3857 my $code = <<END; 3858 static void initializeScriptWrappableForInterface(${implClassName}* object) 3859 { 3860 if (ScriptWrappable::wrapperCanBeStoredInObject(object)) 3861 ScriptWrappable::setTypeInfoInObject(object, &${v8ClassName}::info); 3862 else 3863 ASSERT_NOT_REACHED(); 3864 } 3865 3866 } // namespace WebCore 3867 3868 // In ScriptWrappable::init, the use of a local function declaration has an issue on Windows: 3869 // the local declaration does not pick up the surrounding namespace. Therefore, we provide this function 3870 // in the global namespace. 3871 // (More info on the MSVC bug here: http://connect.microsoft.com/VisualStudio/feedback/details/664619/the-namespace-of-local-function-declarations-in-c) 3872 END 3873 3874 if (GetNamespaceForInterface($interface) eq "WebCore") { 3875 $code .= "void webCoreInitializeScriptWrappableForInterface(WebCore::${implClassName}* object)\n"; 3876 } else { 3877 $code .= "void webCoreInitializeScriptWrappableForInterface(${implClassName}* object)\n"; 3878 } 3879 3880 $code .= <<END; 3881 { 3882 WebCore::initializeScriptWrappableForInterface(object); 3883 } 3884 3885 namespace WebCore { 3886 END 3887 $implementation{nameSpaceWebCore}->addHeader($code); 3888 } 3889 3890 my $code = "WrapperTypeInfo ${v8ClassName}::info = { ${v8ClassName}::GetTemplate, ${v8ClassName}::derefObject, $toActiveDOMObject, $toEventTarget, "; 3891 $code .= "$rootForGC, ${v8ClassName}::installPerContextPrototypeProperties, $parentClassInfo, $WrapperTypePrototype };\n"; 3892 $implementation{nameSpaceWebCore}->addHeader($code); 3893 3894 $implementation{nameSpaceInternal}->add("template <typename T> void V8_USE(T) { }\n\n"); 3895 3896 my $hasConstructors = 0; 3897 my $hasReplaceable = 0; 3898 3899 # Generate property accessors for attributes. 3900 for (my $index = 0; $index < @{$interface->attributes}; $index++) { 3901 my $attribute = @{$interface->attributes}[$index]; 3902 my $attrType = $attribute->type; 3903 my $attrExt = $attribute->extendedAttributes; 3904 3905 # Generate special code for the constructor attributes. 3906 if ($attrType =~ /Constructor$/) { 3907 if (!HasCustomGetter($attrExt)) { 3908 $hasConstructors = 1; 3909 } 3910 next; 3911 } 3912 3913 if ($attrType eq "EventHandler" && $interfaceName eq "Window") { 3914 $attrExt->{"OnProto"} = 1; 3915 } 3916 3917 if ($attrType eq "SerializedScriptValue") { 3918 AddToImplIncludes("bindings/v8/SerializedScriptValue.h"); 3919 } 3920 3921 GenerateNormalAttrGetter($attribute, $interface, ""); 3922 GenerateNormalAttrGetterCallback($attribute, $interface, ""); 3923 if ($attrExt->{"PerWorldBindings"}) { 3924 GenerateNormalAttrGetter($attribute, $interface, "ForMainWorld"); 3925 GenerateNormalAttrGetterCallback($attribute, $interface, "ForMainWorld"); 3926 } 3927 if (!HasCustomSetter($attrExt) && $attrExt->{"Replaceable"}) { 3928 $hasReplaceable = 1; 3929 } elsif (!IsReadonly($attribute)) { 3930 GenerateNormalAttrSetter($attribute, $interface, ""); 3931 GenerateNormalAttrSetterCallback($attribute, $interface, ""); 3932 if ($attrExt->{"PerWorldBindings"}) { 3933 GenerateNormalAttrSetter($attribute, $interface, "ForMainWorld"); 3934 GenerateNormalAttrSetterCallback($attribute, $interface, "ForMainWorld"); 3935 } 3936 } 3937 } 3938 3939 if ($hasConstructors) { 3940 GenerateConstructorGetter($interface); 3941 } 3942 3943 if ($hasConstructors || $hasReplaceable) { 3944 GenerateReplaceableAttrSetter($interface); 3945 GenerateReplaceableAttrSetterCallback($interface); 3946 } 3947 3948 if (NeedsOpaqueRootForGC($interface)) { 3949 GenerateOpaqueRootForGC($interface); 3950 } 3951 3952 if ($interface->extendedAttributes->{"CheckSecurity"} && $interface->name ne "Window") { 3953 GenerateSecurityCheckFunctions($interface); 3954 } 3955 3956 if (IsConstructorTemplate($interface, "TypedArray")) { 3957 my ($nativeType, $arrayType) = GetNativeTypeOfTypedArray($interface); 3958 $implementation{nameSpaceWebCore}->add(<<END); 3959 v8::Handle<v8::Object> wrap($implClassName* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 3960 { 3961 ASSERT(impl); 3962 v8::Handle<v8::Object> wrapper = ${v8ClassName}::createWrapper(impl, creationContext, isolate); 3963 if (!wrapper.IsEmpty()) 3964 wrapper->SetIndexedPropertiesToExternalArrayData(impl->baseAddress(), $arrayType, impl->length()); 3965 return wrapper; 3966 } 3967 3968 END 3969 } 3970 3971 my @enabledPerContextFunctions; 3972 my @normalFunctions; 3973 my $needsDomainSafeFunctionSetter = 0; 3974 # Generate methods for functions. 3975 foreach my $function (@{$interface->functions}) { 3976 next if $function->name eq ""; 3977 GenerateFunction($function, $interface, ""); 3978 if ($function->extendedAttributes->{"PerWorldBindings"}) { 3979 GenerateFunction($function, $interface, "ForMainWorld"); 3980 } 3981 if ($function->{overloadIndex} == @{$function->{overloads}}) { 3982 if ($function->{overloadIndex} > 1) { 3983 GenerateOverloadedFunction($function, $interface, ""); 3984 if ($function->extendedAttributes->{"PerWorldBindings"}) { 3985 GenerateOverloadedFunction($function, $interface, "ForMainWorld"); 3986 } 3987 } 3988 GenerateFunctionCallback($function, $interface, ""); 3989 if ($function->extendedAttributes->{"PerWorldBindings"}) { 3990 GenerateFunctionCallback($function, $interface, "ForMainWorld"); 3991 } 3992 } 3993 3994 # If the function does not need domain security check, we need to 3995 # generate an access getter that returns different function objects 3996 # for different calling context. 3997 if ($interface->extendedAttributes->{"CheckSecurity"} && $function->extendedAttributes->{"DoNotCheckSecurity"}) { 3998 if (!HasCustomMethod($function->extendedAttributes) || $function->{overloadIndex} == 1) { 3999 GenerateDomainSafeFunctionGetter($function, $interface); 4000 if (!$function->extendedAttributes->{"ReadOnly"}) { 4001 $needsDomainSafeFunctionSetter = 1; 4002 } 4003 } 4004 } 4005 4006 # Separate out functions that are enabled per context so we can process them specially. 4007 if ($function->extendedAttributes->{"EnabledPerContext"}) { 4008 push(@enabledPerContextFunctions, $function); 4009 } else { 4010 push(@normalFunctions, $function); 4011 } 4012 } 4013 4014 if ($needsDomainSafeFunctionSetter) { 4015 GenerateDomainSafeFunctionSetter($interface); 4016 } 4017 4018 # Attributes 4019 my $attributes = $interface->attributes; 4020 4021 # For the Window interface we partition the attributes into the 4022 # ones that disallows shadowing and the rest. 4023 my @disallowsShadowing; 4024 # Also separate out attributes that are enabled at runtime so we can process them specially. 4025 my @enabledAtRuntimeAttributes; 4026 my @enabledPerContextAttributes; 4027 my @normalAttributes; 4028 foreach my $attribute (@$attributes) { 4029 4030 if ($interfaceName eq "Window" && $attribute->extendedAttributes->{"Unforgeable"}) { 4031 push(@disallowsShadowing, $attribute); 4032 } elsif ($attribute->extendedAttributes->{"EnabledAtRuntime"} || $attribute->extendedAttributes->{"EnabledPerContext"}) { 4033 if ($attribute->extendedAttributes->{"EnabledPerContext"}) { 4034 push(@enabledPerContextAttributes, $attribute); 4035 } 4036 if ($attribute->extendedAttributes->{"EnabledAtRuntime"}) { 4037 push(@enabledAtRuntimeAttributes, $attribute); 4038 } 4039 } else { 4040 push(@normalAttributes, $attribute); 4041 } 4042 } 4043 AddToImplIncludes("bindings/v8/V8DOMConfiguration.h"); 4044 $attributes = \@normalAttributes; 4045 # Put the attributes that disallow shadowing on the shadow object. 4046 if (@disallowsShadowing) { 4047 my $code = ""; 4048 $code .= "static const V8DOMConfiguration::BatchedAttribute shadowAttrs[] = {\n"; 4049 $code .= GenerateBatchedAttributeData($interface, \@disallowsShadowing); 4050 $code .= "};\n\n"; 4051 $implementation{nameSpaceWebCore}->add($code); 4052 } 4053 4054 my $has_attributes = 0; 4055 if (@$attributes) { 4056 $has_attributes = 1; 4057 my $code = ""; 4058 $code .= "static const V8DOMConfiguration::BatchedAttribute ${v8ClassName}Attrs[] = {\n"; 4059 $code .= GenerateBatchedAttributeData($interface, $attributes); 4060 $code .= "};\n\n"; 4061 $implementation{nameSpaceWebCore}->add($code); 4062 } 4063 4064 # Setup table of standard callback functions 4065 my $num_callbacks = 0; 4066 my $has_callbacks = 0; 4067 $code = ""; 4068 foreach my $function (@normalFunctions) { 4069 # Only one table entry is needed for overloaded methods: 4070 next if $function->{overloadIndex} > 1; 4071 # Don't put any nonstandard functions into this table: 4072 next if !IsStandardFunction($interface, $function); 4073 next if $function->name eq ""; 4074 if (!$has_callbacks) { 4075 $has_callbacks = 1; 4076 $code .= "static const V8DOMConfiguration::BatchedMethod ${v8ClassName}Methods[] = {\n"; 4077 } 4078 my $name = $function->name; 4079 my $methodForMainWorld = "0"; 4080 if ($function->extendedAttributes->{"PerWorldBindings"}) { 4081 $methodForMainWorld = "${implClassName}V8Internal::${name}MethodCallbackForMainWorld"; 4082 } 4083 my $functionLength = GetFunctionLength($function); 4084 my $conditionalString = GenerateConditionalString($function); 4085 $code .= "#if ${conditionalString}\n" if $conditionalString; 4086 $code .= <<END; 4087 {"$name", ${implClassName}V8Internal::${name}MethodCallback, ${methodForMainWorld}, ${functionLength}}, 4088 END 4089 $code .= "#endif // ${conditionalString}\n" if $conditionalString; 4090 $num_callbacks++; 4091 } 4092 $code .= "};\n\n" if $has_callbacks; 4093 $implementation{nameSpaceWebCore}->add($code); 4094 4095 # Setup constants 4096 my $has_constants = 0; 4097 my @constantsEnabledAtRuntime; 4098 $code = ""; 4099 if (@{$interface->constants}) { 4100 $has_constants = 1; 4101 $code .= "static const V8DOMConfiguration::BatchedConstant ${v8ClassName}Consts[] = {\n"; 4102 } 4103 foreach my $constant (@{$interface->constants}) { 4104 my $name = $constant->name; 4105 my $value = $constant->value; 4106 my $attrExt = $constant->extendedAttributes; 4107 my $implementedBy = $attrExt->{"ImplementedBy"}; 4108 if ($implementedBy) { 4109 my $implementedByImplName = GetImplNameFromImplementedBy($implementedBy); 4110 AddToImplIncludes(HeaderFilesForInterface($implementedBy, $implementedByImplName)); 4111 } 4112 if ($attrExt->{"EnabledAtRuntime"}) { 4113 push(@constantsEnabledAtRuntime, $constant); 4114 } else { 4115 my $conditionalString = GenerateConditionalString($constant); 4116 $code .= "#if ${conditionalString}\n" if $conditionalString; 4117 # If the value we're dealing with is a hex number, preprocess it into a signed integer 4118 # here, rather than running static_cast<signed int> in the generated code. 4119 if (substr($value, 0, 2) eq "0x") { 4120 $value = unpack('i', pack('I', hex($value))); 4121 } 4122 $code .= <<END; 4123 {"${name}", $value}, 4124 END 4125 $code .= "#endif\n" if $conditionalString; 4126 } 4127 } 4128 if ($has_constants) { 4129 $code .= "};\n\n"; 4130 $code .= join "", GenerateCompileTimeCheckForEnumsIfNeeded($interface); 4131 $implementation{nameSpaceWebCore}->add($code); 4132 } 4133 4134 if (!HasCustomConstructor($interface)) { 4135 if ($interface->extendedAttributes->{"NamedConstructor"}) { 4136 GenerateNamedConstructor(@{$interface->constructors}[0], $interface); 4137 } elsif ($interface->extendedAttributes->{"Constructor"}) { 4138 GenerateConstructor($interface); 4139 } elsif (IsConstructorTemplate($interface, "Event")) { 4140 GenerateEventConstructor($interface); 4141 } 4142 } 4143 if (IsConstructable($interface)) { 4144 GenerateConstructorCallback($interface); 4145 } 4146 4147 my $access_check = ""; 4148 if ($interface->extendedAttributes->{"CheckSecurity"} && $interfaceName ne "Window") { 4149 $access_check = "instance->SetAccessCheckCallbacks(${implClassName}V8Internal::namedSecurityCheck, ${implClassName}V8Internal::indexedSecurityCheck, v8::External::New(&${v8ClassName}::info));"; 4150 } 4151 4152 # For the Window interface, generate the shadow object template 4153 # configuration method. 4154 if ($interfaceName eq "Window") { 4155 $implementation{nameSpaceWebCore}->add(<<END); 4156 static void ConfigureShadowObjectTemplate(v8::Handle<v8::ObjectTemplate> templ, v8::Isolate* isolate, WrapperWorldType currentWorldType) 4157 { 4158 V8DOMConfiguration::batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs), isolate, currentWorldType); 4159 4160 // Install a security handler with V8. 4161 templ->SetAccessCheckCallbacks(V8Window::namedSecurityCheckCustom, V8Window::indexedSecurityCheckCustom, v8::External::New(&V8Window::info)); 4162 templ->SetInternalFieldCount(V8Window::internalFieldCount); 4163 } 4164 END 4165 } 4166 4167 if (!$parentClassTemplate) { 4168 $parentClassTemplate = "v8::Local<v8::FunctionTemplate>()"; 4169 } 4170 4171 # Generate the template configuration method 4172 $code = <<END; 4173 static v8::Handle<v8::FunctionTemplate> Configure${v8ClassName}Template(v8::Handle<v8::FunctionTemplate> desc, v8::Isolate* isolate, WrapperWorldType currentWorldType) 4174 { 4175 desc->ReadOnlyPrototype(); 4176 4177 v8::Local<v8::Signature> defaultSignature; 4178 END 4179 if ($interface->extendedAttributes->{"EnabledAtRuntime"}) { 4180 my $enable_function = GetRuntimeEnableFunctionName($interface); 4181 $code .= <<END; 4182 if (!${enable_function}()) 4183 defaultSignature = V8DOMConfiguration::configureTemplate(desc, \"\", $parentClassTemplate, ${v8ClassName}::internalFieldCount, 0, 0, 0, 0, isolate, currentWorldType); 4184 else 4185 END 4186 } 4187 $code .= <<END; 4188 defaultSignature = V8DOMConfiguration::configureTemplate(desc, \"${interfaceName}\", $parentClassTemplate, ${v8ClassName}::internalFieldCount, 4189 END 4190 # Set up our attributes if we have them 4191 if ($has_attributes) { 4192 $code .= <<END; 4193 ${v8ClassName}Attrs, WTF_ARRAY_LENGTH(${v8ClassName}Attrs), 4194 END 4195 } else { 4196 $code .= <<END; 4197 0, 0, 4198 END 4199 } 4200 4201 if ($has_callbacks) { 4202 $code .= <<END; 4203 ${v8ClassName}Methods, WTF_ARRAY_LENGTH(${v8ClassName}Methods), isolate, currentWorldType); 4204 END 4205 } else { 4206 $code .= <<END; 4207 0, 0, isolate, currentWorldType); 4208 END 4209 } 4210 4211 AddToImplIncludes("wtf/UnusedParam.h"); 4212 $code .= <<END; 4213 UNUSED_PARAM(defaultSignature); // In some cases, it will not be used. 4214 END 4215 4216 if (IsConstructable($interface)) { 4217 $code .= " desc->SetCallHandler(${v8ClassName}::constructorCallback);\n"; 4218 my $interfaceLength = GetInterfaceLength($interface); 4219 $code .= " desc->SetLength(${interfaceLength});\n"; 4220 } 4221 4222 if ($access_check or @enabledAtRuntimeAttributes or @normalFunctions or $has_constants) { 4223 $code .= <<END; 4224 v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); 4225 v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate(); 4226 UNUSED_PARAM(instance); // In some cases, it will not be used. 4227 UNUSED_PARAM(proto); // In some cases, it will not be used. 4228 END 4229 } 4230 4231 if ($access_check) { 4232 $code .= " $access_check\n"; 4233 } 4234 4235 # Setup the enable-at-runtime attrs if we have them 4236 foreach my $runtime_attr (@enabledAtRuntimeAttributes) { 4237 next if grep { $_ eq $runtime_attr } @enabledPerContextAttributes; 4238 my $enable_function = GetRuntimeEnableFunctionName($runtime_attr); 4239 my $conditionalString = GenerateConditionalString($runtime_attr); 4240 $code .= "\n#if ${conditionalString}\n" if $conditionalString; 4241 $code .= " if (${enable_function}()) {\n"; 4242 $code .= " static const V8DOMConfiguration::BatchedAttribute attrData =\\\n"; 4243 $code .= GenerateSingleBatchedAttribute($interface, $runtime_attr, ";", " "); 4244 $code .= <<END; 4245 V8DOMConfiguration::configureAttribute(instance, proto, attrData, isolate, currentWorldType); 4246 } 4247 END 4248 $code .= "\n#endif // ${conditionalString}\n" if $conditionalString; 4249 } 4250 4251 # Setup the enable-at-runtime constants if we have them 4252 foreach my $runtime_const (@constantsEnabledAtRuntime) { 4253 my $enable_function = GetRuntimeEnableFunctionName($runtime_const); 4254 my $conditionalString = GenerateConditionalString($runtime_const); 4255 my $name = $runtime_const->name; 4256 my $value = $runtime_const->value; 4257 $code .= "\n#if ${conditionalString}\n" if $conditionalString; 4258 $code .= " if (${enable_function}()) {\n"; 4259 $code .= <<END; 4260 static const V8DOMConfiguration::BatchedConstant constData = {"${name}", static_cast<signed int>(${value})}; 4261 V8DOMConfiguration::batchConfigureConstants(desc, proto, &constData, 1, isolate); 4262 END 4263 $code .= " }\n"; 4264 $code .= "\n#endif // ${conditionalString}\n" if $conditionalString; 4265 } 4266 4267 $code .= GenerateImplementationIndexedPropertyAccessors($interface); 4268 $code .= GenerateImplementationNamedPropertyAccessors($interface); 4269 $code .= GenerateImplementationLegacyCall($interface); 4270 $code .= GenerateImplementationMasqueradesAsUndefined($interface); 4271 4272 # Define our functions with Set() or SetAccessor() 4273 my $total_functions = 0; 4274 foreach my $function (@normalFunctions) { 4275 # Only one accessor is needed for overloaded methods: 4276 next if $function->{overloadIndex} > 1; 4277 next if $function->name eq ""; 4278 4279 $total_functions++; 4280 next if IsStandardFunction($interface, $function); 4281 $code .= GenerateNonStandardFunction($interface, $function); 4282 $num_callbacks++; 4283 } 4284 4285 die "Wrong number of callbacks generated for $interfaceName ($num_callbacks, should be $total_functions)" if $num_callbacks != $total_functions; 4286 4287 if ($has_constants) { 4288 $code .= <<END; 4289 V8DOMConfiguration::batchConfigureConstants(desc, proto, ${v8ClassName}Consts, WTF_ARRAY_LENGTH(${v8ClassName}Consts), isolate); 4290 END 4291 } 4292 4293 # Special cases 4294 if ($interfaceName eq "Window") { 4295 $code .= <<END; 4296 4297 proto->SetInternalFieldCount(V8Window::internalFieldCount); 4298 desc->SetHiddenPrototype(true); 4299 instance->SetInternalFieldCount(V8Window::internalFieldCount); 4300 // Set access check callbacks, but turned off initially. 4301 // When a context is detached from a frame, turn on the access check. 4302 // Turning on checks also invalidates inline caches of the object. 4303 instance->SetAccessCheckCallbacks(V8Window::namedSecurityCheckCustom, V8Window::indexedSecurityCheckCustom, v8::External::New(&V8Window::info), false); 4304 END 4305 } 4306 if ($interfaceName eq "HTMLDocument" or $interfaceName eq "DedicatedWorkerGlobalScope" or $interfaceName eq "SharedWorkerGlobalScope") { 4307 $code .= <<END; 4308 desc->SetHiddenPrototype(true); 4309 END 4310 } 4311 4312 $code .= <<END; 4313 4314 // Custom toString template 4315 desc->Set(v8::String::NewSymbol("toString"), V8PerIsolateData::current()->toStringTemplate()); 4316 return desc; 4317 } 4318 4319 END 4320 $implementation{nameSpaceWebCore}->add($code); 4321 4322 $implementation{nameSpaceWebCore}->add(<<END); 4323 v8::Handle<v8::FunctionTemplate> ${v8ClassName}::GetTemplate(v8::Isolate* isolate, WrapperWorldType currentWorldType) 4324 { 4325 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 4326 V8PerIsolateData::TemplateMap::iterator result = data->templateMap(currentWorldType).find(&info); 4327 if (result != data->templateMap(currentWorldType).end()) 4328 return result->value.newLocal(isolate); 4329 4330 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "BuildDOMTemplate"); 4331 v8::HandleScope handleScope(isolate); 4332 v8::Handle<v8::FunctionTemplate> templ = 4333 Configure${v8ClassName}Template(data->rawTemplate(&info, currentWorldType), isolate, currentWorldType); 4334 data->templateMap(currentWorldType).add(&info, UnsafePersistent<v8::FunctionTemplate>(isolate, templ)); 4335 return handleScope.Close(templ); 4336 } 4337 4338 END 4339 $implementation{nameSpaceWebCore}->add(<<END); 4340 bool ${v8ClassName}::HasInstance(v8::Handle<v8::Value> value, v8::Isolate* isolate, WrapperWorldType currentWorldType) 4341 { 4342 return V8PerIsolateData::from(isolate)->hasInstance(&info, value, currentWorldType); 4343 } 4344 4345 END 4346 $implementation{nameSpaceWebCore}->add(<<END); 4347 bool ${v8ClassName}::HasInstanceInAnyWorld(v8::Handle<v8::Value> value, v8::Isolate* isolate) 4348 { 4349 return V8PerIsolateData::from(isolate)->hasInstance(&info, value, MainWorld) 4350 || V8PerIsolateData::from(isolate)->hasInstance(&info, value, IsolatedWorld) 4351 || V8PerIsolateData::from(isolate)->hasInstance(&info, value, WorkerWorld); 4352 } 4353 4354 END 4355 4356 if (@enabledPerContextAttributes) { 4357 my $code = ""; 4358 $code .= <<END; 4359 void ${v8ClassName}::installPerContextProperties(v8::Handle<v8::Object> instance, ${nativeType}* impl, v8::Isolate* isolate) 4360 { 4361 v8::Local<v8::Object> proto = v8::Local<v8::Object>::Cast(instance->GetPrototype()); 4362 END 4363 4364 # Setup the enable-by-settings attrs if we have them 4365 foreach my $runtimeAttr (@enabledPerContextAttributes) { 4366 my $enableFunction = GetContextEnableFunction($runtimeAttr); 4367 my $conditionalString = GenerateConditionalString($runtimeAttr); 4368 $code .= "\n#if ${conditionalString}\n" if $conditionalString; 4369 if (grep { $_ eq $runtimeAttr } @enabledAtRuntimeAttributes) { 4370 my $runtimeEnableFunction = GetRuntimeEnableFunctionName($runtimeAttr); 4371 $code .= " if (${enableFunction}(impl->document()) && ${runtimeEnableFunction}()) {\n"; 4372 } else { 4373 $code .= " if (${enableFunction}(impl->document())) {\n"; 4374 } 4375 4376 $code .= " static const V8DOMConfiguration::BatchedAttribute attrData =\\\n"; 4377 $code .= GenerateSingleBatchedAttribute($interface, $runtimeAttr, ";", " "); 4378 $code .= <<END; 4379 V8DOMConfiguration::configureAttribute(instance, proto, attrData, isolate); 4380 END 4381 $code .= " }\n"; 4382 $code .= "#endif // ${conditionalString}\n" if $conditionalString; 4383 } 4384 $code .= <<END; 4385 } 4386 4387 END 4388 $implementation{nameSpaceWebCore}->add($code); 4389 } 4390 4391 if (@enabledPerContextFunctions) { 4392 my $code = ""; 4393 $code .= <<END; 4394 void ${v8ClassName}::installPerContextPrototypeProperties(v8::Handle<v8::Object> proto, v8::Isolate* isolate) 4395 { 4396 UNUSED_PARAM(proto); 4397 END 4398 # Setup the enable-by-settings functions if we have them 4399 $code .= <<END; 4400 v8::Local<v8::Signature> defaultSignature = v8::Signature::New(GetTemplate(isolate, worldType(isolate))); 4401 UNUSED_PARAM(defaultSignature); // In some cases, it will not be used. 4402 4403 ScriptExecutionContext* context = toScriptExecutionContext(proto->CreationContext()); 4404 END 4405 4406 foreach my $runtimeFunc (@enabledPerContextFunctions) { 4407 my $enableFunction = GetContextEnableFunction($runtimeFunc); 4408 my $functionLength = GetFunctionLength($runtimeFunc); 4409 my $conditionalString = GenerateConditionalString($runtimeFunc); 4410 $code .= "\n#if ${conditionalString}\n" if $conditionalString; 4411 $code .= " if (context && context->isDocument() && ${enableFunction}(toDocument(context)))\n"; 4412 my $name = $runtimeFunc->name; 4413 $code .= <<END; 4414 proto->Set(v8::String::NewSymbol("${name}"), v8::FunctionTemplate::New(${implClassName}V8Internal::${name}MethodCallback, v8Undefined(), defaultSignature, $functionLength)->GetFunction()); 4415 END 4416 $code .= "#endif // ${conditionalString}\n" if $conditionalString; 4417 } 4418 4419 $code .= <<END; 4420 } 4421 4422 END 4423 $implementation{nameSpaceWebCore}->add($code); 4424 } 4425 4426 if (InheritsExtendedAttribute($interface, "ActiveDOMObject")) { 4427 # MessagePort is handled like an active dom object even though it doesn't inherit 4428 # from ActiveDOMObject, so don't try to cast it to ActiveDOMObject. 4429 my $returnValue = $interfaceName eq "MessagePort" ? "0" : "toNative(object)"; 4430 $implementation{nameSpaceWebCore}->add(<<END); 4431 ActiveDOMObject* ${v8ClassName}::toActiveDOMObject(v8::Handle<v8::Object> object) 4432 { 4433 return $returnValue; 4434 } 4435 4436 END 4437 } 4438 4439 if (InheritsInterface($interface, "EventTarget")) { 4440 $implementation{nameSpaceWebCore}->add(<<END); 4441 EventTarget* ${v8ClassName}::toEventTarget(v8::Handle<v8::Object> object) 4442 { 4443 return toNative(object); 4444 } 4445 4446 END 4447 } 4448 4449 if ($interfaceName eq "Window") { 4450 $implementation{nameSpaceWebCore}->add(<<END); 4451 v8::Handle<v8::ObjectTemplate> V8Window::GetShadowObjectTemplate(v8::Isolate* isolate, WrapperWorldType currentWorldType) 4452 { 4453 if (currentWorldType == MainWorld) { 4454 DEFINE_STATIC_LOCAL(v8::Persistent<v8::ObjectTemplate>, V8WindowShadowObjectCacheForMainWorld, ()); 4455 if (V8WindowShadowObjectCacheForMainWorld.IsEmpty()) { 4456 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "BuildDOMTemplate"); 4457 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 4458 ConfigureShadowObjectTemplate(templ, isolate, currentWorldType); 4459 V8WindowShadowObjectCacheForMainWorld.Reset(isolate, templ); 4460 return templ; 4461 } 4462 return v8::Local<v8::ObjectTemplate>::New(isolate, V8WindowShadowObjectCacheForMainWorld); 4463 } else { 4464 DEFINE_STATIC_LOCAL(v8::Persistent<v8::ObjectTemplate>, V8WindowShadowObjectCacheForNonMainWorld, ()); 4465 if (V8WindowShadowObjectCacheForNonMainWorld.IsEmpty()) { 4466 TRACE_EVENT_SCOPED_SAMPLING_STATE("Blink", "BuildDOMTemplate"); 4467 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 4468 ConfigureShadowObjectTemplate(templ, isolate, currentWorldType); 4469 V8WindowShadowObjectCacheForNonMainWorld.Reset(isolate, templ); 4470 return templ; 4471 } 4472 return v8::Local<v8::ObjectTemplate>::New(isolate, V8WindowShadowObjectCacheForNonMainWorld); 4473 } 4474 } 4475 4476 END 4477 } 4478 4479 GenerateToV8Converters($interface, $v8ClassName, $nativeType); 4480 4481 $implementation{nameSpaceWebCore}->add(<<END); 4482 void ${v8ClassName}::derefObject(void* object) 4483 { 4484 fromInternalPointer(object)->deref(); 4485 } 4486 4487 END 4488 } 4489 4490 sub GenerateHeaderContentHeader 4491 { 4492 my $interface = shift; 4493 my $v8ClassName = GetV8ClassName($interface); 4494 my $conditionalString = GenerateConditionalString($interface); 4495 4496 my @headerContentHeader = split("\r", $headerTemplate); 4497 4498 push(@headerContentHeader, "\n#ifndef ${v8ClassName}" . "_h\n"); 4499 push(@headerContentHeader, "#define ${v8ClassName}" . "_h\n\n"); 4500 push(@headerContentHeader, "#if ${conditionalString}\n") if $conditionalString; 4501 return join "", @headerContentHeader; 4502 } 4503 4504 sub GenerateCallbackHeader 4505 { 4506 my $object = shift; 4507 my $interface = shift; 4508 4509 my $interfaceName = $interface->name; 4510 my $implClassName = GetImplName($interface); 4511 my $v8ClassName = GetV8ClassName($interface); 4512 4513 $header{root}->addFooter("\n"); 4514 4515 my @includes = (); 4516 push(@includes, "bindings/v8/ActiveDOMCallback.h"); 4517 push(@includes, "bindings/v8/DOMWrapperWorld.h"); 4518 push(@includes, "bindings/v8/ScopedPersistent.h"); 4519 push(@includes, HeaderFilesForInterface($interfaceName, $implClassName)); 4520 for my $include (sort @includes) { 4521 $header{includes}->add("#include \"$include\"\n"); 4522 } 4523 $header{nameSpaceWebCore}->addHeader("\nclass ScriptExecutionContext;\n\n"); 4524 $header{class}->addHeader("class $v8ClassName : public $implClassName, public ActiveDOMCallback {"); 4525 $header{class}->addFooter("};\n"); 4526 4527 $header{classPublic}->add(<<END); 4528 static PassRefPtr<${v8ClassName}> create(v8::Handle<v8::Value> value, ScriptExecutionContext* context) 4529 { 4530 ASSERT(value->IsObject()); 4531 ASSERT(context); 4532 return adoptRef(new ${v8ClassName}(v8::Handle<v8::Object>::Cast(value), context)); 4533 } 4534 4535 virtual ~${v8ClassName}(); 4536 4537 END 4538 4539 # Functions 4540 my $numFunctions = @{$interface->functions}; 4541 if ($numFunctions > 0) { 4542 $header{classPublic}->add(" // Functions\n"); 4543 foreach my $function (@{$interface->functions}) { 4544 my $code = " virtual " . GetNativeTypeForCallbacks($function->type) . " " . $function->name . "("; 4545 4546 my @args = (); 4547 if (ExtendedAttributeContains($function->extendedAttributes->{"CallWith"}, "ThisValue")) { 4548 push(@args, GetNativeType("any") . " thisValue"); 4549 } 4550 my @params = @{$function->parameters}; 4551 foreach my $param (@params) { 4552 push(@args, GetNativeTypeForCallbacks($param->type) . " " . $param->name); 4553 } 4554 $code .= join(", ", @args); 4555 $code .= ");\n"; 4556 $header{classPublic}->add($code); 4557 } 4558 } 4559 4560 $header{classPublic}->add(<<END); 4561 4562 virtual ScriptExecutionContext* scriptExecutionContext() const { return ContextLifecycleObserver::scriptExecutionContext(); } 4563 4564 END 4565 $header{classPrivate}->add(<<END); 4566 ${v8ClassName}(v8::Handle<v8::Object>, ScriptExecutionContext*); 4567 4568 ScopedPersistent<v8::Object> m_callback; 4569 RefPtr<DOMWrapperWorld> m_world; 4570 END 4571 } 4572 4573 sub GenerateCallbackImplementation 4574 { 4575 my $object = shift; 4576 my $interface = shift; 4577 my $v8ClassName = GetV8ClassName($interface); 4578 4579 AddToImplIncludes("core/dom/ScriptExecutionContext.h"); 4580 AddToImplIncludes("bindings/v8/V8Binding.h"); 4581 AddToImplIncludes("bindings/v8/V8Callback.h"); 4582 AddToImplIncludes("wtf/Assertions.h"); 4583 4584 $implementation{nameSpaceWebCore}->add(<<END); 4585 ${v8ClassName}::${v8ClassName}(v8::Handle<v8::Object> callback, ScriptExecutionContext* context) 4586 : ActiveDOMCallback(context) 4587 , m_callback(callback) 4588 , m_world(DOMWrapperWorld::current()) 4589 { 4590 } 4591 4592 END 4593 4594 $implementation{nameSpaceWebCore}->add(<<END); 4595 ${v8ClassName}::~${v8ClassName}() 4596 { 4597 } 4598 4599 END 4600 4601 # Functions 4602 my $numFunctions = @{$interface->functions}; 4603 if ($numFunctions > 0) { 4604 $implementation{nameSpaceWebCore}->add("// Functions\n"); 4605 foreach my $function (@{$interface->functions}) { 4606 my $code = ""; 4607 my @params = @{$function->parameters}; 4608 next if $function->extendedAttributes->{"Custom"}; 4609 4610 AddIncludesForType($function->type); 4611 die "We don't yet support callbacks that return non-boolean values.\n" if $function->type ne "boolean"; 4612 $code .= "\n" . GetNativeTypeForCallbacks($function->type) . " ${v8ClassName}::" . $function->name . "("; 4613 my $callWithThisValue = ExtendedAttributeContains($function->extendedAttributes->{"CallWith"}, "ThisValue"); 4614 4615 my @args = (); 4616 if ($callWithThisValue) { 4617 push(@args, GetNativeTypeForCallbacks("any") . " thisValue"); 4618 } 4619 foreach my $param (@params) { 4620 my $paramName = $param->name; 4621 my $type = $param->type; 4622 my $arrayOrSequenceType = GetArrayOrSequenceType($type); 4623 4624 if ($arrayOrSequenceType) { 4625 if (IsRefPtrType($arrayOrSequenceType)) { 4626 AddIncludesForType($arrayOrSequenceType); 4627 } 4628 } else { 4629 AddIncludesForType($type); 4630 } 4631 4632 push(@args, GetNativeTypeForCallbacks($type) . " " . $paramName); 4633 } 4634 $code .= join(", ", @args); 4635 4636 $code .= ")\n"; 4637 $code .= "{\n"; 4638 $code .= " if (!canInvokeCallback())\n"; 4639 $code .= " return true;\n\n"; 4640 $code .= " v8::Isolate* isolate = v8::Isolate::GetCurrent();\n"; 4641 $code .= " v8::HandleScope handleScope(isolate);\n\n"; 4642 $code .= " v8::Handle<v8::Context> v8Context = toV8Context(scriptExecutionContext(), m_world.get());\n"; 4643 $code .= " if (v8Context.IsEmpty())\n"; 4644 $code .= " return true;\n\n"; 4645 $code .= " v8::Context::Scope scope(v8Context);\n\n"; 4646 4647 my $thisObjectHandle = ""; 4648 if ($callWithThisValue) { 4649 $code .= " v8::Handle<v8::Value> thisHandle = thisValue.v8Value();\n"; 4650 $code .= " if (thisHandle.IsEmpty()) {\n"; 4651 $code .= " if (!isScriptControllerTerminating())\n"; 4652 $code .= " CRASH();\n"; 4653 $code .= " return true;\n"; 4654 $code .= " }\n"; 4655 $code .= " ASSERT(thisHandle->isObject());\n"; 4656 $thisObjectHandle = "v8::Handle<v8::Object>::Cast(thisHandle), "; 4657 } 4658 @args = (); 4659 foreach my $param (@params) { 4660 my $paramName = $param->name; 4661 $code .= NativeToJSValue($param->type, $param->extendedAttributes, $paramName, " ", "v8::Handle<v8::Value> ${paramName}Handle =", "v8::Handle<v8::Object>()", "isolate", "") . "\n"; 4662 $code .= " if (${paramName}Handle.IsEmpty()) {\n"; 4663 $code .= " if (!isScriptControllerTerminating())\n"; 4664 $code .= " CRASH();\n"; 4665 $code .= " return true;\n"; 4666 $code .= " }\n"; 4667 push(@args, " ${paramName}Handle"); 4668 } 4669 4670 if (scalar(@args) > 0) { 4671 $code .= "\n v8::Handle<v8::Value> argv[] = {\n"; 4672 $code .= join(",\n", @args); 4673 $code .= "\n };\n\n"; 4674 } else { 4675 $code .= "\n v8::Handle<v8::Value> *argv = 0;\n\n"; 4676 } 4677 $code .= " bool callbackReturnValue = false;\n"; 4678 $code .= " return !invokeCallback(m_callback.newLocal(isolate), ${thisObjectHandle}" . scalar(@args) . ", argv, callbackReturnValue, scriptExecutionContext());\n"; 4679 $code .= "}\n"; 4680 $implementation{nameSpaceWebCore}->add($code); 4681 } 4682 } 4683 } 4684 4685 sub BaseInterfaceName 4686 { 4687 my $interface = shift; 4688 4689 while ($interface->parent) { 4690 $interface = ParseInterface($interface->parent); 4691 } 4692 4693 return $interface->name; 4694 } 4695 4696 sub GenerateToV8Converters 4697 { 4698 my $interface = shift; 4699 my $v8ClassName = shift; 4700 my $nativeType = shift; 4701 my $interfaceName = $interface->name; 4702 4703 if ($interface->extendedAttributes->{"DoNotGenerateWrap"} || $interface->extendedAttributes->{"DoNotGenerateToV8"}) { 4704 return; 4705 } 4706 4707 AddToImplIncludes("bindings/v8/ScriptController.h"); 4708 AddToImplIncludes("core/page/Frame.h"); 4709 4710 my $createWrapperArgumentType = GetPassRefPtrType($nativeType); 4711 my $baseType = BaseInterfaceName($interface); 4712 4713 # FIXME: Do we really need to treat "GenerateIsReachable", "CustomIsReachable" and /SVG/ 4714 # as dependent DOM objects? 4715 my $wrapperConfiguration = "WrapperConfiguration::Independent"; 4716 if (InheritsExtendedAttribute($interface, "ActiveDOMObject") 4717 || InheritsExtendedAttribute($interface, "DependentLifetime") 4718 || InheritsExtendedAttribute($interface, "GenerateIsReachable") 4719 || InheritsExtendedAttribute($interface, "CustomIsReachable") 4720 || $v8ClassName =~ /SVG/) { 4721 $wrapperConfiguration = "WrapperConfiguration::Dependent"; 4722 } 4723 4724 my $code = ""; 4725 $code .= <<END; 4726 4727 v8::Handle<v8::Object> ${v8ClassName}::createWrapper(${createWrapperArgumentType} impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 4728 { 4729 ASSERT(impl.get()); 4730 ASSERT(DOMDataStore::getWrapper<${v8ClassName}>(impl.get(), isolate).IsEmpty()); 4731 if (ScriptWrappable::wrapperCanBeStoredInObject(impl.get())) { 4732 const WrapperTypeInfo* actualInfo = ScriptWrappable::getTypeInfoFromObject(impl.get()); 4733 // Might be a XXXConstructor::info instead of an XXX::info. These will both have 4734 // the same object de-ref functions, though, so use that as the basis of the check. 4735 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(actualInfo->derefObjectFunction == info.derefObjectFunction); 4736 } 4737 4738 END 4739 4740 $code .= <<END if ($baseType ne $interfaceName); 4741 END 4742 4743 if (InheritsInterface($interface, "Document")) { 4744 $code .= <<END; 4745 if (Frame* frame = impl->frame()) { 4746 if (frame->script()->initializeMainWorld()) { 4747 // initializeMainWorld may have created a wrapper for the object, retry from the start. 4748 v8::Handle<v8::Object> wrapper = DOMDataStore::getWrapper<${v8ClassName}>(impl.get(), isolate); 4749 if (!wrapper.IsEmpty()) 4750 return wrapper; 4751 } 4752 } 4753 END 4754 } 4755 4756 $code .= <<END; 4757 4758 v8::Handle<v8::Object> wrapper = V8DOMWrapper::createWrapper(creationContext, &info, toInternalPointer(impl.get()), isolate); 4759 if (UNLIKELY(wrapper.IsEmpty())) 4760 return wrapper; 4761 END 4762 if (IsTypedArrayType($interface->name)) { 4763 AddToImplIncludes("bindings/v8/custom/V8ArrayBufferCustom.h"); 4764 $code .= <<END; 4765 if (!impl->buffer()->hasDeallocationObserver()) { 4766 v8::V8::AdjustAmountOfExternalAllocatedMemory(impl->buffer()->byteLength()); 4767 impl->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance()); 4768 } 4769 END 4770 } 4771 4772 $code .= <<END; 4773 installPerContextProperties(wrapper, impl.get(), isolate); 4774 V8DOMWrapper::associateObjectWithWrapper<$v8ClassName>(impl, &info, wrapper, isolate, $wrapperConfiguration); 4775 return wrapper; 4776 } 4777 END 4778 $implementation{nameSpaceWebCore}->add($code); 4779 } 4780 4781 sub GenerateSecurityCheckFunctions 4782 { 4783 my $interface = shift; 4784 my $implClassName = GetImplName($interface); 4785 my $v8ClassName = GetV8ClassName($interface); 4786 4787 AddToImplIncludes("bindings/v8/BindingSecurity.h"); 4788 $implementation{nameSpaceInternal}->add(<<END); 4789 bool indexedSecurityCheck(v8::Local<v8::Object> host, uint32_t index, v8::AccessType type, v8::Local<v8::Value>) 4790 { 4791 $implClassName* imp = ${v8ClassName}::toNative(host); 4792 return BindingSecurity::shouldAllowAccessToFrame(imp->frame(), DoNotReportSecurityError); 4793 } 4794 4795 END 4796 $implementation{nameSpaceInternal}->add(<<END); 4797 bool namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::Value> key, v8::AccessType type, v8::Local<v8::Value>) 4798 { 4799 $implClassName* imp = ${v8ClassName}::toNative(host); 4800 return BindingSecurity::shouldAllowAccessToFrame(imp->frame(), DoNotReportSecurityError); 4801 } 4802 4803 END 4804 } 4805 4806 sub GetNativeTypeForConversions 4807 { 4808 my $interface = shift; 4809 my $implClassName = GetImplName($interface); 4810 $implClassName = GetSVGTypeNeedingTearOff($interface->name) if IsSVGTypeNeedingTearOff($interface->name); 4811 return $implClassName; 4812 } 4813 4814 sub GetNamespaceForInterface 4815 { 4816 my $interface = shift; 4817 return "WTF" if IsTypedArrayType($interface->name); 4818 return "WebCore"; 4819 } 4820 4821 sub GenerateFunctionCallString 4822 { 4823 my $function = shift; 4824 my $numberOfParameters = shift; 4825 my $indent = shift; 4826 my $interface = shift; 4827 my $forMainWorldSuffix = shift; 4828 my %replacements = @_; 4829 4830 my $interfaceName = $interface->name; 4831 my $implClassName = GetImplName($interface); 4832 my $name = GetImplName($function); 4833 my $returnType = $function->type; 4834 my $nativeReturnType = GetNativeType($returnType, {}, ""); 4835 my $code = ""; 4836 4837 my $isSVGTearOffType = (IsSVGTypeNeedingTearOff($returnType) and not $interfaceName =~ /List$/); 4838 $nativeReturnType = GetSVGWrappedTypeNeedingTearOff($returnType) if $isSVGTearOffType; 4839 4840 my $index = 0; 4841 4842 my @arguments; 4843 my $functionName; 4844 my $implementedBy = $function->extendedAttributes->{"ImplementedBy"}; 4845 if ($implementedBy) { 4846 my $implementedByImplName = GetImplNameFromImplementedBy($implementedBy); 4847 AddToImplIncludes(HeaderFilesForInterface($implementedBy, $implementedByImplName)); 4848 unshift(@arguments, "imp") if !$function->isStatic; 4849 $functionName = "${implementedByImplName}::${name}"; 4850 } elsif ($function->isStatic) { 4851 $functionName = "${implClassName}::${name}"; 4852 } else { 4853 $functionName = "imp->${name}"; 4854 } 4855 4856 my $callWith = $function->extendedAttributes->{"CallWith"}; 4857 my ($callWithArgs, $subCode) = GenerateCallWith($callWith, $indent, 1, $function); 4858 $code .= $subCode; 4859 unshift(@arguments, @$callWithArgs); 4860 $index += @$callWithArgs; 4861 $numberOfParameters += @$callWithArgs; 4862 4863 foreach my $parameter (@{$function->parameters}) { 4864 if ($index eq $numberOfParameters) { 4865 last; 4866 } 4867 my $paramName = $parameter->name; 4868 my $paramType = $parameter->type; 4869 4870 if ($replacements{$paramName}) { 4871 push @arguments, $replacements{$paramName}; 4872 } elsif ($parameter->type eq "NodeFilter" || $parameter->type eq "XPathNSResolver") { 4873 push @arguments, "$paramName.get()"; 4874 } elsif (IsSVGTypeNeedingTearOff($parameter->type) and not $interfaceName =~ /List$/) { 4875 AddToImplIncludes("core/dom/ExceptionCode.h"); 4876 push @arguments, "$paramName->propertyReference()"; 4877 $code .= $indent . "if (!$paramName) {\n"; 4878 $code .= $indent . " setDOMException(WebCore::TypeMismatchError, args.GetIsolate());\n"; 4879 $code .= $indent . " return;\n"; 4880 $code .= $indent . "}\n"; 4881 } elsif ($parameter->type eq "SVGMatrix" and $interfaceName eq "SVGTransformList") { 4882 push @arguments, "$paramName.get()"; 4883 } else { 4884 push @arguments, $paramName; 4885 } 4886 $index++; 4887 } 4888 4889 if ($function->extendedAttributes->{"RaisesException"}) { 4890 push @arguments, "es"; 4891 } 4892 4893 my $functionString = "$functionName(" . join(", ", @arguments) . ")"; 4894 4895 my $return = "result"; 4896 my $returnIsRef = IsRefPtrType($returnType); 4897 4898 if ($returnType eq "void") { 4899 $code .= $indent . "$functionString;\n"; 4900 } elsif (ExtendedAttributeContains($callWith, "ScriptState") or $function->extendedAttributes->{"RaisesException"}) { 4901 $code .= $indent . $nativeReturnType . " result = $functionString;\n"; 4902 } else { 4903 # Can inline the function call into the return statement to avoid overhead of using a Ref<> temporary 4904 $return = $functionString; 4905 $returnIsRef = 0; 4906 4907 if ($interfaceName eq "SVGTransformList" and IsRefPtrType($returnType)) { 4908 $return = "WTF::getPtr(" . $return . ")"; 4909 } 4910 } 4911 4912 if ($function->extendedAttributes->{"RaisesException"}) { 4913 $code .= $indent . "if (es.throwIfNeeded())\n"; 4914 $code .= $indent . " return;\n"; 4915 } 4916 4917 if (ExtendedAttributeContains($callWith, "ScriptState")) { 4918 $code .= $indent . "if (state.hadException()) {\n"; 4919 $code .= $indent . " v8::Local<v8::Value> exception = state.exception();\n"; 4920 $code .= $indent . " state.clearException();\n"; 4921 $code .= $indent . " throwError(exception);\n"; 4922 $code .= $indent . " return;\n"; 4923 $code .= $indent . "}\n"; 4924 } 4925 4926 if ($isSVGTearOffType) { 4927 AddToImplIncludes("V8$returnType.h"); 4928 AddToImplIncludes("core/svg/properties/SVGPropertyTearOff.h"); 4929 my $svgNativeType = GetSVGTypeNeedingTearOff($returnType); 4930 # FIXME: Update for all ScriptWrappables. 4931 if (IsDOMNodeType($interfaceName)) { 4932 if ($forMainWorldSuffix eq "ForMainWorld") { 4933 $code .= $indent . "v8SetReturnValue(args, toV8ForMainWorld(WTF::getPtr(${svgNativeType}::create($return)), args.Holder(), args.GetIsolate()));\n"; 4934 } else { 4935 $code .= $indent . "v8SetReturnValue(args, toV8Fast(WTF::getPtr(${svgNativeType}::create($return)), args, imp));\n"; 4936 } 4937 } else { 4938 $code .= $indent . "v8SetReturnValue(args, toV8${forMainWorldSuffix}(WTF::getPtr(${svgNativeType}::create($return)), args.Holder(), args.GetIsolate()));\n"; 4939 } 4940 $code .= $indent . "return;\n"; 4941 return $code; 4942 } 4943 4944 # If the implementing class is a POD type, commit changes 4945 if (IsSVGTypeNeedingTearOff($interfaceName) and not $interfaceName =~ /List$/) { 4946 $code .= $indent . "wrapper->commitChange();\n"; 4947 } 4948 4949 $return .= ".release()" if ($returnIsRef); 4950 4951 my $nativeValue; 4952 # FIXME: Update for all ScriptWrappables. 4953 if (IsDOMNodeType($interfaceName)) { 4954 $nativeValue = NativeToJSValue($function->type, $function->extendedAttributes, $return, $indent, "", "args.Holder()", "args.GetIsolate()", "args", "imp", $forMainWorldSuffix, "return"); 4955 } else { 4956 $nativeValue = NativeToJSValue($function->type, $function->extendedAttributes, $return, $indent, "", "args.Holder()", "args.GetIsolate()", "args", 0, $forMainWorldSuffix, "return"); 4957 } 4958 4959 $code .= $nativeValue . "\n"; 4960 $code .= $indent . "return;\n"; 4961 4962 return $code; 4963 } 4964 4965 sub GetNativeType 4966 { 4967 my $type = shift; 4968 my $extendedAttributes = shift; 4969 my $isParameter = shift; 4970 4971 my $svgNativeType = GetSVGTypeNeedingTearOff($type); 4972 if ($svgNativeType) { 4973 if ($svgNativeType =~ /List$/) { 4974 return "${svgNativeType}*"; 4975 } else { 4976 return "RefPtr<${svgNativeType} >"; 4977 } 4978 } 4979 4980 return "float" if $type eq "float"; 4981 return "double" if $type eq "double"; 4982 return "int" if $type eq "long" or $type eq "int" or $type eq "short" or $type eq "byte"; 4983 if ($type eq "unsigned long" or $type eq "unsigned int" or $type eq "unsigned short" or $type eq "octet") { 4984 if ($extendedAttributes->{"IsIndex"}) { 4985 # Special-case index arguments because we need to check that they aren't < 0. 4986 return "int"; 4987 } 4988 return "unsigned"; 4989 } 4990 return "long long" if $type eq "long long"; 4991 return "unsigned long long" if $type eq "unsigned long long"; 4992 return "bool" if $type eq "boolean"; 4993 4994 if (($type eq "DOMString" || IsEnumType($type)) and $isParameter) { 4995 # FIXME: This implements [TreatNullAs=NullString] and [TreatUndefinedAs=NullString], 4996 # but the Web IDL spec requires [TreatNullAs=EmptyString] and [TreatUndefinedAs=EmptyString]. 4997 my $mode = ""; 4998 if (($extendedAttributes->{"TreatNullAs"} and $extendedAttributes->{"TreatNullAs"} eq "NullString") and ($extendedAttributes->{"TreatUndefinedAs"} and $extendedAttributes->{"TreatUndefinedAs"} eq "NullString")) { 4999 $mode = "WithUndefinedOrNullCheck"; 5000 } elsif (($extendedAttributes->{"TreatNullAs"} and $extendedAttributes->{"TreatNullAs"} eq "NullString") or $extendedAttributes->{"Reflect"}) { 5001 $mode = "WithNullCheck"; 5002 } 5003 # FIXME: Add the case for 'elsif ($attributeOrParameter->extendedAttributes->{"TreatUndefinedAs"} and $attributeOrParameter->extendedAttributes->{"TreatUndefinedAs"} eq "NullString"))'. 5004 return "V8StringResource<$mode>"; 5005 } 5006 5007 return "String" if $type eq "DOMString" or IsEnumType($type); 5008 5009 return "Range::CompareHow" if $type eq "CompareHow"; 5010 return "DOMTimeStamp" if $type eq "DOMTimeStamp"; 5011 return "double" if $type eq "Date"; 5012 return "ScriptValue" if $type eq "any" or IsCallbackFunctionType($type); 5013 return "Dictionary" if $type eq "Dictionary"; 5014 5015 return "RefPtr<DOMStringList>" if $type eq "DOMStringList"; 5016 return "RefPtr<MediaQueryListListener>" if $type eq "MediaQueryListListener"; 5017 return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; 5018 return "RefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue"; 5019 return "RefPtr<XPathNSResolver>" if $type eq "XPathNSResolver"; 5020 5021 die "UnionType is not supported" if IsUnionType($type); 5022 5023 if (IsTypedArrayType($type)) { 5024 return $isParameter ? "${type}*" : "RefPtr<${type}>"; 5025 } 5026 5027 # We need to check [ImplementedAs] extended attribute for wrapper types. 5028 if (IsWrapperType($type)) { 5029 my $interface = ParseInterface($type); 5030 my $implClassName = GetImplName($interface); 5031 return $isParameter ? "${implClassName}*" : "RefPtr<${implClassName}>"; 5032 } 5033 return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; 5034 5035 my $arrayOrSequenceType = GetArrayOrSequenceType($type); 5036 5037 if ($arrayOrSequenceType) { 5038 my $nativeType = GetNativeType($arrayOrSequenceType); 5039 $nativeType .= " " if ($nativeType =~ />$/); 5040 return "Vector<${nativeType}>"; 5041 } 5042 5043 # Default, assume native type is a pointer with same type name as idl type 5044 return "${type}*"; 5045 } 5046 5047 sub GetNativeTypeForCallbacks 5048 { 5049 my $type = shift; 5050 return "const String&" if $type eq "DOMString"; 5051 return "PassRefPtr<SerializedScriptValue>" if $type eq "SerializedScriptValue"; 5052 5053 # Callbacks use raw pointers, so pass isParameter = 1 5054 return GetNativeType($type, {}, "parameter"); 5055 } 5056 5057 sub JSValueToNativeStatement 5058 { 5059 my $type = shift; 5060 my $extendedAttributes = shift; 5061 my $jsValue = shift; 5062 my $variableName = shift; 5063 my $indent = shift; 5064 my $getIsolate = shift; 5065 5066 my $nativeType = GetNativeType($type, $extendedAttributes, "parameter"); 5067 if ($type eq "unsigned long" and $extendedAttributes->{"IsIndex"}) { 5068 # Special-case index arguments because we need to check that they aren't < 0. 5069 $nativeType = "int"; 5070 } 5071 my $native_value = JSValueToNative($type, $extendedAttributes, $jsValue, $getIsolate); 5072 my $code = ""; 5073 if ($type eq "DOMString" || IsEnumType($type)) { 5074 die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8StringResource/; 5075 if ($type eq "DOMString" or IsEnumType($type)) { 5076 $code .= $indent . "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID($nativeType, $variableName, $native_value);\n" 5077 } else { 5078 $code .= $indent . "$nativeType $variableName($native_value, true);\n"; 5079 } 5080 } elsif ($extendedAttributes->{"EnforceRange"}) { 5081 $code .= $indent . "V8TRYCATCH_WITH_TYPECHECK_VOID($nativeType, $variableName, $native_value, $getIsolate);\n"; 5082 } else { 5083 $code .= $indent . "V8TRYCATCH_VOID($nativeType, $variableName, $native_value);\n"; 5084 } 5085 return $code; 5086 } 5087 5088 5089 sub JSValueToNative 5090 { 5091 my $type = shift; 5092 my $extendedAttributes = shift; 5093 my $value = shift; 5094 my $getIsolate = shift; 5095 5096 my $intConversion = $extendedAttributes->{"EnforceRange"} ? "EnforceRange" : "NormalConversion"; 5097 5098 return "$value->BooleanValue()" if $type eq "boolean"; 5099 return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double"; 5100 5101 if ($intConversion ne "NormalConversion") { 5102 return "toInt8($value, $intConversion, ok)" if $type eq "byte"; 5103 return "toUInt8($value, $intConversion, ok)" if $type eq "octet"; 5104 return "toInt32($value, $intConversion, ok)" if $type eq "long" or $type eq "short"; 5105 return "toUInt32($value, $intConversion, ok)" if $type eq "unsigned long" or $type eq "unsigned short"; 5106 return "toInt64($value, $intConversion, ok)" if $type eq "long long"; 5107 return "toUInt64($value, $intConversion, ok)" if $type eq "unsigned long long"; 5108 } else { 5109 return "toInt8($value)" if $type eq "byte"; 5110 return "toUInt8($value)" if $type eq "octet"; 5111 return "toInt32($value)" if $type eq "long" or $type eq "short"; 5112 return "toUInt32($value)" if $type eq "unsigned long" or $type eq "unsigned short"; 5113 return "toInt64($value)" if $type eq "long long"; 5114 return "toUInt64($value)" if $type eq "unsigned long long"; 5115 } 5116 return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; 5117 return "toWebCoreDate($value)" if $type eq "Date"; 5118 return "toDOMStringList($value, $getIsolate)" if $type eq "DOMStringList"; 5119 5120 if ($type eq "DOMString" or IsEnumType($type)) { 5121 return $value; 5122 } 5123 5124 if ($type eq "SerializedScriptValue") { 5125 AddToImplIncludes("bindings/v8/SerializedScriptValue.h"); 5126 return "SerializedScriptValue::create($value, $getIsolate)"; 5127 } 5128 5129 if ($type eq "Dictionary") { 5130 AddToImplIncludes("bindings/v8/Dictionary.h"); 5131 return "Dictionary($value, $getIsolate)"; 5132 } 5133 5134 if ($type eq "any" || IsCallbackFunctionType($type)) { 5135 AddToImplIncludes("bindings/v8/ScriptValue.h"); 5136 return "ScriptValue($value)"; 5137 } 5138 5139 if ($type eq "NodeFilter") { 5140 return "toNodeFilter($value, $getIsolate)"; 5141 } 5142 5143 if ($type eq "MediaQueryListListener") { 5144 AddToImplIncludes("core/css/MediaQueryListListener.h"); 5145 return "MediaQueryListListener::create(" . $value . ")"; 5146 } 5147 5148 if ($type eq "EventTarget") { 5149 return "V8DOMWrapper::isDOMWrapper($value) ? toWrapperTypeInfo(v8::Handle<v8::Object>::Cast($value))->toEventTarget(v8::Handle<v8::Object>::Cast($value)) : 0"; 5150 } 5151 5152 if (IsTypedArrayType($type)) { 5153 AddIncludesForType($type); 5154 return "$value->Is${type}() ? V8${type}::toNative(v8::Handle<v8::${type}>::Cast($value)) : 0" 5155 } 5156 5157 if ($type eq "XPathNSResolver") { 5158 return "toXPathNSResolver($value, $getIsolate)"; 5159 } 5160 5161 my $arrayOrSequenceType = GetArrayOrSequenceType($type); 5162 5163 if ($arrayOrSequenceType) { 5164 if (IsRefPtrType($arrayOrSequenceType)) { 5165 AddToImplIncludes("V8${arrayOrSequenceType}.h"); 5166 return "(toRefPtrNativeArray<${arrayOrSequenceType}, V8${arrayOrSequenceType}>($value, $getIsolate))"; 5167 } 5168 return "toNativeArray<" . GetNativeType($arrayOrSequenceType) . ">($value, $getIsolate)"; 5169 } 5170 5171 AddIncludesForType($type); 5172 5173 AddToImplIncludes("V8${type}.h"); 5174 return "V8${type}::HasInstance($value, $getIsolate, worldType($getIsolate)) ? V8${type}::toNative(v8::Handle<v8::Object>::Cast($value)) : 0"; 5175 } 5176 5177 sub CreateCustomSignature 5178 { 5179 my $function = shift; 5180 my $count = @{$function->parameters}; 5181 my $name = $function->name; 5182 my $code = " const int ${name}Argc = ${count};\n" . 5183 " v8::Handle<v8::FunctionTemplate> ${name}Argv[${name}Argc] = { "; 5184 my $first = 1; 5185 foreach my $parameter (@{$function->parameters}) { 5186 if ($first) { $first = 0; } 5187 else { $code .= ", "; } 5188 if (IsWrapperType($parameter->type) && not IsTypedArrayType($parameter->type)) { 5189 if ($parameter->type eq "XPathNSResolver") { 5190 # Special case for XPathNSResolver. All other browsers accepts a callable, 5191 # so, even though it's against IDL, accept objects here. 5192 $code .= "v8::Handle<v8::FunctionTemplate>()"; 5193 } else { 5194 my $type = $parameter->type; 5195 my $arrayOrSequenceType = GetArrayOrSequenceType($type); 5196 5197 if ($arrayOrSequenceType) { 5198 if (IsRefPtrType($arrayOrSequenceType)) { 5199 AddIncludesForType($arrayOrSequenceType); 5200 } else { 5201 $code .= "v8::Handle<v8::FunctionTemplate>()"; 5202 next; 5203 } 5204 } else { 5205 AddIncludesForType($type); 5206 } 5207 $code .= "V8PerIsolateData::from(isolate)->rawTemplate(&V8${type}::info, currentWorldType)"; 5208 } 5209 } else { 5210 $code .= "v8::Handle<v8::FunctionTemplate>()"; 5211 } 5212 } 5213 $code .= " };\n"; 5214 $code .= " v8::Handle<v8::Signature> ${name}Signature = v8::Signature::New(desc, ${name}Argc, ${name}Argv);\n"; 5215 return $code; 5216 } 5217 5218 5219 sub RequiresCustomSignature 5220 { 5221 my $function = shift; 5222 # No signature needed for Custom function 5223 if (HasCustomMethod($function->extendedAttributes)) { 5224 return 0; 5225 } 5226 # No signature needed for overloaded function 5227 if (@{$function->{overloads}} > 1) { 5228 return 0; 5229 } 5230 if ($function->isStatic) { 5231 return 0; 5232 } 5233 # Type checking is performed in the generated code 5234 if ($function->extendedAttributes->{"StrictTypeChecking"}) { 5235 return 0; 5236 } 5237 foreach my $parameter (@{$function->parameters}) { 5238 if (($parameter->isOptional && !$parameter->extendedAttributes->{"Default"}) || IsCallbackInterface($parameter->type)) { 5239 return 0; 5240 } 5241 } 5242 5243 foreach my $parameter (@{$function->parameters}) { 5244 if (IsWrapperType($parameter->type)) { 5245 return 1; 5246 } 5247 } 5248 return 0; 5249 } 5250 5251 sub IsUnionType 5252 { 5253 my $type = shift; # string or UnionType 5254 if(ref($type) eq "UnionType") { 5255 die "Currently only 2 values of non-union type is supported as union type.\n" unless @{$type->unionMemberTypes} == 2; 5256 return 1; 5257 } 5258 return 0; 5259 } 5260 5261 sub IsWrapperType 5262 { 5263 my $type = shift; 5264 return 0 if GetArrayType($type); 5265 return 0 if GetSequenceType($type); 5266 return 0 if IsCallbackFunctionType($type); 5267 return 0 if IsEnumType($type); 5268 return 0 if IsPrimitiveType($type); 5269 return 0 if $type eq "DOMString"; 5270 return !$nonWrapperTypes{$type}; 5271 } 5272 5273 sub IsCallbackInterface 5274 { 5275 my $type = shift; 5276 return 0 unless IsWrapperType($type); 5277 return 0 if IsTypedArrayType($type); 5278 5279 my $idlFile = IDLFileForInterface($type) 5280 or die("Could NOT find IDL file for interface \"$type\"!\n"); 5281 5282 open FILE, "<", $idlFile; 5283 my @lines = <FILE>; 5284 close FILE; 5285 5286 my $fileContents = join('', @lines); 5287 return ($fileContents =~ /callback\s+interface\s+(\w+)/gs); 5288 } 5289 5290 sub GetNativeTypeOfTypedArray 5291 { 5292 my $interface = shift; 5293 my $interfaceName = $interface->name; 5294 die "TypedArray of unknown type is found" unless $typedArrayHash{$interface->name}; 5295 return @{$typedArrayHash{$interface->name}}; 5296 } 5297 5298 sub IsDOMNodeType 5299 { 5300 my $type = shift; 5301 5302 return 1 if $type eq 'Attr'; 5303 return 1 if $type eq 'CDATASection'; 5304 return 1 if $type eq 'CharacterData'; 5305 return 1 if $type eq 'Comment'; 5306 return 1 if $type eq 'Document'; 5307 return 1 if $type eq 'DocumentFragment'; 5308 return 1 if $type eq 'DocumentType'; 5309 return 1 if $type eq 'Element'; 5310 return 1 if $type eq 'Entity'; 5311 return 1 if $type eq 'HTMLDocument'; 5312 return 1 if $type eq 'Node'; 5313 return 1 if $type eq 'Notation'; 5314 return 1 if $type eq 'ProcessingInstruction'; 5315 return 1 if $type eq 'ShadowRoot'; 5316 return 1 if $type eq 'SVGDocument'; 5317 return 1 if $type eq 'Text'; 5318 5319 return 1 if $type =~ /^HTML.*Element$/; 5320 return 1 if $type =~ /^SVG.*Element$/; 5321 5322 return 1 if $type eq 'TestNode'; 5323 5324 return 0; 5325 } 5326 5327 5328 sub NativeToJSValue 5329 { 5330 my $type = shift; 5331 my $extendedAttributes = shift; 5332 my $nativeValue = shift; 5333 my $indent = shift; # added before every line 5334 my $receiver = shift; # "return" or "<variableName> =" 5335 my $getCreationContext = shift; 5336 my $getIsolate = shift; 5337 die "An Isolate is mandatory for native value => JS value conversion." unless $getIsolate; 5338 my $getCallbackInfo = shift || ""; 5339 my $getCallbackInfoArg = $getCallbackInfo ? ", $getCallbackInfo" : ""; 5340 my $getScriptWrappable = shift || ""; 5341 my $getScriptWrappableArg = $getScriptWrappable ? ", $getScriptWrappable" : ""; 5342 my $forMainWorldSuffix = shift || ""; 5343 my $returnValueArg = shift || 0; 5344 my $isReturnValue = $returnValueArg eq "return"; 5345 5346 if (IsUnionType($type)) { 5347 my $types = $type->unionMemberTypes; 5348 my @codes = (); 5349 for my $i (0 .. scalar(@$types)-1) { 5350 my $unionMemberType = $types->[$i]; 5351 my $unionMemberNumber = $i + 1; 5352 my $unionMemberVariable = $nativeValue . $i; 5353 my $unionMemberEnabledVariable = $nativeValue . $i . "Enabled"; 5354 my $unionMemberNativeValue = $unionMemberVariable; 5355 $unionMemberNativeValue .= ".release()" if (IsRefPtrType($unionMemberType)); 5356 my $returnJSValueCode = NativeToJSValue($unionMemberType, $extendedAttributes, $unionMemberNativeValue, $indent . " ", $receiver, $getCreationContext, $getIsolate, $getCallbackInfo, $getScriptWrappable, $forMainWorldSuffix, $returnValueArg); 5357 my $code = ""; 5358 if ($isReturnValue) { 5359 $code .= "${indent}if (${unionMemberEnabledVariable}) {\n"; 5360 $code .= "${returnJSValueCode}\n"; 5361 $code .= "${indent} return;\n"; 5362 $code .= "${indent}}\n"; 5363 } else { 5364 $code .= "${indent}if (${unionMemberEnabledVariable})\n"; 5365 $code .= "${returnJSValueCode}"; 5366 } 5367 push @codes, $code; 5368 } 5369 return join "\n", @codes; 5370 } 5371 5372 if ($type eq "boolean") { 5373 return "${indent}v8SetReturnValueBool(${getCallbackInfo}, ${nativeValue});" if $isReturnValue; 5374 return "$indent$receiver v8Boolean($nativeValue, $getIsolate);"; 5375 } 5376 5377 if ($type eq "void") { # equivalent to v8Undefined() 5378 return "" if $isReturnValue; 5379 return "$indent$receiver v8Undefined();" 5380 } 5381 5382 # HTML5 says that unsigned reflected attributes should be in the range 5383 # [0, 2^31). When a value isn't in this range, a default value (or 0) 5384 # should be returned instead. 5385 if ($extendedAttributes->{"Reflect"} and ($type eq "unsigned long" or $type eq "unsigned short")) { 5386 $nativeValue =~ s/getUnsignedIntegralAttribute/getIntegralAttribute/g; 5387 return "${indent}v8SetReturnValueUnsigned(${getCallbackInfo}, std::max(0, ${nativeValue}));" if $isReturnValue; 5388 return "$indent$receiver v8::Integer::NewFromUnsigned(std::max(0, " . $nativeValue . "), $getIsolate);"; 5389 } 5390 5391 my $nativeType = GetNativeType($type); 5392 if ($nativeType eq "int") { 5393 return "${indent}v8SetReturnValueInt(${getCallbackInfo}, ${nativeValue});" if $isReturnValue; 5394 return "$indent$receiver v8::Integer::New($nativeValue, $getIsolate);"; 5395 } 5396 5397 if ($nativeType eq "unsigned") { 5398 return "${indent}v8SetReturnValueUnsigned(${getCallbackInfo}, ${nativeValue});" if $isReturnValue; 5399 return "$indent$receiver v8::Integer::NewFromUnsigned($nativeValue, $getIsolate);"; 5400 } 5401 5402 if ($type eq "Date") { 5403 return "${indent}v8SetReturnValue(${getCallbackInfo}, v8DateOrNull($nativeValue, $getIsolate));" if $isReturnValue; 5404 return "$indent$receiver v8DateOrNull($nativeValue, $getIsolate);" 5405 } 5406 5407 # long long and unsigned long long are not representable in ECMAScript. 5408 if ($type eq "long long" or $type eq "unsigned long long" or $type eq "DOMTimeStamp") { 5409 return "${indent}v8SetReturnValue(${getCallbackInfo}, static_cast<double>($nativeValue));" if $isReturnValue; 5410 return "$indent$receiver v8::Number::New(static_cast<double>($nativeValue));"; 5411 } 5412 5413 if (IsPrimitiveType($type)) { 5414 die "unexpected type $type" if not ($type eq "float" or $type eq "double"); 5415 return "${indent}v8SetReturnValue(${getCallbackInfo}, ${nativeValue});" if $isReturnValue; 5416 return "$indent$receiver v8::Number::New($nativeValue);"; 5417 } 5418 5419 if ($nativeType eq "ScriptValue") { 5420 return "${indent}v8SetReturnValue(${getCallbackInfo}, ${nativeValue}.v8Value());" if $isReturnValue; 5421 return "$indent$receiver $nativeValue.v8Value();"; 5422 } 5423 5424 my $conv = $extendedAttributes->{"TreatReturnedNullStringAs"}; 5425 if (($type eq "DOMString" || IsEnumType($type)) && $isReturnValue) { 5426 my $functionSuffix = ""; 5427 if (defined $conv) { 5428 if ($conv eq "Null") { 5429 $functionSuffix = "OrNull"; 5430 } elsif ($conv eq "Undefined") { 5431 $functionSuffix = "OrUndefined"; 5432 } else { 5433 die "Unknown value for TreatReturnedNullStringAs extended attribute"; 5434 } 5435 } 5436 return "${indent}v8SetReturnValueString${functionSuffix}(${getCallbackInfo}, $nativeValue, $getIsolate);"; 5437 } 5438 5439 if ($type eq "DOMString" or IsEnumType($type)) { 5440 my $returnValue = ""; 5441 if (defined $conv) { 5442 if ($conv eq "Null") { 5443 $returnValue = "v8StringOrNull($nativeValue, $getIsolate)"; 5444 } elsif ($conv eq "Undefined") { 5445 $returnValue = "v8StringOrUndefined($nativeValue, $getIsolate)"; 5446 } else { 5447 die "Unknown value for TreatReturnedNullStringAs extended attribute"; 5448 } 5449 } else { 5450 $returnValue = "v8String($nativeValue, $getIsolate)"; 5451 } 5452 return "$indent$receiver $returnValue;"; 5453 } 5454 5455 my $arrayOrSequenceType = GetArrayOrSequenceType($type); 5456 5457 if ($arrayOrSequenceType) { 5458 if (IsRefPtrType($arrayOrSequenceType)) { 5459 AddIncludesForType($arrayOrSequenceType); 5460 } 5461 return "${indent}v8SetReturnValue(${getCallbackInfo}, v8Array($nativeValue, $getIsolate));" if $isReturnValue; 5462 return "$indent$receiver v8Array($nativeValue, $getIsolate);"; 5463 } 5464 5465 AddIncludesForType($type); 5466 5467 if ($type eq "SerializedScriptValue") { 5468 my $returnValue = "$nativeValue ? $nativeValue->deserialize() : v8::Handle<v8::Value>(v8::Null($getIsolate))"; 5469 return "${indent}v8SetReturnValue(${getCallbackInfo}, $returnValue);" if $isReturnValue; 5470 return "$indent$receiver $returnValue;"; 5471 } 5472 5473 AddToImplIncludes("wtf/RefPtr.h"); 5474 AddToImplIncludes("wtf/GetPtr.h"); 5475 5476 if ($getScriptWrappable) { 5477 # FIXME: Use safe handles 5478 if ($isReturnValue) { 5479 if ($forMainWorldSuffix eq "ForMainWorld") { 5480 return "${indent}v8SetReturnValue(${getCallbackInfo}, toV8ForMainWorld($nativeValue, $getCallbackInfo.Holder(), $getCallbackInfo.GetIsolate()));"; 5481 } 5482 return "${indent}v8SetReturnValue(${getCallbackInfo}, toV8Fast($nativeValue$getCallbackInfoArg$getScriptWrappableArg));"; 5483 } 5484 if ($forMainWorldSuffix eq "ForMainWorld") { 5485 return "$indent$receiver toV8ForMainWorld($nativeValue, $getCallbackInfo.Holder(), $getCallbackInfo.GetIsolate());"; 5486 } 5487 return "$indent$receiver toV8Fast($nativeValue$getCallbackInfoArg$getScriptWrappableArg);"; 5488 } 5489 # FIXME: Use safe handles 5490 return "${indent}v8SetReturnValue(${getCallbackInfo}, toV8($nativeValue, $getCreationContext, $getIsolate));" if $isReturnValue; 5491 return "$indent$receiver toV8($nativeValue, $getCreationContext, $getIsolate);"; 5492 } 5493 5494 sub WriteData 5495 { 5496 my $object = shift; 5497 my $interface = shift; 5498 my $outputDirectory = shift; 5499 5500 my $name = $interface->name; 5501 my $headerFileName = "$outputDirectory/V8$name.h"; 5502 my $implFileName = "$outputDirectory/V8$name.cpp"; 5503 5504 my @includes = (); 5505 foreach my $include (keys %implIncludes) { 5506 push @includes, "\"$include\""; 5507 } 5508 5509 #FIXME: do not treat main header special 5510 my $mainInclude = "\"V8$name.h\""; 5511 foreach my $include (sort @includes) { 5512 $implementation{includes}->add("#include $include\n") unless $include eq $mainInclude; 5513 } 5514 $implementation{includes}->add("\n") unless $interface->isCallback; 5515 WriteFileIfChanged($implFileName, $implementation{root}->toString()); 5516 5517 %implIncludes = (); 5518 5519 WriteFileIfChanged($headerFileName, $header{root}->toString()); 5520 } 5521 5522 sub ConvertToV8StringResource 5523 { 5524 my $attributeOrParameter = shift; 5525 my $nativeType = shift; 5526 my $variableName = shift; 5527 my $value = shift; 5528 5529 die "Wrong native type passed: $nativeType" unless $nativeType =~ /^V8StringResource/; 5530 if ($attributeOrParameter->type eq "DOMString" or IsEnumType($attributeOrParameter->type)) { 5531 return "V8TRYCATCH_FOR_V8STRINGRESOURCE_VOID($nativeType, $variableName, $value);" 5532 } else { 5533 return "$nativeType $variableName($value, true);"; 5534 } 5535 } 5536 5537 # Returns the RuntimeEnabledFeatures function name that is hooked up to check if a method/attribute is enabled. 5538 sub GetRuntimeEnableFunctionName 5539 { 5540 my $signature = shift; 5541 5542 # If a parameter is given (e.g. "EnabledAtRuntime=FeatureName") return the RuntimeEnabledFeatures::{FeatureName}Enabled() method. 5543 return "RuntimeEnabledFeatures::" . ToMethodName($signature->extendedAttributes->{"EnabledAtRuntime"}) . "Enabled" if ($signature->extendedAttributes->{"EnabledAtRuntime"} && $signature->extendedAttributes->{"EnabledAtRuntime"} ne "VALUE_IS_MISSING"); 5544 5545 # Otherwise return a function named RuntimeEnabledFeatures::{methodName}Enabled(). 5546 return "RuntimeEnabledFeatures::" . ToMethodName($signature->name) . "Enabled"; 5547 } 5548 5549 sub GetContextEnableFunction 5550 { 5551 my $signature = shift; 5552 5553 # If a parameter is given (e.g. "EnabledPerContext=FeatureName") return the {FeatureName}Allowed() method. 5554 if ($signature->extendedAttributes->{"EnabledPerContext"} && $signature->extendedAttributes->{"EnabledPerContext"} ne "VALUE_IS_MISSING") { 5555 return "ContextFeatures::" . ToMethodName($signature->extendedAttributes->{"EnabledPerContext"}) . "Enabled"; 5556 } 5557 5558 # Or it fallbacks to the attribute name if the parameter value is missing. 5559 return "ContextFeatures::" . ToMethodName($signature->name) . "Enabled"; 5560 } 5561 5562 sub GetPassRefPtrType 5563 { 5564 my $v8ClassName = shift; 5565 5566 my $angleBracketSpace = $v8ClassName =~ />$/ ? " " : ""; 5567 return "PassRefPtr<${v8ClassName}${angleBracketSpace}>"; 5568 } 5569 5570 sub WriteFileIfChanged 5571 { 5572 my $fileName = shift; 5573 my $contents = shift; 5574 5575 if (-f $fileName && $writeFileOnlyIfChanged) { 5576 open FH, "<", $fileName or die "Couldn't open $fileName: $!\n"; 5577 my @lines = <FH>; 5578 my $oldContents = join "", @lines; 5579 close FH; 5580 return if $contents eq $oldContents; 5581 } 5582 open FH, ">", $fileName or die "Couldn't open $fileName: $!\n"; 5583 print FH $contents; 5584 close FH; 5585 } 5586 5587 sub ForAllParents 5588 { 5589 my $interface = shift; 5590 my $beforeRecursion = shift; 5591 my $afterRecursion = shift; 5592 5593 my $recurse; 5594 $recurse = sub { 5595 my $currentInterface = shift; 5596 5597 if ($currentInterface->parent) { 5598 my $parentInterface = ParseInterface($currentInterface->parent); 5599 if ($beforeRecursion) { 5600 &$beforeRecursion($parentInterface) eq 'prune' and return; 5601 } 5602 &$recurse($parentInterface); 5603 &$afterRecursion($parentInterface) if $afterRecursion; 5604 } 5605 }; 5606 5607 &$recurse($interface); 5608 } 5609 5610 sub FindSuperMethod 5611 { 5612 my ($interface, $functionName) = @_; 5613 my $indexer; 5614 ForAllParents($interface, undef, sub { 5615 my $currentInterface = shift; 5616 foreach my $function (@{$currentInterface->functions}) { 5617 if ($function->name eq $functionName) { 5618 $indexer = $function; 5619 return 'prune'; 5620 } 5621 } 5622 }); 5623 return $indexer; 5624 } 5625 5626 sub IsConstructorTemplate 5627 { 5628 my $interface = shift; 5629 my $template = shift; 5630 5631 return $interface->extendedAttributes->{"ConstructorTemplate"} && $interface->extendedAttributes->{"ConstructorTemplate"} eq $template; 5632 } 5633 5634 sub IsPrimitiveType 5635 { 5636 my $type = shift; 5637 5638 return 1 if $primitiveTypeHash{$type}; 5639 return 0; 5640 } 5641 5642 sub IsCallbackFunctionType 5643 { 5644 my $type = shift; 5645 5646 return 1 if $callbackFunctionTypeHash{$type}; 5647 return 0; 5648 } 5649 5650 sub IsEnumType 5651 { 5652 my $type = shift; 5653 5654 return 1 if $enumTypeHash{$type}; 5655 return 0; 5656 } 5657 5658 sub ValidEnumValues 5659 { 5660 my $type = shift; 5661 5662 return @{$enumTypeHash{$type}}; 5663 } 5664 5665 sub IsSVGTypeNeedingTearOff 5666 { 5667 my $type = shift; 5668 5669 return 1 if $svgTypeNeedingTearOff{$type}; 5670 return 0; 5671 } 5672 5673 sub IsSVGTypeWithWritablePropertiesNeedingTearOff 5674 { 5675 my $type = shift; 5676 5677 return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type}; 5678 return 0; 5679 } 5680 5681 sub IsTypedArrayType 5682 { 5683 my $type = shift; 5684 return 1 if $typedArrayHash{$type}; 5685 return 0; 5686 } 5687 5688 sub IsRefPtrType 5689 { 5690 my $type = shift; 5691 5692 return 0 if $type eq "any"; 5693 return 0 if IsPrimitiveType($type); 5694 return 0 if GetArrayType($type); 5695 return 0 if GetSequenceType($type); 5696 return 0 if $type eq "DOMString"; 5697 return 0 if IsCallbackFunctionType($type); 5698 return 0 if IsEnumType($type); 5699 return 0 if IsUnionType($type); 5700 5701 return 1; 5702 } 5703 5704 sub GetSVGTypeNeedingTearOff 5705 { 5706 my $type = shift; 5707 5708 return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type}; 5709 return undef; 5710 } 5711 5712 sub GetSVGWrappedTypeNeedingTearOff 5713 { 5714 my $type = shift; 5715 5716 my $svgTypeNeedingTearOff = GetSVGTypeNeedingTearOff($type); 5717 return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff; 5718 5719 if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) { 5720 $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//; 5721 } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) { 5722 $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//; 5723 } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) { 5724 $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//; 5725 } elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) { 5726 $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//; 5727 } 5728 5729 $svgTypeNeedingTearOff =~ s/>//; 5730 return $svgTypeNeedingTearOff; 5731 } 5732 5733 sub IsSVGAnimatedType 5734 { 5735 my $type = shift; 5736 5737 return $type =~ /^SVGAnimated/; 5738 } 5739 5740 sub GetSequenceType 5741 { 5742 my $type = shift; 5743 5744 return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/; 5745 return ""; 5746 } 5747 5748 sub GetArrayType 5749 { 5750 my $type = shift; 5751 5752 return $1 if $type =~ /^([\w\d_\s]+)\[\]/; 5753 return ""; 5754 } 5755 5756 sub GetArrayOrSequenceType 5757 { 5758 my $type = shift; 5759 5760 return GetArrayType($type) || GetSequenceType($type); 5761 } 5762 5763 sub AssertNotSequenceType 5764 { 5765 my $type = shift; 5766 die "Sequences must not be used as the type of an attribute, constant or exception field." if GetSequenceType($type); 5767 } 5768 5769 sub FirstLetterToUpperCase 5770 { 5771 my $param = shift; 5772 my $ret = ucfirst($param); 5773 # xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. 5774 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; 5775 $ret =~ s/Css/CSS/ if $ret =~ /^Css[^T]/; # css -> setCSS, except setCssText. 5776 $ret =~ s/Ime/IME/ if $ret =~ /^Ime/; # ime -> setIME 5777 $ret =~ s/Svg/SVG/ if $ret =~ /^Svg/; # svg -> setSVG 5778 return $ret; 5779 } 5780 5781 # URL becomes url, but SetURL becomes setURL. 5782 sub ToMethodName 5783 { 5784 my $param = shift; 5785 my $ret = lcfirst($param); 5786 $ret =~ s/hTML/html/ if $ret =~ /^hTML/; 5787 $ret =~ s/uRL/url/ if $ret =~ /^uRL/; 5788 $ret =~ s/jS/js/ if $ret =~ /^jS/; 5789 $ret =~ s/xML/xml/ if $ret =~ /^xML/; 5790 $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/; 5791 $ret =~ s/cSS/css/ if $ret =~ /^cSS/; 5792 5793 # For HTML5 FileSystem API Flags attributes. 5794 # (create is widely used to instantiate an object and must be avoided.) 5795 $ret =~ s/^create/isCreate/ if $ret =~ /^create$/; 5796 $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/; 5797 5798 return $ret; 5799 } 5800 5801 sub NamespaceForAttributeName 5802 { 5803 my ($interfaceName, $attributeName) = @_; 5804 return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName}; 5805 return "HTMLNames"; 5806 } 5807 5808 # Identifies overloaded functions and for each function adds an array with 5809 # links to its respective overloads (including itself). 5810 sub LinkOverloadedFunctions 5811 { 5812 my $interface = shift; 5813 5814 my %nameToFunctionsMap = (); 5815 foreach my $function (@{$interface->functions}) { 5816 my $name = $function->name; 5817 $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name} or !$name; # Nameless functions cannot be overloaded 5818 push(@{$nameToFunctionsMap{$name}}, $function); 5819 $function->{overloads} = $nameToFunctionsMap{$name}; 5820 $function->{overloadIndex} = @{$nameToFunctionsMap{$name}}; 5821 } 5822 } 5823 5824 sub AttributeNameForGetterAndSetter 5825 { 5826 my $attribute = shift; 5827 5828 my $attributeName = GetImplName($attribute); 5829 if ($attribute->extendedAttributes->{"ImplementedAs"}) { 5830 $attributeName = $attribute->extendedAttributes->{"ImplementedAs"}; 5831 } 5832 my $attributeType = $attribute->type; 5833 5834 return $attributeName; 5835 } 5836 5837 sub ContentAttributeName 5838 { 5839 my ($interfaceName, $attribute) = @_; 5840 5841 my $contentAttributeName = $attribute->extendedAttributes->{"Reflect"}; 5842 return undef if !$contentAttributeName; 5843 5844 $contentAttributeName = lc AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING"; 5845 5846 my $namespace = NamespaceForAttributeName($interfaceName, $contentAttributeName); 5847 5848 AddToImplIncludes("${namespace}.h"); 5849 return "WebCore::${namespace}::${contentAttributeName}Attr"; 5850 } 5851 5852 sub GetterExpression 5853 { 5854 my ($interfaceName, $attribute) = @_; 5855 5856 my $contentAttributeName = ContentAttributeName($interfaceName, $attribute); 5857 5858 if (!$contentAttributeName) { 5859 return (ToMethodName(AttributeNameForGetterAndSetter($attribute))); 5860 } 5861 5862 my $functionName; 5863 if ($attribute->extendedAttributes->{"URL"}) { 5864 $functionName = "getURLAttribute"; 5865 } elsif ($attribute->type eq "boolean") { 5866 $functionName = "fastHasAttribute"; 5867 } elsif ($attribute->type eq "long") { 5868 $functionName = "getIntegralAttribute"; 5869 } elsif ($attribute->type eq "unsigned long") { 5870 $functionName = "getUnsignedIntegralAttribute"; 5871 } else { 5872 if ($contentAttributeName eq "WebCore::HTMLNames::idAttr") { 5873 $functionName = "getIdAttribute"; 5874 $contentAttributeName = ""; 5875 } elsif ($contentAttributeName eq "WebCore::HTMLNames::nameAttr") { 5876 $functionName = "getNameAttribute"; 5877 $contentAttributeName = ""; 5878 } elsif ($contentAttributeName eq "WebCore::HTMLNames::classAttr") { 5879 $functionName = "getClassAttribute"; 5880 $contentAttributeName = ""; 5881 } else { 5882 # We cannot use fast attributes for animated SVG types. 5883 $functionName = IsSVGAnimatedType($attribute->type) ? "getAttribute" : "fastGetAttribute"; 5884 } 5885 } 5886 5887 return ($functionName, $contentAttributeName); 5888 } 5889 5890 sub SetterExpression 5891 { 5892 my ($interfaceName, $attribute) = @_; 5893 5894 my $contentAttributeName = ContentAttributeName($interfaceName, $attribute); 5895 5896 if (!$contentAttributeName) { 5897 return ("set" . FirstLetterToUpperCase(AttributeNameForGetterAndSetter($attribute))); 5898 } 5899 5900 my $functionName; 5901 if ($attribute->type eq "boolean") { 5902 $functionName = "setBooleanAttribute"; 5903 } elsif ($attribute->type eq "long") { 5904 $functionName = "setIntegralAttribute"; 5905 } elsif ($attribute->type eq "unsigned long") { 5906 $functionName = "setUnsignedIntegralAttribute"; 5907 } else { 5908 $functionName = "setAttribute"; 5909 } 5910 5911 return ($functionName, $contentAttributeName); 5912 } 5913 5914 sub GenerateConditionalString 5915 { 5916 my $node = shift; 5917 5918 my $conditional = $node->extendedAttributes->{"Conditional"}; 5919 if ($conditional) { 5920 return GenerateConditionalStringFromAttributeValue($conditional); 5921 } else { 5922 return ""; 5923 } 5924 } 5925 5926 sub GenerateConditionalStringFromAttributeValue 5927 { 5928 my $conditional = shift; 5929 5930 my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : '')); 5931 if ($operator) { 5932 # Avoid duplicated conditions. 5933 my %conditions; 5934 map { $conditions{$_} = 1 } split('\\' . $operator, $conditional); 5935 return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")"; 5936 } else { 5937 return "ENABLE(" . $conditional . ")"; 5938 } 5939 } 5940 5941 sub GenerateCompileTimeCheckForEnumsIfNeeded 5942 { 5943 my $interface = shift; 5944 my $implClassName = GetImplName($interface); 5945 my @checks = (); 5946 # If necessary, check that all constants are available as enums with the same value. 5947 if (!$interface->extendedAttributes->{"DoNotCheckConstants"} && @{$interface->constants}) { 5948 push(@checks, "\n"); 5949 foreach my $constant (@{$interface->constants}) { 5950 my $reflect = $constant->extendedAttributes->{"Reflect"}; 5951 my $name = $reflect ? $reflect : $constant->name; 5952 my $value = $constant->value; 5953 my $conditionalString = GenerateConditionalString($constant); 5954 push(@checks, "#if ${conditionalString}\n") if $conditionalString; 5955 5956 if ($constant->extendedAttributes->{"ImplementedBy"}) { 5957 my $implementedByImplName = GetImplNameFromImplementedBy($constant->extendedAttributes->{"ImplementedBy"}); 5958 push(@checks, "COMPILE_ASSERT($value == " . $implementedByImplName . "::$name, ${implClassName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 5959 } else { 5960 push(@checks, "COMPILE_ASSERT($value == ${implClassName}::$name, ${implClassName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 5961 } 5962 5963 push(@checks, "#endif\n") if $conditionalString; 5964 } 5965 push(@checks, "\n"); 5966 } 5967 return @checks; 5968 } 5969 5970 sub ExtendedAttributeContains 5971 { 5972 my $callWith = shift; 5973 return 0 unless $callWith; 5974 my $keyword = shift; 5975 5976 my @callWithKeywords = split /\s*\&\s*/, $callWith; 5977 return grep { $_ eq $keyword } @callWithKeywords; 5978 } 5979 5980 sub InheritsInterface 5981 { 5982 my $interface = shift; 5983 my $interfaceName = shift; 5984 my $found = 0; 5985 5986 return 1 if $interfaceName eq $interface->name; 5987 ForAllParents($interface, sub { 5988 my $currentInterface = shift; 5989 if ($currentInterface->name eq $interfaceName) { 5990 $found = 1; 5991 } 5992 return 1 if $found; 5993 }, 0); 5994 5995 return $found; 5996 } 5997 5998 sub InheritsExtendedAttribute 5999 { 6000 my $interface = shift; 6001 my $extendedAttribute = shift; 6002 my $found = 0; 6003 6004 return 1 if $interface->extendedAttributes->{$extendedAttribute}; 6005 ForAllParents($interface, sub { 6006 my $currentInterface = shift; 6007 if ($currentInterface->extendedAttributes->{$extendedAttribute}) { 6008 $found = 1; 6009 } 6010 return 1 if $found; 6011 }, 0); 6012 6013 return $found; 6014 } 6015 6016 1; 6017