• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#
11# 1.  Redistributions of source code must retain the above copyright
12#     notice, this list of conditions and the following disclaimer.
13# 2.  Redistributions in binary form must reproduce the above copyright
14#     notice, this list of conditions and the following disclaimer in the
15#     documentation and/or other materials provided with the distribution.
16# 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17#     its contributors may be used to endorse or promote products derived
18#     from this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31use strict;
32
33use Config;
34use Getopt::Long;
35use File::Path;
36use IO::File;
37use InFilesParser;
38use Switch;
39
40my $printFactory = 0;
41my $printWrapperFactory = 0;
42my $tagsFile = "";
43my $attrsFile = "";
44my $outputDir = ".";
45my %tags = ();
46my %attrs = ();
47my %parameters = ();
48my $extraDefines = 0;
49my $preprocessor = "/usr/bin/gcc -E -P -x c++";
50
51GetOptions('tags=s' => \$tagsFile,
52    'attrs=s' => \$attrsFile,
53    'factory' => \$printFactory,
54    'outputDir=s' => \$outputDir,
55    'extraDefines=s' => \$extraDefines,
56    'preprocessor=s' => \$preprocessor,
57    'wrapperFactory' => \$printWrapperFactory);
58
59die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile));
60
61readNames($tagsFile, "tags") if length($tagsFile);
62readNames($attrsFile, "attrs") if length($attrsFile);
63
64die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $parameters{'namespace'};
65die "You must specify a namespaceURI (e.g. http://www.w3.org/2000/svg)" unless $parameters{'namespaceURI'};
66
67$parameters{'namespacePrefix'} = $parameters{'namespace'} unless $parameters{'namespacePrefix'};
68
69mkpath($outputDir);
70my $namesBasePath = "$outputDir/$parameters{'namespace'}Names";
71my $factoryBasePath = "$outputDir/$parameters{'namespace'}ElementFactory";
72my $wrapperFactoryBasePath = "$outputDir/JS$parameters{'namespace'}ElementWrapperFactory";
73
74printNamesHeaderFile("$namesBasePath.h");
75printNamesCppFile("$namesBasePath.cpp");
76
77if ($printFactory) {
78    printFactoryCppFile("$factoryBasePath.cpp");
79    printFactoryHeaderFile("$factoryBasePath.h");
80}
81
82if ($printWrapperFactory) {
83    printWrapperFactoryCppFile("$wrapperFactoryBasePath.cpp");
84    printWrapperFactoryHeaderFile("$wrapperFactoryBasePath.h");
85}
86
87### Hash initialization
88
89sub initializeTagPropertyHash
90{
91    return ('constructorNeedsCreatedByParser' => 0,
92            'constructorNeedsFormElement' => 0,
93            'exportString' => 0,
94            'interfaceName' => defaultInterfaceName($_[0]),
95            # By default, the JSInterfaceName is the same as the interfaceName.
96            'JSInterfaceName' => defaultInterfaceName($_[0]),
97            'mapToTagName' => '',
98            'wrapperOnlyIfMediaIsAvailable' => 0,
99            'conditional' => 0);
100}
101
102sub initializeAttrPropertyHash
103{
104    return ('exportString' => 0);
105}
106
107sub initializeParametersHash
108{
109    return ('namespace' => '',
110            'namespacePrefix' => '',
111            'namespaceURI' => '',
112            'guardFactoryWith' => '',
113            'tagsNullNamespace' => 0,
114            'attrsNullNamespace' => 0,
115            'exportStrings' => 0);
116}
117
118sub defaultInterfaceName
119{
120    die "No namespace found" if !$parameters{'namespace'};
121    return $parameters{'namespace'} . upperCaseName($_[0]) . "Element"
122}
123
124### Parsing handlers
125
126sub tagsHandler
127{
128    my ($tag, $property, $value) = @_;
129
130    $tag =~ s/-/_/g;
131
132    # Initialize default properties' values.
133    $tags{$tag} = { initializeTagPropertyHash($tag) } if !defined($tags{$tag});
134
135    if ($property) {
136        die "Unknown property $property for tag $tag\n" if !defined($tags{$tag}{$property});
137        # The code rely on JSInterfaceName deriving from interfaceName to check for custom JSInterfaceName.
138        # So just override JSInterfaceName if it was not already set.
139        if ($property eq "interfaceName" && $tags{$tag}{'JSInterfaceName'} eq $tags{$tag}{'interfaceName'}) {
140                $tags{$tag}{'JSInterfaceName'} = $value;
141        }
142        $tags{$tag}{$property} = $value;
143    }
144}
145
146sub attrsHandler
147{
148    my ($attr, $property, $value) = @_;
149
150    $attr =~ s/-/_/g;
151
152    # Initialize default properties' values.
153    $attrs{$attr} = { initializeAttrPropertyHash($attr) } if !defined($attrs{$attr});
154
155    if ($property) {
156        die "Unknown property $property for attribute $attr\n" if !defined($attrs{$attr}{$property});
157        $attrs{$attr}{$property} = $value;
158    }
159}
160
161sub parametersHandler
162{
163    my ($parameter, $value) = @_;
164
165    # Initialize default properties' values.
166    %parameters = initializeParametersHash() if !(keys %parameters);
167
168    die "Unknown parameter $parameter for tags/attrs\n" if !defined($parameters{$parameter});
169    $parameters{$parameter} = $value;
170}
171
172## Support routines
173
174sub readNames
175{
176    my ($namesFile, $type) = @_;
177
178    my $names = new IO::File;
179
180    if ($extraDefines eq 0) {
181        open($names, $preprocessor . " " . $namesFile . "|") or die "Failed to open file: $namesFile";
182    } else {
183        open($names, $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)) . " " . $namesFile . "|") or die "Failed to open file: $namesFile";
184    }
185
186    # Store hashes keys count to know if some insertion occured.
187    my $tagsCount = keys %tags;
188    my $attrsCount = keys %attrs;
189
190    my $InParser = InFilesParser->new();
191
192    switch ($type) {
193        case "tags" {
194            $InParser->parse($names, \&parametersHandler, \&tagsHandler);
195        }
196        case "attrs" {
197            $InParser->parse($names, \&parametersHandler, \&attrsHandler);
198        }
199        else {
200            die "Do not know how to parse $type";
201        }
202    }
203
204    close($names);
205
206    die "Failed to read names from file: $namesFile" if ((keys %tags == $tagsCount) && (keys %attrs == $attrsCount));
207}
208
209sub printMacros
210{
211    my ($F, $macro, $suffix, $namesRef) = @_;
212    my %names = %$namesRef;
213
214    for my $name (sort keys %$namesRef) {
215        print F "$macro $name","$suffix;\n";
216
217        if ($parameters{'exportStrings'} or $names{$name}{"exportString"}) {
218            print F "extern char $name", "${suffix}String[];\n";
219        }
220    }
221}
222
223sub usesDefaultWrapper
224{
225    my $tagName = shift;
226    return $tagName eq $parameters{'namespace'} . "Element";
227}
228
229# Build a direct mapping from the tags to the Element to create, excluding
230# Element that have not constructor.
231sub buildConstructorMap
232{
233    my %tagConstructorMap = ();
234    for my $tagName (keys %tags) {
235        my $interfaceName = $tags{$tagName}{'interfaceName'};
236        next if (usesDefaultWrapper($interfaceName));
237
238        if ($tags{$tagName}{'mapToTagName'}) {
239            die "Cannot handle multiple mapToTagName for $tagName\n" if $tags{$tags{$tagName}{'mapToTagName'}}{'mapToTagName'};
240            $interfaceName = $tags{ $tags{$tagName}{'mapToTagName'} }{'interfaceName'};
241        }
242
243        # Chop the string to keep the interesting part.
244        $interfaceName =~ s/$parameters{'namespace'}(.*)Element/$1/;
245        $tagConstructorMap{$tagName} = lc($interfaceName);
246    }
247
248    return %tagConstructorMap;
249}
250
251# Helper method that print the constructor's signature avoiding
252# unneeded arguments.
253sub printConstructorSignature
254{
255    my ($F, $tagName, $constructorName, $constructorTagName) = @_;
256
257    print F "static PassRefPtr<$parameters{'namespace'}Element> ${constructorName}Constructor(const QualifiedName& $constructorTagName, Document* doc";
258    if ($parameters{'namespace'} eq "HTML") {
259        print F ", HTMLFormElement*";
260        if ($tags{$tagName}{'constructorNeedsFormElement'}) {
261            print F " formElement";
262        }
263    }
264    print F ", bool";
265    if ($tags{$tagName}{'constructorNeedsCreatedByParser'}) {
266        print F " createdByParser";
267    }
268    print F ")\n{\n";
269}
270
271# Helper method to dump the constructor interior and call the
272# Element constructor with the right arguments.
273# The variable names should be kept in sync with the previous method.
274sub printConstructorInterior
275{
276    my ($F, $tagName, $interfaceName, $constructorTagName) = @_;
277
278    # Handle media elements.
279    if ($tags{$tagName}{'wrapperOnlyIfMediaIsAvailable'}) {
280        print F <<END
281    if (!MediaPlayer::isAvailable())
282        return new HTMLElement($constructorTagName, doc);
283END
284;
285    }
286
287    # Now call the constructor with the right parameters.
288    print F "    return new ${interfaceName}($constructorTagName, doc";
289    if ($tags{$tagName}{'constructorNeedsFormElement'}) {
290        print F ", formElement";
291    }
292    if ($tags{$tagName}{'constructorNeedsCreatedByParser'}) {
293        print F ", createdByParser";
294    }
295    print F ");\n}\n\n";
296}
297
298sub printConstructors
299{
300    my ($F, $tagConstructorMapRef) = @_;
301    my %tagConstructorMap = %$tagConstructorMapRef;
302
303    print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
304
305    # This is to avoid generating the same constructor several times.
306    my %uniqueTags = ();
307    for my $tagName (sort keys %tagConstructorMap) {
308        my $interfaceName = $tags{$tagName}{'interfaceName'};
309
310        # Ignore the mapped tag
311        # FIXME: It could be moved inside this loop but was split for readibility.
312        next if (defined($uniqueTags{$interfaceName}) || $tags{$tagName}{'mapToTagName'});
313
314        $uniqueTags{$interfaceName} = '1';
315
316        my $conditional = $tags{$tagName}{"conditional"};
317        if ($conditional) {
318            my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
319            print F "#if ${conditionalString}\n\n";
320        }
321
322        printConstructorSignature($F, $tagName, $tagConstructorMap{$tagName}, "tagName");
323        printConstructorInterior($F, $tagName, $interfaceName, "tagName");
324
325        if ($conditional) {
326            print F "#endif\n\n";
327        }
328    }
329
330    # Mapped tag name uses a special wrapper to keep their prefix and namespaceURI while using the mapped localname.
331    for my $tagName (sort keys %tagConstructorMap) {
332        if ($tags{$tagName}{'mapToTagName'}) {
333            my $mappedName = $tags{$tagName}{'mapToTagName'};
334            printConstructorSignature($F, $mappedName, $mappedName . "To" . $tagName, "tagName");
335            printConstructorInterior($F, $mappedName, $tags{$mappedName}{'interfaceName'}, "QualifiedName(tagName.prefix(), ${mappedName}Tag.localName(), tagName.namespaceURI())");
336        }
337    }
338
339    print F "#endif\n" if $parameters{'guardFactoryWith'};
340}
341
342sub printFunctionInits
343{
344    my ($F, $tagConstructorMap) = @_;
345    my %tagConstructorMap = %$tagConstructorMap;
346
347    for my $tagName (sort keys %tagConstructorMap) {
348
349        my $conditional = $tags{$tagName}{"conditional"};
350        if ($conditional) {
351            my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
352            print F "#if ${conditionalString}\n";
353        }
354
355        if ($tags{$tagName}{'mapToTagName'}) {
356            print F "    addTag(${tagName}Tag, $tags{$tagName}{'mapToTagName'}To${tagName}Constructor);\n";
357        } else {
358            print F "    addTag(${tagName}Tag, $tagConstructorMap{$tagName}Constructor);\n";
359        }
360
361        if ($conditional) {
362            print F "#endif\n\n";
363        }
364    }
365}
366
367sub svgCapitalizationHacks
368{
369    my $name = shift;
370
371    if ($name =~ /^fe(.+)$/) {
372        $name = "FE" . ucfirst $1;
373    }
374
375    return $name;
376}
377
378sub upperCaseName
379{
380    my $name = shift;
381
382    $name = svgCapitalizationHacks($name) if ($parameters{'namespace'} eq "SVG");
383
384    while ($name =~ /^(.*?)_(.*)/) {
385        $name = $1 . ucfirst $2;
386    }
387
388    return ucfirst $name;
389}
390
391sub printLicenseHeader
392{
393    my $F = shift;
394    print F "/*
395 * THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT.
396 *
397 *
398 * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
399 *
400 * Redistribution and use in source and binary forms, with or without
401 * modification, are permitted provided that the following conditions
402 * are met:
403 * 1. Redistributions of source code must retain the above copyright
404 *    notice, this list of conditions and the following disclaimer.
405 * 2. Redistributions in binary form must reproduce the above copyright
406 *    notice, this list of conditions and the following disclaimer in the
407 *    documentation and/or other materials provided with the distribution.
408 *
409 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
410 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
411 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
412 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
413 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
414 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
415 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
416 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
417 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
418 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
419 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
420 */
421
422
423";
424}
425
426sub printNamesHeaderFile
427{
428    my ($headerPath) = shift;
429    my $F;
430    open F, ">$headerPath";
431
432    printLicenseHeader($F);
433    print F "#ifndef DOM_$parameters{'namespace'}NAMES_H\n";
434    print F "#define DOM_$parameters{'namespace'}NAMES_H\n\n";
435    print F "#include \"QualifiedName.h\"\n\n";
436
437    print F "namespace WebCore {\n\n namespace $parameters{'namespace'}Names {\n\n";
438
439    my $lowerNamespace = lc($parameters{'namespacePrefix'});
440    print F "#ifndef DOM_$parameters{'namespace'}NAMES_HIDE_GLOBALS\n";
441    print F "// Namespace\n";
442    print F "extern const WebCore::AtomicString ${lowerNamespace}NamespaceURI;\n\n";
443
444    if (keys %tags) {
445        print F "// Tags\n";
446        printMacros($F, "extern const WebCore::QualifiedName", "Tag", \%tags);
447    }
448
449    if (keys %attrs) {
450        print F "// Attributes\n";
451        printMacros($F, "extern const WebCore::QualifiedName", "Attr", \%attrs);
452    }
453    print F "#endif\n\n";
454
455    if (keys %tags) {
456        print F "WebCore::QualifiedName** get$parameters{'namespace'}Tags(size_t* size);\n";
457    }
458
459    if (keys %attrs) {
460        print F "WebCore::QualifiedName** get$parameters{'namespace'}Attrs(size_t* size);\n";
461    }
462
463    print F "\nvoid init();\n\n";
464    print F "} }\n\n";
465    print F "#endif\n\n";
466
467    close F;
468}
469
470sub printNamesCppFile
471{
472    my $cppPath = shift;
473    my $F;
474    open F, ">$cppPath";
475
476    printLicenseHeader($F);
477
478    my $lowerNamespace = lc($parameters{'namespacePrefix'});
479
480print F "#include \"config.h\"\n";
481
482print F "#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC\n";
483print F "#define DOM_$parameters{'namespace'}NAMES_HIDE_GLOBALS 1\n";
484print F "#else\n";
485print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n";
486print F "#endif\n\n";
487
488
489print F "#include \"$parameters{'namespace'}Names.h\"\n\n";
490print F "#include \"StaticConstructors.h\"\n";
491
492print F "namespace WebCore {\n\n namespace $parameters{'namespace'}Names {
493
494using namespace WebCore;
495
496DEFINE_GLOBAL(AtomicString, ${lowerNamespace}NamespaceURI, \"$parameters{'namespaceURI'}\")
497";
498
499    if (keys %tags) {
500        print F "// Tags\n";
501        for my $name (sort keys %tags) {
502            print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Tag, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
503        }
504
505        print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Tags(size_t* size)\n";
506        print F "{\n    static WebCore::QualifiedName* $parameters{'namespace'}Tags[] = {\n";
507        for my $name (sort keys %tags) {
508            print F "        (WebCore::QualifiedName*)&${name}Tag,\n";
509        }
510        print F "    };\n";
511        print F "    *size = ", scalar(keys %tags), ";\n";
512        print F "    return $parameters{'namespace'}Tags;\n";
513        print F "}\n";
514    }
515
516    if (keys %attrs) {
517        print F "\n// Attributes\n";
518        for my $name (sort keys %attrs) {
519            print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Attr, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
520        }
521        print F "\n\nWebCore::QualifiedName** get$parameters{'namespace'}Attrs(size_t* size)\n";
522        print F "{\n    static WebCore::QualifiedName* $parameters{'namespace'}Attr[] = {\n";
523        for my $name (sort keys %attrs) {
524            print F "        (WebCore::QualifiedName*)&${name}Attr,\n";
525        }
526        print F "    };\n";
527        print F "    *size = ", scalar(keys %attrs), ";\n";
528        print F "    return $parameters{'namespace'}Attr;\n";
529        print F "}\n";
530    }
531
532    if (keys %tags) {
533        printDefinitionStrings($F, \%tags, "tags");
534    }
535
536    if (keys %attrs) {
537        printDefinitionStrings($F, \%attrs, "attributes");
538    }
539
540print F "\nvoid init()
541{
542    static bool initialized = false;
543    if (initialized)
544        return;
545    initialized = true;
546
547    // Use placement new to initialize the globals.
548
549    AtomicString::init();
550";
551
552    print(F "    AtomicString ${lowerNamespace}NS(\"$parameters{'namespaceURI'}\");\n\n");
553
554    print(F "    // Namespace\n");
555    print(F "    new ((void*)&${lowerNamespace}NamespaceURI) AtomicString(${lowerNamespace}NS);\n\n");
556    if (keys %tags) {
557        my $tagsNamespace = $parameters{'tagsNullNamespace'} ? "nullAtom" : "${lowerNamespace}NS";
558        printDefinitions($F, \%tags, "tags", $tagsNamespace);
559    }
560    if (keys %attrs) {
561        my $attrsNamespace = $parameters{'attrsNullNamespace'} ? "nullAtom" : "${lowerNamespace}NS";
562        printDefinitions($F, \%attrs, "attributes", $attrsNamespace);
563    }
564
565    print F "}\n\n} }\n\n";
566    close F;
567}
568
569sub printJSElementIncludes
570{
571    my $F = shift;
572
573    my %tagsSeen;
574    for my $tagName (sort keys %tags) {
575        my $JSInterfaceName = $tags{$tagName}{"JSInterfaceName"};
576        next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName);
577        $tagsSeen{$JSInterfaceName} = 1;
578
579        print F "#include \"JS${JSInterfaceName}.h\"\n";
580    }
581}
582
583sub printElementIncludes
584{
585    my $F = shift;
586
587    my %tagsSeen;
588    for my $tagName (sort keys %tags) {
589        my $interfaceName = $tags{$tagName}{"interfaceName"};
590        next if defined($tagsSeen{$interfaceName});
591        $tagsSeen{$interfaceName} = 1;
592
593        print F "#include \"${interfaceName}.h\"\n";
594    }
595}
596
597sub printDefinitionStrings
598{
599    my ($F, $namesRef, $type) = @_;
600    my $singularType = substr($type, 0, -1);
601    my $shortType = substr($singularType, 0, 4);
602    my $shortCamelType = ucfirst($shortType);
603    print F "\n// " . ucfirst($type) . " as strings\n";
604
605    my %names = %$namesRef;
606    for my $name (sort keys %$namesRef) {
607        next if (!$parameters{'exportStrings'} and !$names{$name}{"exportString"});
608
609        my $realName = $name;
610        $realName =~ s/_/-/g;
611
612        print F "char $name","${shortCamelType}String[] = \"$realName\";\n";
613    }
614}
615
616sub printDefinitions
617{
618    my ($F, $namesRef, $type, $namespaceURI) = @_;
619    my $singularType = substr($type, 0, -1);
620    my $shortType = substr($singularType, 0, 4);
621    my $shortCamelType = ucfirst($shortType);
622    my $shortUpperType = uc($shortType);
623
624    print F "    // " . ucfirst($type) . "\n";
625
626    my %names = %$namesRef;
627    for my $name (sort keys %$namesRef) {
628        next if ($parameters{'exportStrings'} or $names{$name}{"exportString"});
629
630        my $realName = $name;
631        $realName =~ s/_/-/g;
632        print F "    const char *$name","${shortCamelType}String = \"$realName\";\n";
633    }
634
635    print "\n";
636
637    for my $name (sort keys %$namesRef) {
638        print F "    new ((void*)&$name","${shortCamelType}) QualifiedName(nullAtom, $name","${shortCamelType}String, $namespaceURI);\n";
639    }
640}
641
642## ElementFactory routines
643
644sub printFactoryCppFile
645{
646    my $cppPath = shift;
647    my $F;
648    open F, ">$cppPath";
649
650printLicenseHeader($F);
651
652print F <<END
653#include "config.h"
654#include "$parameters{'namespace'}ElementFactory.h"
655
656#include "$parameters{'namespace'}Names.h"
657#if ENABLE(DASHBOARD_SUPPORT)
658#include "Document.h"
659#include "Settings.h"
660#endif
661
662END
663;
664
665if ($parameters{'namespace'} eq "HTML") {
666    print F "#include \"HTMLFormElement.h\"\n";
667}
668
669printElementIncludes($F);
670
671print F <<END
672#include <wtf/HashMap.h>
673
674namespace WebCore {
675
676using namespace $parameters{'namespace'}Names;
677
678END
679;
680
681print F "typedef PassRefPtr<$parameters{'namespace'}Element> (*ConstructorFunction)(const QualifiedName&, Document*";
682
683if ($parameters{'namespace'} eq "HTML") {
684    print F ", HTMLFormElement*";
685}
686
687print F ", bool createdByParser);\n";
688print F <<END
689typedef HashMap<AtomicStringImpl*, ConstructorFunction> FunctionMap;
690
691static FunctionMap* gFunctionMap = 0;
692
693END
694;
695
696my %tagConstructorMap = buildConstructorMap();
697
698printConstructors($F, \%tagConstructorMap);
699
700print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
701
702print F <<END
703static void addTag(const QualifiedName& tag, ConstructorFunction func)
704{
705    gFunctionMap->set(tag.localName().impl(), func);
706}
707
708static inline void createFunctionMapIfNecessary()
709{
710    if (gFunctionMap)
711        return;
712    // Create the table.
713    gFunctionMap = new FunctionMap;
714
715    // Populate it with constructor functions.
716END
717;
718
719printFunctionInits($F, \%tagConstructorMap);
720
721print F "}\n";
722print F "#endif\n" if $parameters{'guardFactoryWith'};
723
724print F "\nPassRefPtr<$parameters{'namespace'}Element> $parameters{'namespace'}ElementFactory::create$parameters{'namespace'}Element(const QualifiedName& qName, Document* doc";
725
726if ($parameters{"namespace"} eq "HTML") {
727    print F ", HTMLFormElement* formElement";
728}
729
730print F ", bool createdByParser)\n{\n";
731
732print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
733
734print F <<END
735    // Don't make elements without a document
736    if (!doc)
737        return 0;
738
739END
740;
741
742if ($parameters{'namespace'} ne "HTML") {
743print F <<END
744#if ENABLE(DASHBOARD_SUPPORT)
745    Settings* settings = doc->settings();
746    if (settings && settings->usesDashboardBackwardCompatibilityMode())
747        return 0;
748#endif
749END
750;
751
752}
753
754print F <<END
755    createFunctionMapIfNecessary();
756    ConstructorFunction func = gFunctionMap->get(qName.localName().impl());
757    if (func)
758END
759;
760
761if ($parameters{"namespace"} eq "HTML") {
762    print F "        return func(qName, doc, formElement, createdByParser);\n";
763} else {
764    print F "        return func(qName, doc, createdByParser);\n";
765}
766
767print F "    return new $parameters{'namespace'}Element(qName, doc);\n";
768
769if ($parameters{'guardFactoryWith'}) {
770
771print F <<END
772#else
773    return 0;
774#endif
775END
776;
777
778}
779
780print F <<END
781}
782
783} // namespace WebCore
784
785END
786;
787
788    close F;
789}
790
791sub printFactoryHeaderFile
792{
793    my $headerPath = shift;
794    my $F;
795    open F, ">$headerPath";
796
797    printLicenseHeader($F);
798
799    print F<<END
800#ifndef $parameters{'namespace'}ElementFactory_h
801#define $parameters{'namespace'}ElementFactory_h
802
803#include <wtf/PassRefPtr.h>
804
805namespace WebCore {
806    class Element;
807    class Document;
808    class QualifiedName;
809    class AtomicString;
810}
811
812namespace WebCore {
813
814    class $parameters{'namespace'}Element;
815END
816;
817
818if ($parameters{'namespace'} eq "HTML") {
819    print F "     class HTMLFormElement;\n";
820}
821
822print F<<END
823    // The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense
824    // elements. In a compound document world, the generic createElement function (will end up being virtual) will be called.
825    class $parameters{'namespace'}ElementFactory {
826    public:
827        PassRefPtr<Element> createElement(const WebCore::QualifiedName&, WebCore::Document*, bool createdByParser = true);
828END
829;
830print F "        static PassRefPtr<$parameters{'namespace'}Element> create$parameters{'namespace'}Element(const WebCore::QualifiedName&, WebCore::Document*";
831
832if ($parameters{'namespace'} eq "HTML") {
833    print F ", HTMLFormElement* = 0";
834}
835
836print F ", bool /*createdByParser*/ = true);\n";
837
838printf F<<END
839    };
840}
841
842#endif // $parameters{'namespace'}ElementFactory_h
843
844END
845;
846
847    close F;
848}
849
850## Wrapper Factory routines
851
852sub usesDefaultJSWrapper
853{
854    my $name = shift;
855
856    # A tag reuses the default wrapper if its JSInterfaceName matches the default namespace Element.
857    return $tags{$name}{'JSInterfaceName'} eq $parameters{"namespace"} . "Element" || $tags{$name}{'JSInterfaceName'} eq "HTMLNoScriptElement";
858}
859
860sub printWrapperFunctions
861{
862    my $F = shift;
863
864    my %tagsSeen;
865    for my $tagName (sort keys %tags) {
866        # Avoid defining the same wrapper method twice.
867        my $JSInterfaceName = $tags{$tagName}{"JSInterfaceName"};
868        next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName);
869        $tagsSeen{$JSInterfaceName} = 1;
870
871        my $conditional = $tags{$tagName}{"conditional"};
872        if ($conditional) {
873            my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
874            print F "#if ${conditionalString}\n\n";
875        }
876
877        # Hack for the media tags
878        # FIXME: This should have been done via a CustomWrapper attribute and a separate *Custom file.
879        if ($tags{$tagName}{"wrapperOnlyIfMediaIsAvailable"}) {
880            print F <<END
881static JSNode* create${JSInterfaceName}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{'namespace'}Element> element)
882{
883    if (!MediaPlayer::isAvailable())
884        return CREATE_DOM_NODE_WRAPPER(exec, globalObject, $parameters{'namespace'}Element, element.get());
885    return CREATE_DOM_NODE_WRAPPER(exec, globalObject, ${JSInterfaceName}, element.get());
886}
887
888END
889;
890        } else {
891            print F <<END
892static JSNode* create${JSInterfaceName}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{'namespace'}Element> element)
893{
894    return CREATE_DOM_NODE_WRAPPER(exec, globalObject, ${JSInterfaceName}, element.get());
895}
896
897END
898;
899        }
900        if ($conditional) {
901            print F "#endif\n\n";
902        }
903    }
904}
905
906sub printWrapperFactoryCppFile
907{
908    my $cppPath = shift;
909    my $F;
910    open F, ">$cppPath";
911
912    printLicenseHeader($F);
913
914    print F "#include \"config.h\"\n\n";
915
916    print F "#if $parameters{'guardFactoryWith'}\n\n" if $parameters{'guardFactoryWith'};
917
918    print F "#include \"JS$parameters{'namespace'}ElementWrapperFactory.h\"\n";
919
920    printJSElementIncludes($F);
921
922    print F "\n#include \"$parameters{'namespace'}Names.h\"\n\n";
923
924    printElementIncludes($F);
925
926    print F "\n#include <wtf/StdLibExtras.h>\n\n";
927
928    print F <<END
929using namespace JSC;
930
931namespace WebCore {
932
933using namespace $parameters{'namespace'}Names;
934
935typedef JSNode* (*Create$parameters{'namespace'}ElementWrapperFunction)(ExecState*, JSDOMGlobalObject*, PassRefPtr<$parameters{'namespace'}Element>);
936
937END
938;
939
940    printWrapperFunctions($F);
941
942    print F <<END
943JSNode* createJS$parameters{'namespace'}Wrapper(ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<$parameters{'namespace'}Element> element)
944{
945    typedef HashMap<WebCore::AtomicStringImpl*, Create$parameters{'namespace'}ElementWrapperFunction> FunctionMap;
946    DEFINE_STATIC_LOCAL(FunctionMap, map, ());
947    if (map.isEmpty()) {
948END
949;
950
951    for my $tag (sort keys %tags) {
952        # Do not add the name to the map if it does not have a JS wrapper constructor or uses the default wrapper.
953        next if usesDefaultJSWrapper($tag, \%tags);
954
955        my $conditional = $tags{$tag}{"conditional"};
956        if ($conditional) {
957            my $conditionalString = "ENABLE(" . join(") && ENABLE(", split(/&/, $conditional)) . ")";
958            print F "#if ${conditionalString}\n";
959        }
960
961        my $ucTag = $tags{$tag}{"JSInterfaceName"};
962        print F "       map.set(${tag}Tag.localName().impl(), create${ucTag}Wrapper);\n";
963
964        if ($conditional) {
965            print F "#endif\n";
966        }
967    }
968
969    print F <<END
970    }
971    Create$parameters{'namespace'}ElementWrapperFunction createWrapperFunction = map.get(element->localName().impl());
972    if (createWrapperFunction)
973        return createWrapperFunction(exec, globalObject, element);
974    return CREATE_DOM_NODE_WRAPPER(exec, globalObject, $parameters{'namespace'}Element, element.get());
975}
976
977}
978
979END
980;
981
982    print F "#endif\n" if $parameters{'guardFactoryWith'};
983
984    close F;
985}
986
987sub printWrapperFactoryHeaderFile
988{
989    my $headerPath = shift;
990    my $F;
991    open F, ">$headerPath";
992
993    printLicenseHeader($F);
994
995    print F "#ifndef JS$parameters{'namespace'}ElementWrapperFactory_h\n";
996    print F "#define JS$parameters{'namespace'}ElementWrapperFactory_h\n\n";
997
998    print F "#if $parameters{'guardFactoryWith'}\n" if $parameters{'guardFactoryWith'};
999
1000    print F <<END
1001#include <wtf/Forward.h>
1002
1003namespace JSC {
1004    class ExecState;
1005}
1006
1007namespace WebCore {
1008
1009    class JSNode;
1010    class JSDOMGlobalObject;
1011    class $parameters{'namespace'}Element;
1012
1013    JSNode* createJS$parameters{'namespace'}Wrapper(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<$parameters{'namespace'}Element>);
1014
1015}
1016
1017END
1018;
1019
1020    print F "#endif // $parameters{'guardFactoryWith'}\n\n" if $parameters{'guardFactoryWith'};
1021
1022    print F "#endif // JS$parameters{'namespace'}ElementWrapperFactory_h\n";
1023
1024    close F;
1025}
1026