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