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