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 # 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, \&parametersHandler, $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