1 #!/usr/bin/perl -w 2 3 # Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. 4 # Copyright (C) 2009, Julien Chaffraix <jchaffraix (at] webkit.org> 5 # Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 6 # 7 # Redistribution and use in source and binary forms, with or without 8 # modification, are permitted provided that the following conditions 9 # are met: 10 # 11 # 1. Redistributions of source code must retain the above copyright 12 # notice, this list of conditions and the following disclaimer. 13 # 2. Redistributions in binary form must reproduce the above copyright 14 # notice, this list of conditions and the following disclaimer in the 15 # documentation and/or other materials provided with the distribution. 16 # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 17 # its contributors may be used to endorse or promote products derived 18 # from this software without specific prior written permission. 19 # 20 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 21 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 24 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 use strict; 32 33 use Config; 34 use Getopt::Long; 35 use File::Path; 36 use IO::File; 37 use InFilesParser; 38 use Switch; 39 40 my $printFactory = 0; 41 my $printWrapperFactory = 0; 42 my $printWrapperFactoryV8 = 0; 43 my $tagsFile = ""; 44 my $attrsFile = ""; 45 my $outputDir = "."; 46 my %tags = (); 47 my %attrs = (); 48 my %parameters = (); 49 my $extraDefines = 0; 50 my $preprocessor = "/usr/bin/gcc -E -P -x c++"; 51 52 GetOptions( 53 'tags=s' => \$tagsFile, 54 'attrs=s' => \$attrsFile, 55 'factory' => \$printFactory, 56 'outputDir=s' => \$outputDir, 57 'extraDefines=s' => \$extraDefines, 58 'preprocessor=s' => \$preprocessor, 59 'wrapperFactory' => \$printWrapperFactory, 60 'wrapperFactoryV8' => \$printWrapperFactoryV8 61 ); 62 63 die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile)); 64 65 readNames($tagsFile, "tags") if length($tagsFile); 66 readNames($attrsFile, "attrs") if length($attrsFile); 67 68 die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $parameters{namespace}; 69 die "You must specify a namespaceURI (e.g. http://www.w3.org/2000/svg)" unless $parameters{namespaceURI}; 70 71 $parameters{namespacePrefix} = $parameters{namespace} unless $parameters{namespacePrefix}; 72 73 mkpath($outputDir); 74 my $namesBasePath = "$outputDir/$parameters{namespace}Names"; 75 my $factoryBasePath = "$outputDir/$parameters{namespace}ElementFactory"; 76 my $wrapperFactoryFileName = "$parameters{namespace}ElementWrapperFactory"; 77 78 printNamesHeaderFile("$namesBasePath.h"); 79 printNamesCppFile("$namesBasePath.cpp"); 80 81 if ($printFactory) { 82 printFactoryCppFile("$factoryBasePath.cpp"); 83 printFactoryHeaderFile("$factoryBasePath.h"); 84 } 85 86 die "You cannot specify both --wrapperFactory and --wrapperFactoryV8" if $printWrapperFactory && $printWrapperFactoryV8; 87 my $wrapperFactoryType = ""; 88 if ($printWrapperFactory) { 89 $wrapperFactoryType = "JS"; 90 } elsif ($printWrapperFactoryV8) { 91 $wrapperFactoryType = "V8"; 92 } 93 94 if ($wrapperFactoryType) { 95 printWrapperFactoryCppFile($outputDir, $wrapperFactoryType, $wrapperFactoryFileName); 96 printWrapperFactoryHeaderFile($outputDir, $wrapperFactoryType, $wrapperFactoryFileName); 97 } 98 99 ### Hash initialization 100 101 sub defaultTagPropertyHash 102 { 103 return ( 104 'constructorNeedsCreatedByParser' => 0, 105 'constructorNeedsFormElement' => 0, 106 'createWithNew' => 0, 107 'interfaceName' => defaultInterfaceName($_[0]), 108 # By default, the JSInterfaceName is the same as the interfaceName. 109 'JSInterfaceName' => defaultInterfaceName($_[0]), 110 'mapToTagName' => '', 111 'wrapperOnlyIfMediaIsAvailable' => 0, 112 'conditional' => 0 113 ); 114 } 115 116 sub defaultParametersHash 117 { 118 return ( 119 'namespace' => '', 120 'namespacePrefix' => '', 121 'namespaceURI' => '', 122 'guardFactoryWith' => '', 123 'tagsNullNamespace' => 0, 124 'attrsNullNamespace' => 0 125 ); 126 } 127 128 sub defaultInterfaceName 129 { 130 die "No namespace found" if !$parameters{namespace}; 131 return $parameters{namespace} . upperCaseName($_[0]) . "Element" 132 } 133 134 ### Parsing handlers 135 136 sub tagsHandler 137 { 138 my ($tag, $property, $value) = @_; 139 140 $tag =~ s/-/_/g; 141 142 # Initialize default property values. 143 $tags{$tag} = { defaultTagPropertyHash($tag) } if !defined($tags{$tag}); 144 145 if ($property) { 146 die "Unknown property $property for tag $tag\n" if !defined($tags{$tag}{$property}); 147 148 # The code relies on JSInterfaceName deriving from interfaceName to check for custom JSInterfaceName. 149 # So override JSInterfaceName if it was not already set. 150 $tags{$tag}{JSInterfaceName} = $value if $property eq "interfaceName" && $tags{$tag}{JSInterfaceName} eq $tags{$tag}{interfaceName}; 151 152 $tags{$tag}{$property} = $value; 153 } 154 } 155 156 sub attrsHandler 157 { 158 my ($attr, $property, $value) = @_; 159 160 $attr =~ s/-/_/g; 161 162 # Initialize default properties' values. 163 $attrs{$attr} = {} if !defined($attrs{$attr}); 164 165 if ($property) { 166 die "Unknown property $property for attribute $attr\n" if !defined($attrs{$attr}{$property}); 167 $attrs{$attr}{$property} = $value; 168 } 169 } 170 171 sub parametersHandler 172 { 173 my ($parameter, $value) = @_; 174 175 # Initialize default properties' values. 176 %parameters = defaultParametersHash() if !(keys %parameters); 177 178 die "Unknown parameter $parameter for tags/attrs\n" if !defined($parameters{$parameter}); 179 $parameters{$parameter} = $value; 180 } 181 182 ## Support routines 183 184 sub readNames 185 { 186 my ($namesFile, $type) = @_; 187 188 my $names = new IO::File; 189 190 if ($extraDefines eq 0) { 191 open($names, $preprocessor . " " . $namesFile . "|") or die "Failed to open file: $namesFile"; 192 } else { 193 open($names, $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)) . " " . $namesFile . "|") or die "Failed to open file: $namesFile"; 194 } 195 196 # Store hashes keys count to know if some insertion occured. 197 my $tagsCount = keys %tags; 198 my $attrsCount = keys %attrs; 199 200 my $InParser = InFilesParser->new(); 201 202 switch ($type) { 203 case "tags" { 204 $InParser->parse($names, \¶metersHandler, \&tagsHandler); 205 } 206 case "attrs" { 207 $InParser->parse($names, \¶metersHandler, \&attrsHandler); 208 } 209 else { 210 die "Do not know how to parse $type"; 211 } 212 } 213 214 close($names); 215 216 die "Failed to read names from file: $namesFile" if ((keys %tags == $tagsCount) && (keys %attrs == $attrsCount)); 217 } 218 219 sub printMacros 220 { 221 my ($F, $macro, $suffix, $namesRef) = @_; 222 my %names = %$namesRef; 223 224 for my $name (sort keys %$namesRef) { 225 print F "$macro $name","$suffix;\n"; 226 } 227 } 228 229 sub usesDefaultWrapper 230 { 231 my $tagName = shift; 232 return $tagName eq $parameters{namespace} . "Element"; 233 } 234 235 # Build a direct mapping from the tags to the Element to create, excluding 236 # Element that have not constructor. 237 sub buildConstructorMap 238 { 239 my %tagConstructorMap = (); 240 for my $tagName (keys %tags) { 241 my $interfaceName = $tags{$tagName}{interfaceName}; 242 next if (usesDefaultWrapper($interfaceName)); 243 244 if ($tags{$tagName}{mapToTagName}) { 245 die "Cannot handle multiple mapToTagName for $tagName\n" if $tags{$tags{$tagName}{mapToTagName}}{mapToTagName}; 246 $interfaceName = $tags{ $tags{$tagName}{mapToTagName} }{interfaceName}; 247 } 248 249 # Chop the string to keep the interesting part. 250 $interfaceName =~ s/$parameters{namespace}(.*)Element/$1/; 251 $tagConstructorMap{$tagName} = lc($interfaceName); 252 } 253 254 return %tagConstructorMap; 255 } 256 257 # Helper method that print the constructor's signature avoiding 258 # unneeded arguments. 259 sub printConstructorSignature 260 { 261 my ($F, $tagName, $constructorName, $constructorTagName) = @_; 262 263 print F "static PassRefPtr<$parameters{namespace}Element> ${constructorName}Constructor(const QualifiedName& $constructorTagName, Document* document"; 264 if ($parameters{namespace} eq "HTML") { 265 print F ", HTMLFormElement*"; 266 print F " formElement" if $tags{$tagName}{constructorNeedsFormElement}; 267 } 268 print F ", bool"; 269 print F " createdByParser" if $tags{$tagName}{constructorNeedsCreatedByParser}; 270 print F ")\n{\n"; 271 } 272 273 # Helper method to dump the constructor interior and call the 274 # Element constructor with the right arguments. 275 # The variable names should be kept in sync with the previous method. 276 sub printConstructorInterior 277 { 278 my ($F, $tagName, $interfaceName, $constructorTagName) = @_; 279 280 # Handle media elements. 281 if ($tags{$tagName}{wrapperOnlyIfMediaIsAvailable}) { 282 print F <<END 283 if (!MediaPlayer::isAvailable()) 284 return HTMLElement::create($constructorTagName, document); 285 END 286 ; 287 } 288 289 my $newPrefix = ""; 290 my $createSuffix = "::create"; 291 292 if ($tags{$tagName}{createWithNew}) { 293 $newPrefix = "new "; 294 $createSuffix = ""; 295 } 296 297 # Call the constructor with the right parameters. 298 print F " return $newPrefix$interfaceName${createSuffix}($constructorTagName, document"; 299 print F ", formElement" if $tags{$tagName}{constructorNeedsFormElement}; 300 print F ", createdByParser" if $tags{$tagName}{constructorNeedsCreatedByParser}; 301 print F ");\n}\n\n"; 302 } 303 304 sub printConstructors 305 { 306 my ($F, $tagConstructorMapRef) = @_; 307 my %tagConstructorMap = %$tagConstructorMapRef; 308 309 print F "#if $parameters{guardFactoryWith}\n" if $parameters{guardFactoryWith}; 310 311 # This is to avoid generating the same constructor several times. 312 my %uniqueTags = (); 313 for my $tagName (sort keys %tagConstructorMap) { 314 my $interfaceName = $tags{$tagName}{interfaceName}; 315 316 # Ignore the mapped tag 317 # FIXME: It could be moved inside this loop but was split for readibility. 318 next if (defined($uniqueTags{$interfaceName}) || $tags{$tagName}{mapToTagName}); 319 320 $uniqueTags{$interfaceName} = '1'; 321 322 my $conditional = $tags{$tagName}{conditional}; 323 if ($conditional) { 324 my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; 325 print F "#if ${conditionalString}\n\n"; 326 } 327 328 printConstructorSignature($F, $tagName, $tagConstructorMap{$tagName}, "tagName"); 329 printConstructorInterior($F, $tagName, $interfaceName, "tagName"); 330 331 if ($conditional) { 332 print F "#endif\n"; 333 } 334 } 335 336 # Mapped tag name uses a special wrapper to keep their prefix and namespaceURI while using the mapped localname. 337 for my $tagName (sort keys %tagConstructorMap) { 338 if ($tags{$tagName}{mapToTagName}) { 339 my $mappedName = $tags{$tagName}{mapToTagName}; 340 printConstructorSignature($F, $mappedName, $mappedName . "To" . $tagName, "tagName"); 341 printConstructorInterior($F, $mappedName, $tags{$mappedName}{interfaceName}, "QualifiedName(tagName.prefix(), ${mappedName}Tag.localName(), tagName.namespaceURI())"); 342 } 343 } 344 345 print F "#endif\n" if $parameters{guardFactoryWith}; 346 } 347 348 sub printFunctionInits 349 { 350 my ($F, $tagConstructorMap) = @_; 351 my %tagConstructorMap = %$tagConstructorMap; 352 353 for my $tagName (sort keys %tagConstructorMap) { 354 355 my $conditional = $tags{$tagName}{conditional}; 356 if ($conditional) { 357 my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; 358 print F "#if ${conditionalString}\n"; 359 } 360 361 if ($tags{$tagName}{mapToTagName}) { 362 print F " addTag(${tagName}Tag, $tags{$tagName}{mapToTagName}To${tagName}Constructor);\n"; 363 } else { 364 print F " addTag(${tagName}Tag, $tagConstructorMap{$tagName}Constructor);\n"; 365 } 366 367 if ($conditional) { 368 print F "#endif\n\n"; 369 } 370 } 371 } 372 373 sub svgCapitalizationHacks 374 { 375 my $name = shift; 376 377 $name = "FE" . ucfirst $1 if $name =~ /^fe(.+)$/; 378 379 return $name; 380 } 381 382 sub upperCaseName 383 { 384 my $name = shift; 385 386 $name = svgCapitalizationHacks($name) if ($parameters{namespace} eq "SVG"); 387 388 while ($name =~ /^(.*?)_(.*)/) { 389 $name = $1 . ucfirst $2; 390 } 391 392 return ucfirst $name; 393 } 394 395 sub printLicenseHeader 396 { 397 my $F = shift; 398 print F "/* 399 * THIS FILE WAS AUTOMATICALLY GENERATED, DO NOT EDIT. 400 * 401 * This file was generated by the dom/make_names.pl script. 402 * 403 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 404 * 405 * Redistribution and use in source and binary forms, with or without 406 * modification, are permitted provided that the following conditions 407 * are met: 408 * 1. Redistributions of source code must retain the above copyright 409 * notice, this list of conditions and the following disclaimer. 410 * 2. Redistributions in binary form must reproduce the above copyright 411 * notice, this list of conditions and the following disclaimer in the 412 * documentation and/or other materials provided with the distribution. 413 * 414 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 415 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 416 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 417 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 418 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 419 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 420 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 421 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 422 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 423 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 424 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 425 */ 426 427 "; 428 } 429 430 sub printNamesHeaderFile 431 { 432 my ($headerPath) = shift; 433 my $F; 434 open F, ">$headerPath"; 435 436 printLicenseHeader($F); 437 print F "#ifndef DOM_$parameters{namespace}NAMES_H\n"; 438 print F "#define DOM_$parameters{namespace}NAMES_H\n\n"; 439 print F "#include \"QualifiedName.h\"\n\n"; 440 441 print F "namespace WebCore {\n\n namespace $parameters{namespace}Names {\n\n"; 442 443 my $lowerNamespace = lc($parameters{namespacePrefix}); 444 print F "#ifndef DOM_$parameters{namespace}NAMES_HIDE_GLOBALS\n"; 445 print F "// Namespace\n"; 446 print F "extern const WebCore::AtomicString ${lowerNamespace}NamespaceURI;\n\n"; 447 448 if (keys %tags) { 449 print F "// Tags\n"; 450 printMacros($F, "extern const WebCore::QualifiedName", "Tag", \%tags); 451 } 452 453 if (keys %attrs) { 454 print F "// Attributes\n"; 455 printMacros($F, "extern const WebCore::QualifiedName", "Attr", \%attrs); 456 } 457 print F "#endif\n\n"; 458 459 if (keys %tags) { 460 print F "WebCore::QualifiedName** get$parameters{namespace}Tags(size_t* size);\n"; 461 } 462 463 if (keys %attrs) { 464 print F "WebCore::QualifiedName** get$parameters{namespace}Attrs(size_t* size);\n"; 465 } 466 467 print F "\nvoid init();\n\n"; 468 print F "} }\n\n"; 469 print F "#endif\n\n"; 470 471 close F; 472 } 473 474 sub printNamesCppFile 475 { 476 my $cppPath = shift; 477 my $F; 478 open F, ">$cppPath"; 479 480 printLicenseHeader($F); 481 482 my $lowerNamespace = lc($parameters{namespacePrefix}); 483 484 print F "#include \"config.h\"\n"; 485 486 print F "#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC\n"; 487 print F "#define DOM_$parameters{namespace}NAMES_HIDE_GLOBALS 1\n"; 488 print F "#else\n"; 489 print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n"; 490 print F "#endif\n\n"; 491 492 493 print F "#include \"$parameters{namespace}Names.h\"\n\n"; 494 print F "#include \"StaticConstructors.h\"\n"; 495 496 print F "namespace WebCore {\n\n namespace $parameters{namespace}Names { 497 498 using namespace WebCore; 499 500 DEFINE_GLOBAL(AtomicString, ${lowerNamespace}NamespaceURI, \"$parameters{namespaceURI}\") 501 "; 502 503 if (keys %tags) { 504 print F "// Tags\n"; 505 for my $name (sort keys %tags) { 506 print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Tag, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n"; 507 } 508 509 print F "\n\nWebCore::QualifiedName** get$parameters{namespace}Tags(size_t* size)\n"; 510 print F "{\n static WebCore::QualifiedName* $parameters{namespace}Tags[] = {\n"; 511 for my $name (sort keys %tags) { 512 print F " (WebCore::QualifiedName*)&${name}Tag,\n"; 513 } 514 print F " };\n"; 515 print F " *size = ", scalar(keys %tags), ";\n"; 516 print F " return $parameters{namespace}Tags;\n"; 517 print F "}\n"; 518 } 519 520 if (keys %attrs) { 521 print F "\n// Attributes\n"; 522 for my $name (sort keys %attrs) { 523 print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Attr, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n"; 524 } 525 print F "\n\nWebCore::QualifiedName** get$parameters{namespace}Attrs(size_t* size)\n"; 526 print F "{\n static WebCore::QualifiedName* $parameters{namespace}Attr[] = {\n"; 527 for my $name (sort keys %attrs) { 528 print F " (WebCore::QualifiedName*)&${name}Attr,\n"; 529 } 530 print F " };\n"; 531 print F " *size = ", scalar(keys %attrs), ";\n"; 532 print F " return $parameters{namespace}Attr;\n"; 533 print F "}\n"; 534 } 535 536 print F "\nvoid init() 537 { 538 static bool initialized = false; 539 if (initialized) 540 return; 541 initialized = true; 542 543 // Use placement new to initialize the globals. 544 545 AtomicString::init(); 546 "; 547 548 print(F " AtomicString ${lowerNamespace}NS(\"$parameters{namespaceURI}\");\n\n"); 549 550 print(F " // Namespace\n"); 551 print(F " new ((void*)&${lowerNamespace}NamespaceURI) AtomicString(${lowerNamespace}NS);\n\n"); 552 if (keys %tags) { 553 my $tagsNamespace = $parameters{tagsNullNamespace} ? "nullAtom" : "${lowerNamespace}NS"; 554 printDefinitions($F, \%tags, "tags", $tagsNamespace); 555 } 556 if (keys %attrs) { 557 my $attrsNamespace = $parameters{attrsNullNamespace} ? "nullAtom" : "${lowerNamespace}NS"; 558 printDefinitions($F, \%attrs, "attributes", $attrsNamespace); 559 } 560 561 print F "}\n\n} }\n\n"; 562 close F; 563 } 564 565 sub printJSElementIncludes 566 { 567 my $F = shift; 568 my $wrapperFactoryType = shift; 569 570 my %tagsSeen; 571 for my $tagName (sort keys %tags) { 572 my $JSInterfaceName = $tags{$tagName}{JSInterfaceName}; 573 next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName); 574 $tagsSeen{$JSInterfaceName} = 1; 575 576 print F "#include \"${wrapperFactoryType}${JSInterfaceName}.h\"\n"; 577 } 578 } 579 580 sub printElementIncludes 581 { 582 my $F = shift; 583 584 my %tagsSeen; 585 for my $tagName (sort keys %tags) { 586 my $interfaceName = $tags{$tagName}{interfaceName}; 587 next if defined($tagsSeen{$interfaceName}); 588 $tagsSeen{$interfaceName} = 1; 589 590 print F "#include \"${interfaceName}.h\"\n"; 591 } 592 } 593 594 sub printDefinitions 595 { 596 my ($F, $namesRef, $type, $namespaceURI) = @_; 597 my $singularType = substr($type, 0, -1); 598 my $shortType = substr($singularType, 0, 4); 599 my $shortCamelType = ucfirst($shortType); 600 my $shortUpperType = uc($shortType); 601 602 print F " // " . ucfirst($type) . "\n"; 603 604 for my $name (sort keys %$namesRef) { 605 my $realName = $name; 606 $realName =~ s/_/-/g; 607 print F " new ((void*)&$name","${shortCamelType}) QualifiedName(nullAtom, \"$realName\", $namespaceURI);\n"; 608 } 609 } 610 611 ## ElementFactory routines 612 613 sub printFactoryCppFile 614 { 615 my $cppPath = shift; 616 my $F; 617 open F, ">$cppPath"; 618 619 printLicenseHeader($F); 620 621 print F <<END 622 #include "config.h" 623 #include "$parameters{namespace}ElementFactory.h" 624 625 #include "$parameters{namespace}Names.h" 626 END 627 ; 628 629 printElementIncludes($F); 630 631 print F <<END 632 #include <wtf/HashMap.h> 633 634 #if ENABLE(DASHBOARD_SUPPORT) 635 #include "Document.h" 636 #include "Settings.h" 637 #endif 638 639 namespace WebCore { 640 641 using namespace $parameters{namespace}Names; 642 643 END 644 ; 645 646 print F "typedef PassRefPtr<$parameters{namespace}Element> (*ConstructorFunction)(const QualifiedName&, Document*"; 647 print F ", HTMLFormElement*" if $parameters{namespace} eq "HTML"; 648 print F ", bool createdByParser);\n"; 649 print F <<END 650 typedef HashMap<AtomicStringImpl*, ConstructorFunction> FunctionMap; 651 652 static FunctionMap* gFunctionMap = 0; 653 654 END 655 ; 656 657 my %tagConstructorMap = buildConstructorMap(); 658 659 printConstructors($F, \%tagConstructorMap); 660 661 print F "#if $parameters{guardFactoryWith}\n" if $parameters{guardFactoryWith}; 662 663 print F <<END 664 static void addTag(const QualifiedName& tag, ConstructorFunction func) 665 { 666 gFunctionMap->set(tag.localName().impl(), func); 667 } 668 669 static void createFunctionMap() 670 { 671 ASSERT(!gFunctionMap); 672 673 // Create the table. 674 gFunctionMap = new FunctionMap; 675 676 // Populate it with constructor functions. 677 END 678 ; 679 680 printFunctionInits($F, \%tagConstructorMap); 681 682 print F "}\n"; 683 print F "#endif\n" if $parameters{guardFactoryWith}; 684 685 print F "\nPassRefPtr<$parameters{namespace}Element> $parameters{namespace}ElementFactory::create$parameters{namespace}Element(const QualifiedName& qName, Document* document"; 686 print F ", HTMLFormElement* formElement" if $parameters{namespace} eq "HTML"; 687 print F ", bool createdByParser)\n{\n"; 688 689 print F "#if $parameters{guardFactoryWith}\n" if $parameters{guardFactoryWith}; 690 691 print F <<END 692 if (!document) 693 return 0; 694 695 END 696 ; 697 698 if ($parameters{namespace} ne "HTML") { 699 print F <<END 700 #if ENABLE(DASHBOARD_SUPPORT) 701 Settings* settings = document->settings(); 702 if (settings && settings->usesDashboardBackwardCompatibilityMode()) 703 return 0; 704 #endif 705 END 706 ; 707 708 } 709 710 print F <<END 711 if (!gFunctionMap) 712 createFunctionMap(); 713 if (ConstructorFunction function = gFunctionMap->get(qName.localName().impl())) 714 END 715 ; 716 717 if ($parameters{namespace} eq "HTML") { 718 print F " return function(qName, document, formElement, createdByParser);\n"; 719 } else { 720 print F " return function(qName, document, createdByParser);\n"; 721 } 722 723 print F " return $parameters{namespace}Element::create(qName, document);\n"; 724 725 if ($parameters{guardFactoryWith}) { 726 727 print F <<END 728 #else 729 return 0; 730 #endif 731 END 732 ; 733 734 } 735 736 print F <<END 737 } 738 739 } // namespace WebCore 740 741 END 742 ; 743 744 close F; 745 } 746 747 sub printFactoryHeaderFile 748 { 749 my $headerPath = shift; 750 my $F; 751 open F, ">$headerPath"; 752 753 printLicenseHeader($F); 754 755 print F<<END 756 #ifndef $parameters{namespace}ElementFactory_h 757 #define $parameters{namespace}ElementFactory_h 758 759 #include <wtf/PassRefPtr.h> 760 761 namespace WebCore { 762 class Element; 763 class Document; 764 class QualifiedName; 765 class AtomicString; 766 } 767 768 namespace WebCore { 769 770 class $parameters{namespace}Element; 771 END 772 ; 773 774 print F " class HTMLFormElement;\n" if $parameters{namespace} eq "HTML"; 775 776 print F<<END 777 // The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense 778 // elements. In a compound document world, the generic createElement function (will end up being virtual) will be called. 779 class $parameters{namespace}ElementFactory { 780 public: 781 PassRefPtr<Element> createElement(const WebCore::QualifiedName&, WebCore::Document*, bool createdByParser = true); 782 END 783 ; 784 print F " static PassRefPtr<$parameters{namespace}Element> create$parameters{namespace}Element(const WebCore::QualifiedName&, WebCore::Document*"; 785 print F ", HTMLFormElement* = 0" if $parameters{namespace} eq "HTML"; 786 print F ", bool /*createdByParser*/ = true);\n"; 787 788 printf F<<END 789 }; 790 } 791 792 #endif // $parameters{namespace}ElementFactory_h 793 794 END 795 ; 796 797 close F; 798 } 799 800 ## Wrapper Factory routines 801 802 sub usesDefaultJSWrapper 803 { 804 my $name = shift; 805 806 # A tag reuses the default wrapper if its JSInterfaceName matches the default namespace Element. 807 return $tags{$name}{JSInterfaceName} eq $parameters{namespace} . "Element" || $tags{$name}{JSInterfaceName} eq "HTMLNoScriptElement"; 808 } 809 810 sub printWrapperFunctions 811 { 812 my $F = shift; 813 my $wrapperFactoryType = shift; 814 815 my %tagsSeen; 816 for my $tagName (sort keys %tags) { 817 # Avoid defining the same wrapper method twice. 818 my $JSInterfaceName = $tags{$tagName}{JSInterfaceName}; 819 next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName); 820 $tagsSeen{$JSInterfaceName} = 1; 821 822 my $conditional = $tags{$tagName}{conditional}; 823 if ($conditional) { 824 my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; 825 print F "#if ${conditionalString}\n\n"; 826 } 827 828 if ($wrapperFactoryType eq "JS") { 829 # Hack for the media tags 830 # FIXME: This should have been done via a CustomWrapper attribute and a separate *Custom file. 831 if ($tags{$tagName}{wrapperOnlyIfMediaIsAvailable}) { 832 print F <<END 833 static JSNode* create${JSInterfaceName}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{namespace}Element> element) 834 { 835 if (!MediaPlayer::isAvailable()) 836 return CREATE_DOM_NODE_WRAPPER(exec, globalObject, $parameters{namespace}Element, element.get()); 837 return CREATE_DOM_NODE_WRAPPER(exec, globalObject, ${JSInterfaceName}, element.get()); 838 } 839 840 END 841 ; 842 } else { 843 print F <<END 844 static JSNode* create${JSInterfaceName}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{namespace}Element> element) 845 { 846 return CREATE_DOM_NODE_WRAPPER(exec, globalObject, ${JSInterfaceName}, element.get()); 847 } 848 849 END 850 ; 851 } 852 } elsif ($wrapperFactoryType eq "V8") { 853 print F <<END 854 static v8::Handle<v8::Value> create${JSInterfaceName}Wrapper($parameters{namespace}Element* element) 855 { 856 return toV8(static_cast<${JSInterfaceName}*>(element)); 857 } 858 859 END 860 ; 861 } 862 863 if ($conditional) { 864 print F "#endif\n\n"; 865 } 866 } 867 } 868 869 sub printWrapperFactoryCppFile 870 { 871 my $outputDir = shift; 872 my $wrapperFactoryType = shift; 873 my $wrapperFactoryFileName = shift; 874 my $F; 875 open F, ">" . $outputDir . "/" . $wrapperFactoryType . $wrapperFactoryFileName . ".cpp"; 876 877 printLicenseHeader($F); 878 879 print F "#include \"config.h\"\n\n"; 880 881 print F "#if $parameters{guardFactoryWith}\n\n" if $parameters{guardFactoryWith}; 882 883 print F "#include \"$wrapperFactoryType$parameters{namespace}ElementWrapperFactory.h\"\n"; 884 885 printJSElementIncludes($F, $wrapperFactoryType); 886 887 print F "\n#include \"$parameters{namespace}Names.h\"\n\n"; 888 889 printElementIncludes($F); 890 891 print F "\n#include <wtf/StdLibExtras.h>\n\n"; 892 893 if ($wrapperFactoryType eq "JS") { 894 print F <<END 895 using namespace JSC; 896 END 897 ; 898 } elsif ($wrapperFactoryType eq "V8") { 899 print F <<END 900 #include "V8$parameters{namespace}Element.h" 901 902 #include <v8.h> 903 END 904 ; 905 } 906 907 print F <<END 908 909 namespace WebCore { 910 911 using namespace $parameters{namespace}Names; 912 913 END 914 ; 915 if ($wrapperFactoryType eq "JS") { 916 print F <<END 917 typedef JSNode* (*Create$parameters{namespace}ElementWrapperFunction)(ExecState*, JSDOMGlobalObject*, PassRefPtr<$parameters{namespace}Element>); 918 919 END 920 ; 921 } elsif ($wrapperFactoryType eq "V8") { 922 print F <<END 923 typedef v8::Handle<v8::Value> (*Create$parameters{namespace}ElementWrapperFunction)($parameters{namespace}Element*); 924 925 END 926 ; 927 } 928 929 printWrapperFunctions($F, $wrapperFactoryType); 930 931 if ($wrapperFactoryType eq "JS") { 932 print F <<END 933 JSNode* createJS$parameters{namespace}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{namespace}Element> element) 934 { 935 typedef HashMap<WebCore::AtomicStringImpl*, Create$parameters{namespace}ElementWrapperFunction> FunctionMap; 936 DEFINE_STATIC_LOCAL(FunctionMap, map, ()); 937 if (map.isEmpty()) { 938 END 939 ; 940 } elsif ($wrapperFactoryType eq "V8") { 941 print F <<END 942 v8::Handle<v8::Value> createV8$parameters{namespace}Wrapper($parameters{namespace}Element* element, bool forceNewObject) 943 { 944 typedef HashMap<WebCore::AtomicStringImpl*, Create$parameters{namespace}ElementWrapperFunction> FunctionMap; 945 DEFINE_STATIC_LOCAL(FunctionMap, map, ()); 946 if (map.isEmpty()) { 947 END 948 ; 949 } 950 951 for my $tag (sort keys %tags) { 952 # Do not add the name to the map if it does not have a JS wrapper constructor or uses the default wrapper. 953 next if usesDefaultJSWrapper($tag, \%tags); 954 955 my $conditional = $tags{$tag}{conditional}; 956 if ($conditional) { 957 my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")"; 958 print F "#if ${conditionalString}\n"; 959 } 960 961 my $ucTag = $tags{$tag}{JSInterfaceName}; 962 print F " map.set(${tag}Tag.localName().impl(), create${ucTag}Wrapper);\n"; 963 964 if ($conditional) { 965 print F "#endif\n"; 966 } 967 } 968 969 print F <<END 970 } 971 Create$parameters{namespace}ElementWrapperFunction createWrapperFunction = map.get(element->localName().impl()); 972 if (createWrapperFunction) 973 END 974 ; 975 if ($wrapperFactoryType eq "JS") { 976 print F <<END 977 return createWrapperFunction(exec, globalObject, element); 978 return CREATE_DOM_NODE_WRAPPER(exec, globalObject, $parameters{namespace}Element, element.get()); 979 END 980 ; 981 } elsif ($wrapperFactoryType eq "V8") { 982 print F <<END 983 return createWrapperFunction(element); 984 return V8$parameters{namespace}Element::wrap(element, forceNewObject); 985 END 986 ; 987 } 988 print F <<END 989 } 990 991 } 992 993 END 994 ; 995 996 print F "#endif\n" if $parameters{guardFactoryWith}; 997 998 close F; 999 } 1000 1001 sub printWrapperFactoryHeaderFile 1002 { 1003 my $outputDir = shift; 1004 my $wrapperFactoryType = shift; 1005 my $wrapperFactoryFileName = shift; 1006 my $F; 1007 open F, ">" . $outputDir . "/" . $wrapperFactoryType . $wrapperFactoryFileName . ".h"; 1008 1009 printLicenseHeader($F); 1010 1011 print F "#ifndef $wrapperFactoryType$parameters{namespace}ElementWrapperFactory_h\n"; 1012 print F "#define $wrapperFactoryType$parameters{namespace}ElementWrapperFactory_h\n\n"; 1013 1014 print F "#if $parameters{guardFactoryWith}\n" if $parameters{guardFactoryWith}; 1015 1016 if ($wrapperFactoryType eq "JS") { 1017 print F <<END 1018 #include <wtf/Forward.h> 1019 1020 namespace JSC { 1021 class ExecState; 1022 } 1023 1024 namespace WebCore { 1025 1026 class JSNode; 1027 class JSDOMGlobalObject; 1028 class $parameters{namespace}Element; 1029 1030 JSNode* createJS$parameters{namespace}Wrapper(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<$parameters{namespace}Element>); 1031 1032 } 1033 1034 END 1035 ; 1036 } elsif ($wrapperFactoryType eq "V8") { 1037 print F <<END 1038 #include <v8.h> 1039 1040 namespace WebCore { 1041 1042 class $parameters{namespace}Element; 1043 1044 v8::Handle<v8::Value> createV8$parameters{namespace}Wrapper($parameters{namespace}Element*, bool); 1045 } 1046 END 1047 ; 1048 } 1049 1050 print F "#endif // $parameters{guardFactoryWith}\n\n" if $parameters{guardFactoryWith}; 1051 1052 print F "#endif // $wrapperFactoryType$parameters{namespace}ElementWrapperFactory_h\n"; 1053 1054 close F; 1055 } 1056