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# 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 32use strict; 33 34use Config; 35use Getopt::Long; 36use File::Path; 37use IO::File; 38use InFilesParser; 39 40sub readTags($$); 41sub readAttrs($$); 42 43my $printFactory = 0; 44my $printWrapperFactory = 0; 45my $printWrapperFactoryV8 = 0; 46my $tagsFile = ""; 47my $attrsFile = ""; 48my $outputDir = "."; 49my %parsedTags = (); 50my %parsedAttrs = (); 51my %enabledTags = (); 52my %enabledAttrs = (); 53my %allTags = (); 54my %allAttrs = (); 55my %parameters = (); 56my $extraDefines = 0; 57my %extensionAttrs = (); 58 59require Config; 60 61my $gccLocation = ""; 62if ($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} 69my $preprocessor = $gccLocation . " -E -x c++"; 70 71GetOptions( 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 82die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile)); 83 84if (length($tagsFile)) { 85 %allTags = %{readTags($tagsFile, 0)}; 86 %enabledTags = %{readTags($tagsFile, 1)}; 87} 88 89if (length($attrsFile)) { 90 %allAttrs = %{readAttrs($attrsFile, 0)}; 91 %enabledAttrs = %{readAttrs($attrsFile, 1)}; 92} 93 94die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $parameters{namespace}; 95die "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 99mkpath($outputDir); 100my $namesBasePath = "$outputDir/$parameters{namespace}Names"; 101my $factoryBasePath = "$outputDir/$parameters{namespace}ElementFactory"; 102my $wrapperFactoryFileName = "$parameters{namespace}ElementWrapperFactory"; 103 104printNamesHeaderFile("$namesBasePath.h"); 105printNamesCppFile("$namesBasePath.cpp"); 106 107if ($printFactory) { 108 printFactoryCppFile("$factoryBasePath.cpp"); 109 printFactoryHeaderFile("$factoryBasePath.h"); 110} 111 112die "You cannot specify both --wrapperFactory and --wrapperFactoryV8" if $printWrapperFactory && $printWrapperFactoryV8; 113my $wrapperFactoryType = ""; 114if ($printWrapperFactory) { 115 $wrapperFactoryType = "JS"; 116} elsif ($printWrapperFactoryV8) { 117 $wrapperFactoryType = "V8"; 118} 119 120if ($wrapperFactoryType) { 121 printWrapperFactoryCppFile($outputDir, $wrapperFactoryType, $wrapperFactoryFileName); 122 printWrapperFactoryHeaderFile($outputDir, $wrapperFactoryType, $wrapperFactoryFileName); 123} 124 125### Hash initialization 126 127sub 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 141sub defaultParametersHash 142{ 143 return ( 144 'namespace' => '', 145 'namespacePrefix' => '', 146 'namespaceURI' => '', 147 'guardFactoryWith' => '', 148 'tagsNullNamespace' => 0, 149 'attrsNullNamespace' => 0 150 ); 151} 152 153sub defaultInterfaceName 154{ 155 die "No namespace found" if !$parameters{namespace}; 156 return $parameters{namespace} . upperCaseName($_[0]) . "Element" 157} 158 159### Parsing handlers 160 161sub 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 181sub 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 203sub 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 216sub preprocessorCommand() 217{ 218 return $preprocessor if $extraDefines eq 0; 219 return $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)); 220} 221 222sub 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 241sub readAttrs($$) 242{ 243 my ($namesFile, $usePreprocessor) = @_; 244 %parsedAttrs = (); 245 return readNames($namesFile, \%parsedAttrs, \&attrsHandler, $usePreprocessor); 246} 247 248sub readTags($$) 249{ 250 my ($namesFile, $usePreprocessor) = @_; 251 %parsedTags = (); 252 return readNames($namesFile, \%parsedTags, \&tagsHandler, $usePreprocessor); 253} 254 255sub 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 265sub 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. 273sub 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. 295sub 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. 312sub 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 323END 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 334sub 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 374sub 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 399sub svgCapitalizationHacks 400{ 401 my $name = shift; 402 403 $name = "FE" . ucfirst $1 if $name =~ /^fe(.+)$/; 404 405 return $name; 406} 407 408sub 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 421sub 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 456sub 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 500sub 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 510print F "#include \"config.h\"\n"; 511 512print F "#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC\n"; 513print F "#define DOM_$parameters{namespace}NAMES_HIDE_GLOBALS 1\n"; 514print F "#else\n"; 515print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n"; 516print F "#endif\n\n"; 517 518 519print F "#include \"$parameters{namespace}Names.h\"\n\n"; 520print F "#include <wtf/StaticConstructors.h>\n"; 521 522print F "namespace WebCore {\n\n namespace $parameters{namespace}Names { 523 524using namespace WebCore; 525 526DEFINE_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 562print 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 591sub 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 610sub 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 628sub 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 666sub 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 688sub printFactoryCppFile 689{ 690 my $cppPath = shift; 691 my $F; 692 open F, ">$cppPath"; 693 694printLicenseHeader($F); 695 696print F <<END 697#include "config.h" 698END 699; 700 701print F "\n#if $parameters{guardFactoryWith}\n\n" if $parameters{guardFactoryWith}; 702 703print F <<END 704#include "$parameters{namespace}ElementFactory.h" 705#include "$parameters{namespace}Names.h" 706END 707; 708 709printElementIncludes($F); 710 711print F "\n#include <wtf/HashMap.h>\n"; 712 713printConditionalElementIncludes($F); 714 715print F <<END 716 717#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(VIDEO) 718#include "Document.h" 719#include "Settings.h" 720#endif 721 722namespace WebCore { 723 724using namespace $parameters{namespace}Names; 725 726END 727; 728 729print F "typedef PassRefPtr<$parameters{namespace}Element> (*ConstructorFunction)(const QualifiedName&, Document*"; 730print F ", HTMLFormElement*" if $parameters{namespace} eq "HTML"; 731print F ", bool createdByParser);\n"; 732print F <<END 733typedef HashMap<AtomicStringImpl*, ConstructorFunction> FunctionMap; 734 735static FunctionMap* gFunctionMap = 0; 736 737END 738; 739 740my %tagConstructorMap = buildConstructorMap(); 741 742printConstructors($F, \%tagConstructorMap); 743 744print F <<END 745static void addTag(const QualifiedName& tag, ConstructorFunction func) 746{ 747 gFunctionMap->set(tag.localName().impl(), func); 748} 749 750static void createFunctionMap() 751{ 752 ASSERT(!gFunctionMap); 753 754 // Create the table. 755 gFunctionMap = new FunctionMap; 756 757 // Populate it with constructor functions. 758END 759; 760 761printFunctionInits($F, \%tagConstructorMap); 762 763print F "}\n"; 764 765print F "\nPassRefPtr<$parameters{namespace}Element> $parameters{namespace}ElementFactory::create$parameters{namespace}Element(const QualifiedName& qName, Document* document"; 766print F ", HTMLFormElement* formElement" if $parameters{namespace} eq "HTML"; 767print F ", bool createdByParser)\n{\n"; 768 769print F <<END 770 if (!document) 771 return 0; 772 773END 774; 775 776if ($parameters{namespace} ne "HTML") { 777print F <<END 778#if ENABLE(DASHBOARD_SUPPORT) 779 Settings* settings = document->settings(); 780 if (settings && settings->usesDashboardBackwardCompatibilityMode()) 781 return 0; 782#endif 783END 784; 785 786} 787 788print F <<END 789 if (!gFunctionMap) 790 createFunctionMap(); 791 if (ConstructorFunction function = gFunctionMap->get(qName.localName().impl())) 792END 793; 794 795if ($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 801print F " return $parameters{namespace}Element::create(qName, document);\n"; 802 803print F <<END 804} 805 806} // namespace WebCore 807 808END 809; 810 811 print F "#endif\n" if $parameters{guardFactoryWith}; 812 813 close F; 814} 815 816sub 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 831namespace WebCore { 832 class Element; 833 class Document; 834 class QualifiedName; 835} 836 837namespace WebCore { 838 839 class $parameters{namespace}Element; 840END 841; 842 843print F " class HTMLFormElement;\n" if $parameters{namespace} eq "HTML"; 844 845print 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); 851END 852; 853print F " static PassRefPtr<$parameters{namespace}Element> create$parameters{namespace}Element(const WebCore::QualifiedName&, WebCore::Document*"; 854print F ", HTMLFormElement* = 0" if $parameters{namespace} eq "HTML"; 855print F ", bool createdByParser = true);\n"; 856 857printf F<<END 858 }; 859} 860 861#endif // $parameters{namespace}ElementFactory_h 862 863END 864; 865 866 close F; 867} 868 869## Wrapper Factory routines 870 871sub 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 879sub 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 902static 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 910END 911; 912 } else { 913 print F <<END 914static 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 919END 920; 921 } 922 } elsif ($wrapperFactoryType eq "V8") { 923 if ($enabledTags{$tagName}{wrapperOnlyIfMediaIsAvailable}) { 924 print F <<END 925static 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 933END 934; 935 } else { 936 print F <<END 937static v8::Handle<v8::Value> create${JSInterfaceName}Wrapper($parameters{namespace}Element* element) 938{ 939 return toV8(static_cast<${JSInterfaceName}*>(element)); 940} 941 942 943END 944; 945 } 946 } 947 948 if ($conditional) { 949 print F "#endif\n\n"; 950 } 951 } 952} 953 954sub 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 986END 987; 988 989 if ($wrapperFactoryType eq "JS") { 990 print F <<END 991using namespace JSC; 992END 993; 994 } elsif ($wrapperFactoryType eq "V8") { 995 print F <<END 996#include "V8$parameters{namespace}Element.h" 997 998#include <v8.h> 999END 1000; 1001 } 1002 1003 print F <<END 1004 1005namespace WebCore { 1006 1007using namespace $parameters{namespace}Names; 1008 1009END 1010; 1011 if ($wrapperFactoryType eq "JS") { 1012 print F <<END 1013typedef JSNode* (*Create$parameters{namespace}ElementWrapperFunction)(ExecState*, JSDOMGlobalObject*, PassRefPtr<$parameters{namespace}Element>); 1014 1015END 1016; 1017 } elsif ($wrapperFactoryType eq "V8") { 1018 print F <<END 1019typedef v8::Handle<v8::Value> (*Create$parameters{namespace}ElementWrapperFunction)($parameters{namespace}Element*); 1020 1021END 1022; 1023 } 1024 1025 printWrapperFunctions($F, $wrapperFactoryType); 1026 1027 if ($wrapperFactoryType eq "JS") { 1028 print F <<END 1029JSNode* 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()) { 1034END 1035; 1036 } elsif ($wrapperFactoryType eq "V8") { 1037 print F <<END 1038v8::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()) { 1043END 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) 1069END 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()); 1075END 1076; 1077 } elsif ($wrapperFactoryType eq "V8") { 1078 print F <<END 1079 return createWrapperFunction(element); 1080 return V8$parameters{namespace}Element::wrap(element, forceNewObject); 1081END 1082; 1083 } 1084 print F <<END 1085} 1086 1087} 1088 1089END 1090; 1091 1092 print F "#endif\n" if $parameters{guardFactoryWith}; 1093 1094 close F; 1095} 1096 1097sub 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 1116namespace JSC { 1117 class ExecState; 1118} 1119 1120namespace 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 1130END 1131; 1132 } elsif ($wrapperFactoryType eq "V8") { 1133 print F <<END 1134#include <v8.h> 1135 1136namespace WebCore { 1137 1138 class $parameters{namespace}Element; 1139 1140 v8::Handle<v8::Value> createV8$parameters{namespace}Wrapper($parameters{namespace}Element*, bool); 1141} 1142END 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