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