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