Reviewed by Sam.
[WebKit-https.git] / WebCore / dom / make_names.pl
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1.  Redistributions of source code must retain the above copyright
10 #     notice, this list of conditions and the following disclaimer. 
11 # 2.  Redistributions in binary form must reproduce the above copyright
12 #     notice, this list of conditions and the following disclaimer in the
13 #     documentation and/or other materials provided with the distribution. 
14 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 #     its contributors may be used to endorse or promote products derived
16 #     from this software without specific prior written permission. 
17 #
18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 use strict;
30
31 use Config;
32 use Getopt::Long;
33 use File::Path;
34 use IO::File;
35 use Switch;
36 use XMLTiny qw(parsefile);
37
38 my $tagsFile = "";
39 my $attrsFile = "";
40 my $outputDir = ".";
41 my %tags = ();
42 my %attrs = ();
43 my %parameters = ();
44 my $extraDefines = 0;
45 my $preprocessor = "/usr/bin/gcc -E -P -x c++";
46 my %svgCustomMappings = ();
47 my %htmlCustomMappings = ();
48
49 GetOptions('tags=s' => \$tagsFile, 
50     'attrs=s' => \$attrsFile,
51     'outputDir=s' => \$outputDir,
52     'extraDefines=s' => \$extraDefines,
53     'preprocessor=s' => \$preprocessor);
54
55 die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile));
56
57 readNames($tagsFile) if length($tagsFile);
58 readNames($attrsFile) if length($attrsFile);
59
60 die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $parameters{'namespace'};
61 die "You must specify a namespaceURI (e.g. http://www.w3.org/2000/svg)" unless $parameters{'namespaceURI'};
62 die "You must specify a cppNamespace (e.g. DOM) used for <cppNamespace>::<namespace>Names::fooTag" unless $parameters{'cppNamespace'};
63
64 $parameters{'namespacePrefix'} = $parameters{'namespace'} unless $parameters{'namespacePrefix'};
65
66 mkpath($outputDir);
67 my $namesBasePath = "$outputDir/$parameters{'namespace'}Names";
68 my $factoryBasePath = "$outputDir/$parameters{'namespace'}ElementFactory";
69 my $wrapperFactoryBasePath = "$outputDir/JS$parameters{'namespace'}ElementWrapperFactory";
70
71 printNamesHeaderFile("$namesBasePath.h");
72 printNamesCppFile("$namesBasePath.cpp");
73
74 if ($parameters{'generateFactory'}) {
75     printFactoryCppFile("$factoryBasePath.cpp");
76     printFactoryHeaderFile("$factoryBasePath.h");
77 }
78
79 if ($parameters{'generateWrapperFactory'}) {
80     printWrapperFactoryCppFile("$wrapperFactoryBasePath.cpp");
81     printWrapperFactoryHeaderFile("$wrapperFactoryBasePath.h");
82 }
83
84 ### Hash initialization
85
86 sub initializeTagPropertyHash
87 {
88     return ('upperCase' => upperCaseName($_[0]),
89             'applyAudioHack' => 0,
90             'exportString' => 0);
91 }
92
93 sub initializeAttrPropertyHash
94 {
95     return ('upperCase' => upperCaseName($_[0]),
96             'exportString' => 0);
97 }
98
99 sub initializeParametersHash
100 {
101     return ('namespace' => '',
102             'namespacePrefix' => '',
103             'namespaceURI' => '',
104             'cppNamespace' => '',
105             'generateFactory' => 0,
106             'guardFactoryWith' => '',
107             'generateWrapperFactory' => 0,
108             # The 2 nullNamespace properties are generated from the "nullNamespace" attribute with respect to the file parsed (attrs or tags).
109             'tagsNullNamespace' => 0,
110             'attrsNullNamespace' => 0,
111             'exportStrings' => 0);
112 }
113
114 ### Parsing handlers
115
116 # Our files should have the following form :
117 # <'tags' or 'attrs' globalProperty1 = 'value1' ... />
118 # <'tag/attr name' 'property1' = 'value1' ... />
119 # where the properties are defined in the initialize*PropertyHash methods.
120 # (more tag/attr ...)
121 # </tags> or </attrs>
122
123 sub parseTags
124 {
125     my $contentsRef = shift;
126     foreach my $contentRef (@$contentsRef) {
127         my $tag = $${contentRef}{'name'};
128         $tag =~ s/-/_/g;
129
130         # Initialize default properties' values.
131         $tags{$tag} = { initializeTagPropertyHash($tag) } if !defined($tags{$tag});
132
133         # Parse the XML attributes.
134         my %properties = %{$$contentRef{'attrib'}};
135         foreach my $property (keys %properties) {
136             die "Unknown property $property for tag $tag\n" if !defined($tags{$tag}{$property});
137             $tags{$tag}{$property} = $properties{$property};
138         }
139     }
140 }
141
142 sub parseAttrs
143 {
144     my $contentsRef = shift;
145     foreach my $contentRef (@$contentsRef) {
146         my $attr = $${contentRef}{'name'};
147         $attr =~ s/-/_/g;
148
149         # Initialize default properties' values.
150         $attrs{$attr} = { initializeAttrPropertyHash($attr) } if !defined($attrs{$attr});
151
152         # Parse the XML attributes.
153         my %properties = %{$$contentRef{'attrib'}};
154         foreach my $property (keys %properties) {
155             die "Unknown property $property for attribute $attr\n" if !defined($attrs{$attr}{$property});
156             $attrs{$attr}{$property} = $properties{$property};
157         }
158     }
159 }
160
161 sub parseParameters
162 {
163     my ($propertiesRef, $elementName) = @_;
164     my %properties = %$propertiesRef;
165
166     # Initialize default properties' values.
167     %parameters = initializeParametersHash() if !(keys %parameters);
168
169     # Parse the XML attributes.
170     foreach my $property (keys %properties) {
171         # This is used in case we want to change the parameter name depending
172         # on what is parsed.
173         my $parameter = $property;
174
175         # "nullNamespace" case
176         if ($property eq "nullNamespace") {
177             $parameter = $elementName.(ucfirst $property);
178         }
179
180         die "Unknown parameter $property for tags/attrs\n" if !defined($parameters{$parameter});
181         $parameters{$parameter} = $properties{$property};
182     }
183 }
184
185 ## Support routines
186
187 sub readNames
188 {
189     my $namesFile = shift;
190
191     my $names = new IO::File;
192     if ($extraDefines eq 0) {
193         open($names, $preprocessor . " " . $namesFile . "|") or die "Failed to open file: $namesFile";
194     } else {
195         open($names, $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)) . " " . $namesFile . "|") or die "Failed to open file: $namesFile";
196     }
197
198     # Store hashes keys count to know if some insertion occured.
199     my $tagsCount = keys %tags;
200     my $attrsCount = keys %attrs;
201
202     my $documentRef = parsefile($names);
203
204     # XML::Tiny returns an array reference to a hash containing the different properties
205     my %document = %{@$documentRef[0]};
206     my $name = $document{'name'};
207
208     # Check root element to determine what we are parsing
209     switch($name) {
210         case "tags" {
211             parseParameters(\%{$document{'attrib'}}, $name);
212             parseTags(\@{$document{'content'}});
213         }
214         case "attrs" {
215             parseParameters(\%{$document{'attrib'}}, $name);
216             parseAttrs(\@{$document{'content'}});
217         } else {
218             die "Do not know how to parse file starting with $name!\n";
219         }
220     }
221
222     close($names);
223
224     die "Failed to read names from file: $namesFile" if ((keys %tags == $tagsCount) && (keys %attrs == $attrsCount));
225 }
226
227 sub printMacros
228 {
229     my ($F, $macro, $suffix, $namesRef) = @_;
230     my %names = %$namesRef;
231
232     for my $name (sort keys %$namesRef) {
233         print F "$macro $name","$suffix;\n";
234
235         if ($parameters{'exportStrings'} or $names{$name}{"exportString"}) { 
236             print F "extern char $name", "${suffix}String[];\n";
237         }
238     }
239 }
240
241 sub printConstructors
242 {
243     my ($F, $namesRef) = @_;
244     my %names = %$namesRef;
245
246     print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
247     for my $name (sort keys %names) {
248         my $ucName = $names{$name}{"upperCase"};
249
250         print F "$parameters{'namespace'}Element* ${name}Constructor(Document* doc, bool createdByParser)\n";
251         print F "{\n";
252         print F "    return new $parameters{'namespace'}${ucName}Element(${name}Tag, doc);\n";
253         print F "}\n\n";
254     }
255     print F "#endif\n" if $parameters{'guardFactoryWith'};
256 }
257
258 sub printFunctionInits
259 {
260     my ($F, $namesRef) = @_;
261     for my $name (sort keys %$namesRef) {
262         print F "    gFunctionMap->set(${name}Tag.localName().impl(), ${name}Constructor);\n";
263     }
264 }
265
266 sub svgCapitalizationHacks
267 {
268     my $name = shift;
269
270     if ($name =~ /^fe(.+)$/) {
271         $name = "FE" . ucfirst $1;
272     }
273
274     return $name;
275 }
276
277 sub upperCaseName
278 {
279     my $name = shift;
280     
281     $name = svgCapitalizationHacks($name) if ($parameters{'namespace'} eq "SVG");
282
283     while ($name =~ /^(.*?)_(.*)/) {
284         $name = $1 . ucfirst $2;
285     }
286     
287     return ucfirst $name;
288 }
289
290 sub printLicenseHeader
291 {
292     my $F = shift;
293     print F "/*
294  * THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT.
295  *
296  *
297  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
298  *
299  * Redistribution and use in source and binary forms, with or without
300  * modification, are permitted provided that the following conditions
301  * are met:
302  * 1. Redistributions of source code must retain the above copyright
303  *    notice, this list of conditions and the following disclaimer.
304  * 2. Redistributions in binary form must reproduce the above copyright
305  *    notice, this list of conditions and the following disclaimer in the
306  *    documentation and/or other materials provided with the distribution.
307  *
308  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
309  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
310  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
311  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
312  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
313  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
314  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
315  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
316  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
317  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
318  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
319  */
320
321
322 ";
323 }
324
325 sub printNamesHeaderFile
326 {
327     my ($headerPath) = shift;
328     my $F;
329     open F, ">$headerPath";
330     
331     printLicenseHeader($F);
332     print F "#ifndef DOM_$parameters{'namespace'}NAMES_H\n";
333     print F "#define DOM_$parameters{'namespace'}NAMES_H\n\n";
334     print F "#include \"QualifiedName.h\"\n\n";
335     
336     print F "namespace $parameters{'cppNamespace'} { namespace $parameters{'namespace'}Names {\n\n";
337     
338     my $lowerNamespace = lc($parameters{'namespacePrefix'});
339     print F "#ifndef DOM_$parameters{'namespace'}NAMES_HIDE_GLOBALS\n";
340     print F "// Namespace\n";
341     print F "extern const WebCore::AtomicString ${lowerNamespace}NamespaceURI;\n\n";
342
343     if (keys %tags) {
344         print F "// Tags\n";
345         printMacros($F, "extern const WebCore::QualifiedName", "Tag", \%tags);
346         print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Tags(size_t* size);\n";
347     }
348     
349     if (keys %attrs) {
350         print F "// Attributes\n";
351         printMacros($F, "extern const WebCore::QualifiedName", "Attr", \%attrs);
352         print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Attr(size_t* size);\n";
353     }
354     print F "#endif\n\n";
355     print F "void init();\n\n";
356     print F "} }\n\n";
357     print F "#endif\n\n";
358     
359     close F;
360 }
361
362 sub printNamesCppFile
363 {
364     my $cppPath = shift;
365     my $F;
366     open F, ">$cppPath";
367     
368     printLicenseHeader($F);
369     
370     my $lowerNamespace = lc($parameters{'namespacePrefix'});
371
372 print F "#include \"config.h\"\n";
373
374 print F "#ifdef AVOID_STATIC_CONSTRUCTORS\n";
375 print F "#define DOM_$parameters{'namespace'}NAMES_HIDE_GLOBALS 1\n";
376 print F "#else\n";
377 print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n";
378 print F "#endif\n\n";
379
380
381 print F "#include \"$parameters{'namespace'}Names.h\"\n\n";
382 print F "#include \"StaticConstructors.h\"\n";
383
384 print F "namespace $parameters{'cppNamespace'} { namespace $parameters{'namespace'}Names {
385
386 using namespace WebCore;
387
388 DEFINE_GLOBAL(AtomicString, ${lowerNamespace}NamespaceURI, \"$parameters{'namespaceURI'}\")
389 ";
390
391     if (keys %tags) {
392         print F "// Tags\n";
393         for my $name (sort keys %tags) {
394             print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Tag, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
395         }
396         
397         print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Tags(size_t* size)\n";
398         print F "{\n    static WebCore::QualifiedName* $parameters{'namespace'}Tags[] = {\n";
399         for my $name (sort keys %tags) {
400             print F "        (WebCore::QualifiedName*)&${name}Tag,\n";
401         }
402         print F "    };\n";
403         print F "    *size = ", scalar(keys %tags), ";\n";
404         print F "    return $parameters{'namespace'}Tags;\n";
405         print F "}\n";
406     }
407
408     if (keys %attrs) {
409         print F "\n// Attributes\n";
410         for my $name (sort keys %attrs) {
411             print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Attr, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
412         }
413         print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Attrs(size_t* size)\n";
414         print F "{\n    static WebCore::QualifiedName* $parameters{'namespace'}Attr[] = {\n";
415         for my $name (sort keys %attrs) {
416             print F "        (WebCore::QualifiedName*)&${name}Attr,\n";
417         }
418         print F "    };\n";
419         print F "    *size = ", scalar(keys %attrs), ";\n";
420         print F "    return $parameters{'namespace'}Attr;\n";
421         print F "}\n";
422     }
423
424     if (keys %tags) {
425         printDefinitionStrings($F, \%tags, "tags");
426     }
427
428     if (keys %attrs) {
429         printDefinitionStrings($F, \%attrs, "attributes");
430     }
431
432 print F "\nvoid init()
433 {
434     static bool initialized = false;
435     if (initialized)
436         return;
437     initialized = true;
438     
439     // Use placement new to initialize the globals.
440     
441     AtomicString::init();
442 ";
443     
444     print(F "    AtomicString ${lowerNamespace}NS(\"$parameters{'namespaceURI'}\");\n\n");
445
446     print(F "    // Namespace\n");
447     print(F "    new ((void*)&${lowerNamespace}NamespaceURI) AtomicString(${lowerNamespace}NS);\n\n");
448     if (keys %tags) {
449         my $tagsNamespace = $parameters{'tagsNullNamespace'} ? "nullAtom" : "${lowerNamespace}NS";
450         printDefinitions($F, \%tags, "tags", $tagsNamespace);
451     }
452     if (keys %attrs) {
453         my $attrsNamespace = $parameters{'attrsNullNamespace'} ? "nullAtom" : "${lowerNamespace}NS";
454         printDefinitions($F, \%attrs, "attributes", $attrsNamespace);
455     }
456
457     print F "}\n\n} }\n\n";
458     close F;
459 }
460
461 sub printJSElementIncludes
462 {
463     my ($F, $namesRef) = @_;
464     my %names = %$namesRef;
465     for my $name (sort keys %names) {
466         next if (hasCustomMapping($name));
467
468         my $ucName = $names{$name}{"upperCase"};
469         print F "#include \"JS$parameters{'namespace'}${ucName}Element.h\"\n";
470     }
471 }
472
473 sub printElementIncludes
474 {
475     my ($F, $namesRef, $shouldSkipCustomMappings) = @_;
476     my %names = %$namesRef;
477     for my $name (sort keys %names) {
478         next if ($shouldSkipCustomMappings && hasCustomMapping($name));
479
480         my $ucName = $names{$name}{"upperCase"};
481         print F "#include \"$parameters{'namespace'}${ucName}Element.h\"\n";
482     }
483 }
484
485 sub printDefinitionStrings
486 {
487     my ($F, $namesRef, $type) = @_;
488     my $singularType = substr($type, 0, -1);
489     my $shortType = substr($singularType, 0, 4);
490     my $shortCamelType = ucfirst($shortType);
491     print F "\n// " . ucfirst($type) . " as strings\n";
492
493     my %names = %$namesRef;
494     for my $name (sort keys %$namesRef) {
495         next if (!$parameters{'exportStrings'} and !$names{$name}{"exportString"});
496
497         my $realName = $name;
498         $realName =~ s/_/-/g;
499
500         print F "char $name","${shortCamelType}String[] = \"$realName\";\n";
501     }
502
503
504 sub printDefinitions
505 {
506     my ($F, $namesRef, $type, $namespaceURI) = @_;
507     my $singularType = substr($type, 0, -1);
508     my $shortType = substr($singularType, 0, 4);
509     my $shortCamelType = ucfirst($shortType);
510     my $shortUpperType = uc($shortType);
511     
512     print F "    // " . ucfirst($type) . "\n";
513
514     my %names = %$namesRef;
515     for my $name (sort keys %$namesRef) {
516         next if ($parameters{'exportStrings'} or $names{$name}{"exportString"});
517
518         my $realName = $name;
519         $realName =~ s/_/-/g;
520         print F "    const char *$name","${shortCamelType}String = \"$realName\";\n\n";
521     }
522
523     for my $name (sort keys %$namesRef) {
524         print F "    new ((void*)&$name","${shortCamelType}) QualifiedName(nullAtom, $name","${shortCamelType}String, $namespaceURI);\n";
525     }
526 }
527
528 ## ElementFactory routines
529
530 sub printFactoryCppFile
531 {
532     my $cppPath = shift;
533     my $F;
534     open F, ">$cppPath";
535
536 printLicenseHeader($F);
537
538 print F <<END
539 #include "config.h"
540 #include "$parameters{'namespace'}ElementFactory.h"
541 #include "$parameters{'namespace'}Names.h"
542 #include "Page.h"
543 #include "Settings.h"
544 END
545 ;
546
547 printElementIncludes($F, \%tags, 0);
548
549 print F <<END
550 #include <wtf/HashMap.h>
551
552 using namespace WebCore;
553 using namespace $parameters{'cppNamespace'}::$parameters{'namespace'}Names;
554
555 typedef $parameters{'namespace'}Element* (*ConstructorFunc)(Document* doc, bool createdByParser);
556 typedef WTF::HashMap<AtomicStringImpl*, ConstructorFunc> FunctionMap;
557
558 static FunctionMap* gFunctionMap = 0;
559
560 namespace $parameters{'cppNamespace'} {
561
562 END
563 ;
564
565 printConstructors($F, \%tags);
566
567 print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
568
569 print F <<END
570 static inline void createFunctionMapIfNecessary()
571 {
572     if (gFunctionMap)
573         return;
574     // Create the table.
575     gFunctionMap = new FunctionMap;
576     
577     // Populate it with constructor functions.
578 END
579 ;
580
581 printFunctionInits($F, \%tags);
582
583 print F "}\n";
584 print F "#endif\n\n" if $parameters{'guardFactoryWith'};
585
586 print F <<END
587 $parameters{'namespace'}Element* $parameters{'namespace'}ElementFactory::create$parameters{'namespace'}Element(const QualifiedName& qName, Document* doc, bool createdByParser)
588 {
589 END
590 ;
591
592 print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
593
594 print F <<END
595     // Don't make elements without a document
596     if (!doc)
597         return 0;
598
599 #if ENABLE(DASHBOARD_SUPPORT)
600     Settings* settings = doc->settings();
601     if (settings && settings->usesDashboardBackwardCompatibilityMode())
602         return 0;
603 #endif
604
605     createFunctionMapIfNecessary();
606     ConstructorFunc func = gFunctionMap->get(qName.localName().impl());
607     if (func)
608         return func(doc, createdByParser);
609
610     return new $parameters{'namespace'}Element(qName, doc);
611 END
612 ;
613
614 if ($parameters{'guardFactoryWith'}) {
615
616 print F <<END
617 #else
618     return 0;
619 #endif
620 END
621 ;
622
623 }
624
625 print F <<END
626 }
627
628 } // namespace
629
630 END
631 ;
632
633     close F;
634 }
635
636 sub printFactoryHeaderFile
637 {
638     my $headerPath = shift;
639     my $F;
640     open F, ">$headerPath";
641
642     printLicenseHeader($F);
643
644 print F "#ifndef $parameters{'namespace'}ELEMENTFACTORY_H\n";
645 print F "#define $parameters{'namespace'}ELEMENTFACTORY_H\n\n";
646
647 print F "
648 namespace WebCore {
649     class Element;
650     class Document;
651     class QualifiedName;
652     class AtomicString;
653 }
654
655 namespace $parameters{'cppNamespace'}
656 {
657     class $parameters{'namespace'}Element;
658
659     // The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense
660     // elements.  In a compound document world, the generic createElement function (will end up being virtual) will be called.
661     class $parameters{'namespace'}ElementFactory
662     {
663     public:
664         WebCore::Element* createElement(const WebCore::QualifiedName& qName, WebCore::Document* doc, bool createdByParser = true);
665         static $parameters{'namespace'}Element* create$parameters{'namespace'}Element(const WebCore::QualifiedName& qName, WebCore::Document* doc, bool createdByParser = true);
666     };
667 }
668
669 #endif
670
671 ";
672
673     close F;
674 }
675
676 ## Wrapper Factory routines
677
678 sub initializeCustomMappings
679 {
680     if (!keys %svgCustomMappings) {
681         # These are used to map a tag to another one in WrapperFactory
682         # (for example, "h2" is mapped to "h1" so that they use the same JS Wrapper ("h1" wrapper))
683         # Mapping to an empty string will not generate a wrapper
684         %svgCustomMappings = ('animateMotion' => '',
685                               'hkern' => '',
686                               'mpath' => '');
687         %htmlCustomMappings = ('abbr' => '',
688                                'acronym' => '',
689                                'address' => '',
690                                'b' => '',
691                                'bdo' => '',
692                                'big' => '',
693                                'center' => '',
694                                'cite' => '',
695                                'code' => '',
696                                'colgroup' => 'col',
697                                'dd' => '',
698                                'dfn' => '',
699                                'dt' => '',
700                                'em' => '',
701                                'h2' => 'h1',
702                                'h3' => 'h1',
703                                'h4' => 'h1',
704                                'h5' => 'h1',
705                                'h6' => 'h1',
706                                'i' => '',
707                                'image' => 'img',
708                                'ins' => 'del',
709                                'kbd' => '',
710                                'keygen' => 'select',
711                                'listing' => 'pre',
712                                'layer' => '',
713                                'nobr' => '',
714                                'noembed' => '',
715                                'noframes' => '',
716                                'nolayer' => '',
717                                'noscript' => '',
718                                'plaintext' => '',
719                                's' => '',
720                                'samp' => '',
721                                'small' => '',
722                                'span' => '',
723                                'strike' => '',
724                                'strong' => '',
725                                'sub' => '',
726                                'sup' => '',
727                                'tfoot' => 'tbody',
728                                'th' => 'td',
729                                'thead' => 'tbody',
730                                'tt' => '',
731                                'u' => '',
732                                'var' => '',
733                                'wbr' => '',
734                                'xmp' => 'pre');
735     }
736 }
737
738 sub hasCustomMapping
739 {
740     my $name = shift;
741     initializeCustomMappings();
742     return 1 if $parameters{'namespace'} eq "HTML" && exists($htmlCustomMappings{$name});
743     return 1 if $parameters{'namespace'} eq "SVG" && exists($svgCustomMappings{$name});
744     return 0;
745 }
746
747 sub printWrapperFunctions
748 {
749     my ($F, $namesRef) = @_;
750     my %names = %$namesRef;
751     for my $name (sort keys %names) {
752         # Custom mapping do not need a JS wrapper
753         next if (hasCustomMapping($name));
754
755         my $ucName = $names{$name}{"upperCase"};
756         # Hack for the media tags
757         if ($names{$name}{"applyAudioHack"}) {
758             print F <<END
759 static JSNode* create${ucName}Wrapper(ExecState* exec, PassRefPtr<$parameters{'namespace'}Element> element)
760 {
761     if (!MediaPlayer::isAvailable())
762         return new (exec) JS$parameters{'namespace'}Element(JS$parameters{'namespace'}ElementPrototype::self(exec), element.get());
763     return new (exec) JS$parameters{'namespace'}${ucName}Element(JS$parameters{'namespace'}${ucName}ElementPrototype::self(exec), static_cast<$parameters{'namespace'}${ucName}Element*>(element.get()));
764 }
765
766 END
767 ;
768         } else {
769             print F <<END
770 static JSNode* create${ucName}Wrapper(ExecState* exec, PassRefPtr<$parameters{'namespace'}Element> element)
771 {   
772     return new (exec) JS$parameters{'namespace'}${ucName}Element(JS$parameters{'namespace'}${ucName}ElementPrototype::self(exec), static_cast<$parameters{'namespace'}${ucName}Element*>(element.get()));
773 }
774
775 END
776 ;
777         }
778     }
779 }
780
781 sub printWrapperFactoryCppFile
782 {
783     my $cppPath = shift;
784     my $F;
785     open F, ">$cppPath";
786
787     printLicenseHeader($F);
788
789     print F "#include \"config.h\"\n\n";
790
791     print F "#if $parameters{'guardFactoryWith'}\n\n" if $parameters{'guardFactoryWith'};
792
793     print F "#include \"JS$parameters{'namespace'}ElementWrapperFactory.h\"\n";
794
795     printJSElementIncludes($F, \%tags);
796
797     print F "\n#include \"$parameters{'namespace'}Names.h\"\n\n";
798
799     printElementIncludes($F, \%tags, 1);
800
801     print F <<END
802 using namespace KJS;
803
804 namespace WebCore {
805
806 using namespace $parameters{'namespace'}Names;
807
808 typedef JSNode* (*Create$parameters{'namespace'}ElementWrapperFunction)(ExecState*, PassRefPtr<$parameters{'namespace'}Element>);
809
810 END
811 ;
812
813     printWrapperFunctions($F, \%tags);
814
815     print F <<END
816 JSNode* createJS$parameters{'namespace'}Wrapper(ExecState* exec, PassRefPtr<$parameters{'namespace'}Element> element)
817 {   
818     static HashMap<WebCore::AtomicStringImpl*, Create$parameters{'namespace'}ElementWrapperFunction> map;
819     if (map.isEmpty()) {
820 END
821 ;
822
823     for my $tag (sort keys %tags) {
824         next if (hasCustomMapping($tag));
825
826         my $ucTag = $tags{$tag}{"upperCase"};
827         print F "       map.set(${tag}Tag.localName().impl(), create${ucTag}Wrapper);\n";
828     }
829
830     if ($parameters{'namespace'} eq "HTML") {
831         for my $tag (sort keys %htmlCustomMappings) {
832             next if !$htmlCustomMappings{$tag};
833
834             my $ucCustomTag = $tags{$htmlCustomMappings{$tag}}{"upperCase"};
835             print F "       map.set(${tag}Tag.localName().impl(), create${ucCustomTag}Wrapper);\n";
836         }
837     }
838
839     # Currently SVG has no need to add custom map.set as it only has empty elements
840
841     print F <<END
842     }
843     Create$parameters{'namespace'}ElementWrapperFunction createWrapperFunction = map.get(element->localName().impl());
844     if (createWrapperFunction)
845         return createWrapperFunction(exec, element);
846     return new (exec) JS$parameters{'namespace'}Element(JS$parameters{'namespace'}ElementPrototype::self(exec), element.get());
847 }
848
849 }
850
851 END
852 ;
853
854     print F "#endif\n" if $parameters{'guardFactoryWith'};
855
856     close F;
857 }
858
859 sub printWrapperFactoryHeaderFile
860 {
861     my $headerPath = shift;
862     my $F;
863     open F, ">$headerPath";
864
865     printLicenseHeader($F);
866
867     print F "#ifndef JS$parameters{'namespace'}ElementWrapperFactory_h\n";
868     print F "#define JS$parameters{'namespace'}ElementWrapperFactory_h\n\n";
869
870     print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
871
872     print F <<END
873 #include <wtf/Forward.h>
874
875 namespace KJS {
876     class ExecState;
877 }                                            
878                                              
879 namespace WebCore {
880
881     class JSNode;
882     class $parameters{'namespace'}Element;
883
884     JSNode* createJS$parameters{'namespace'}Wrapper(KJS::ExecState*, PassRefPtr<$parameters{'namespace'}Element>);
885
886 }
887  
888 END
889 ;
890
891     print F "#endif // $parameters{'guardFactoryWith'}\n\n" if $parameters{'guardFactoryWith'};
892
893     print F "#endif // JS$parameters{'namespace'}ElementWrapperFactory_h\n";
894
895     close F;
896 }