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