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