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