1#! /usr/bin/perl
2#
3#   This file is part of the WebKit project
4#
5#   Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
6#   Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved.
7#   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
8#   Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
9#
10#   This library is free software; you can redistribute it and/or
11#   modify it under the terms of the GNU Library General Public
12#   License as published by the Free Software Foundation; either
13#   version 2 of the License, or (at your option) any later version.
14#
15#   This library is distributed in the hope that it will be useful,
16#   but WITHOUT ANY WARRANTY; without even the implied warranty of
17#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18#   Library General Public License for more details.
19#
20#   You should have received a copy of the GNU Library General Public License
21#   along with this library; see the file COPYING.LIB.  If not, write to
22#   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23#   Boston, MA 02110-1301, USA.
24use Getopt::Long;
25use preprocessor;
26use strict;
27use warnings;
28
29my $defines;
30my $preprocessor;
31GetOptions('defines=s' => \$defines,
32           'preprocessor=s' => \$preprocessor);
33
34my @NAMES = applyPreprocessor("CSSPropertyNames.in", $defines, $preprocessor);
35die "We've reached more than 1024 CSS properties, please make sure to update CSSProperty/StylePropertyMetadata accordingly" if (scalar(@NAMES) > 1024);
36
37my %namesHash;
38my @duplicates = ();
39
40my $numPredefinedProperties = 1;
41my @names = ();
42my %nameIsInherited;
43my %nameToId;
44my @aliases = ();
45foreach (@NAMES) {
46  next if (m/(^\s*$)/);
47  next if (/^#/);
48
49  # Input may use a different EOL sequence than $/, so avoid chomp.
50  $_ =~ s/\s*\[(.+?)\]\r?$//;
51  my @options = ();
52  if ($1) {
53    @options = split(/\s*,\s*/, $1);
54  }
55
56  $_ =~ s/[\r\n]+$//g;
57  if (exists $namesHash{$_}) {
58    push @duplicates, $_;
59  } else {
60    $namesHash{$_} = 1;
61  }
62  if ($_ =~ /=/) {
63    if (@options) {
64        die "Options are specified on an alias $_: ", join(", ", @options) . "\n";
65    }
66    push @aliases, $_;
67  } else {
68    $nameIsInherited{$_} = 0;
69    foreach my $option (@options) {
70      if ($option eq "Inherited") {
71        $nameIsInherited{$_} = 1;
72      }
73    }
74
75    my $id = $_;
76    $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge;
77    $nameToId{$_} = $id;
78
79    push @names, $_;
80  }
81}
82
83if (@duplicates > 0) {
84    die 'Duplicate CSS property names: ', join(', ', @duplicates) . "\n";
85}
86
87open GPERF, ">CSSPropertyNames.gperf" || die "Could not open CSSPropertyNames.gperf for writing";
88print GPERF << "EOF";
89%{
90/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
91#include "config.h"
92#include \"CSSProperty.h\"
93#include \"CSSPropertyNames.h\"
94#include \"HashTools.h\"
95#include <string.h>
96
97#include <wtf/ASCIICType.h>
98#include <wtf/text/AtomicString.h>
99#include <wtf/text/WTFString.h>
100
101#if defined(__clang__)
102#pragma clang diagnostic push
103#pragma clang diagnostic ignored \"-Wunknown-pragmas\"
104#pragma clang diagnostic ignored \"-Wdeprecated-register\"
105#pragma clang diagnostic ignored \"-Wimplicit-fallthrough\"
106#endif
107
108namespace WebCore {
109EOF
110
111print GPERF "const char* const propertyNameStrings[numCSSProperties] = {\n";
112foreach my $name (@names) {
113  print GPERF "    \"$name\",\n";
114}
115print GPERF "};\n\n";
116
117print GPERF << "EOF";
118%}
119%struct-type
120struct Property;
121%omit-struct-type
122%language=C++
123%readonly-tables
124%global-table
125%compare-strncmp
126%define class-name CSSPropertyNamesHash
127%define lookup-function-name findPropertyImpl
128%define hash-function-name propery_hash_function
129%define word-array-name property_wordlist
130%enum
131%%
132EOF
133
134foreach my $name (@names) {
135  print GPERF $name . ", CSSProperty" . $nameToId{$name} . "\n";
136}
137
138foreach my $alias (@aliases) {
139  $alias =~ /^([^\s]*)[\s]*=[\s]*([^\s]*)/;
140  my $name = $1;
141  print GPERF $name . ", CSSProperty" . $nameToId{$2} . "\n";
142}
143
144print GPERF<< "EOF";
145%%
146const Property* findProperty(const char* str, unsigned int len)
147{
148    return CSSPropertyNamesHash::findPropertyImpl(str, len);
149}
150
151const char* getPropertyName(CSSPropertyID id)
152{
153    if (id < firstCSSProperty)
154        return 0;
155    int index = id - firstCSSProperty;
156    if (index >= numCSSProperties)
157        return 0;
158    return propertyNameStrings[index];
159}
160
161const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
162{
163    if (id < firstCSSProperty)
164        return nullAtom;
165    int index = id - firstCSSProperty;
166    if (index >= numCSSProperties)
167        return nullAtom;
168
169    static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
170    AtomicString& propertyString = propertyStrings[index];
171    if (propertyString.isNull()) {
172        const char* propertyName = propertyNameStrings[index];
173        propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
174    }
175    return propertyString;
176}
177
178String getPropertyNameString(CSSPropertyID id)
179{
180    // We share the StringImpl with the AtomicStrings.
181    return getPropertyNameAtomicString(id).string();
182}
183
184String getJSPropertyName(CSSPropertyID id)
185{
186    char result[maxCSSPropertyNameLength + 1];
187    const char* cssPropertyName = getPropertyName(id);
188    const char* propertyNamePointer = cssPropertyName;
189    if (!propertyNamePointer)
190        return emptyString();
191
192    char* resultPointer = result;
193    while (char character = *propertyNamePointer++) {
194        if (character == '-') {
195            char nextCharacter = *propertyNamePointer++;
196            if (!nextCharacter)
197                break;
198            character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
199        }
200        *resultPointer++ = character;
201    }
202    *resultPointer = '\\0';
203    return WTF::String(result);
204}
205
206static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
207    false, // CSSPropertyInvalid
208EOF
209
210foreach my $name (@names) {
211  my $id = $nameToId{$name};
212  my $value = $nameIsInherited{$name} ? "true " : "false";
213  print GPERF "    $value, // CSSProperty$id\n";
214}
215
216print GPERF<< "EOF";
217};
218
219bool CSSProperty::isInheritedProperty(CSSPropertyID id)
220{
221    ASSERT(id >= 0 && id <= lastCSSProperty);
222    ASSERT(id != CSSPropertyInvalid);
223    return isInheritedPropertyTable[id];
224}
225
226} // namespace WebCore
227
228#if defined(__clang__)
229#pragma clang diagnostic pop
230#endif
231EOF
232
233open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing";
234print HEADER << "EOF";
235/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
236
237#ifndef CSSPropertyNames_h
238#define CSSPropertyNames_h
239
240#include <string.h>
241#include <wtf/HashFunctions.h>
242#include <wtf/HashTraits.h>
243
244namespace WTF {
245class AtomicString;
246class String;
247}
248
249namespace WebCore {
250
251enum CSSPropertyID {
252    CSSPropertyInvalid = 0,
253EOF
254
255my $first = $numPredefinedProperties;
256my $i = $numPredefinedProperties;
257my $maxLen = 0;
258foreach my $name (@names) {
259  print HEADER "    CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
260  $i = $i + 1;
261  if (length($name) > $maxLen) {
262    $maxLen = length($name);
263  }
264}
265my $num = $i - $first;
266my $last = $i - 1;
267
268print HEADER "};\n\n";
269print HEADER "const int firstCSSProperty = $first;\n";
270print HEADER "const int numCSSProperties = $num;\n";
271print HEADER "const int lastCSSProperty = $last;\n";
272print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
273
274print HEADER << "EOF";
275
276const char* getPropertyName(CSSPropertyID);
277const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
278WTF::String getPropertyNameString(CSSPropertyID id);
279WTF::String getJSPropertyName(CSSPropertyID);
280
281inline CSSPropertyID convertToCSSPropertyID(int value)
282{
283    ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid);
284    return static_cast<CSSPropertyID>(value);
285}
286
287} // namespace WebCore
288
289namespace WTF {
290template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
291template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
292    static const bool emptyValueIsZero = true;
293    static const bool needsDestruction = false;
294    static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
295    static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
296};
297}
298
299#endif // CSSPropertyNames_h
300
301EOF
302
303close HEADER;
304
305my $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
306system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";
307