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