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