Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / build / scripts / make_css_property_names.py
blobe733c25dd494488483ed06386ab5c0d0eb0b6cd9
1 #!/usr/bin/env python
3 import subprocess
4 import sys
6 import css_properties
7 import in_generator
8 import license
11 HEADER_TEMPLATE = """
12 %(license)s
14 #ifndef %(class_name)s_h
15 #define %(class_name)s_h
17 #include "core/css/parser/CSSParserMode.h"
18 #include "wtf/HashFunctions.h"
19 #include "wtf/HashTraits.h"
20 #include <string.h>
22 namespace WTF {
23 class AtomicString;
24 class String;
27 namespace blink {
29 enum CSSPropertyID {
30 CSSPropertyInvalid = 0,
31 %(property_enums)s
34 const int firstCSSProperty = %(first_property_id)s;
35 const int numCSSProperties = %(properties_count)s;
36 const int lastCSSProperty = %(last_property_id)d;
37 const int lastUnresolvedCSSProperty = %(last_unresolved_property_id)d;
38 const size_t maxCSSPropertyNameLength = %(max_name_length)d;
40 const char* getPropertyName(CSSPropertyID);
41 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID);
42 WTF::String getPropertyNameString(CSSPropertyID);
43 WTF::String getJSPropertyName(CSSPropertyID);
45 inline CSSPropertyID convertToCSSPropertyID(int value)
47 ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid);
48 return static_cast<CSSPropertyID>(value);
51 inline CSSPropertyID resolveCSSPropertyID(CSSPropertyID id)
53 return convertToCSSPropertyID(id & ~512);
56 inline bool isPropertyAlias(CSSPropertyID id) { return id & 512; }
58 CSSPropertyID unresolvedCSSPropertyID(const WTF::String&);
60 CSSPropertyID cssPropertyID(const WTF::String&);
62 } // namespace blink
64 namespace WTF {
65 template<> struct DefaultHash<blink::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
66 template<> struct HashTraits<blink::CSSPropertyID> : GenericHashTraits<blink::CSSPropertyID> {
67 static const bool emptyValueIsZero = true;
68 static void constructDeletedValue(blink::CSSPropertyID& slot, bool) { slot = static_cast<blink::CSSPropertyID>(blink::lastUnresolvedCSSProperty + 1); }
69 static bool isDeletedValue(blink::CSSPropertyID value) { return value == (blink::lastUnresolvedCSSProperty + 1); }
73 #endif // %(class_name)s_h
74 """
76 GPERF_TEMPLATE = """
77 %%{
78 %(license)s
80 #include "config.h"
81 #include "%(class_name)s.h"
82 #include "core/css/HashTools.h"
83 #include <string.h>
85 #include "wtf/ASCIICType.h"
86 #include "wtf/text/AtomicString.h"
87 #include "wtf/text/WTFString.h"
89 namespace blink {
90 static const char propertyNameStringsPool[] = {
91 %(property_name_strings)s
94 static const unsigned short propertyNameStringsOffsets[] = {
95 %(property_name_offsets)s
98 %%}
99 %%struct-type
100 struct Property;
101 %%omit-struct-type
102 %%language=C++
103 %%readonly-tables
104 %%global-table
105 %%compare-strncmp
106 %%define class-name %(class_name)sHash
107 %%define lookup-function-name findPropertyImpl
108 %%define hash-function-name property_hash_function
109 %%define slot-name nameOffset
110 %%define word-array-name property_word_list
111 %%enum
112 %%%%
113 %(property_to_enum_map)s
114 %%%%
115 const Property* findProperty(register const char* str, register unsigned int len)
117 return %(class_name)sHash::findPropertyImpl(str, len);
120 const char* getPropertyName(CSSPropertyID id)
122 ASSERT(id >= firstCSSProperty && id <= lastUnresolvedCSSProperty);
123 int index = id - firstCSSProperty;
124 return propertyNameStringsPool + propertyNameStringsOffsets[index];
127 const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
129 ASSERT(id >= firstCSSProperty && id <= lastUnresolvedCSSProperty);
130 int index = id - firstCSSProperty;
131 static AtomicString* propertyStrings = new AtomicString[lastUnresolvedCSSProperty]; // Intentionally never destroyed.
132 AtomicString& propertyString = propertyStrings[index];
133 if (propertyString.isNull()) {
134 const char* propertyName = propertyNameStringsPool + propertyNameStringsOffsets[index];
135 propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
137 return propertyString;
140 String getPropertyNameString(CSSPropertyID id)
142 // We share the StringImpl with the AtomicStrings.
143 return getPropertyNameAtomicString(id).string();
146 String getJSPropertyName(CSSPropertyID id)
148 char result[maxCSSPropertyNameLength + 1];
149 const char* cssPropertyName = getPropertyName(id);
150 const char* propertyNamePointer = cssPropertyName;
151 if (!propertyNamePointer)
152 return emptyString();
154 char* resultPointer = result;
155 while (char character = *propertyNamePointer++) {
156 if (character == '-') {
157 char nextCharacter = *propertyNamePointer++;
158 if (!nextCharacter)
159 break;
160 character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
162 *resultPointer++ = character;
164 *resultPointer = '\\0';
165 return String(result);
168 CSSPropertyID cssPropertyID(const String& string)
170 return resolveCSSPropertyID(unresolvedCSSPropertyID(string));
173 } // namespace blink
177 class CSSPropertyNamesWriter(css_properties.CSSProperties):
178 class_name = "CSSPropertyNames"
180 def __init__(self, in_file_path):
181 super(CSSPropertyNamesWriter, self).__init__(in_file_path)
182 self._outputs = {(self.class_name + ".h"): self.generate_header,
183 (self.class_name + ".cpp"): self.generate_implementation,
186 def _enum_declaration(self, property):
187 return " %(property_id)s = %(enum_value)s," % property
189 def generate_header(self):
190 return HEADER_TEMPLATE % {
191 'license': license.license_for_generated_cpp(),
192 'class_name': self.class_name,
193 'property_enums': "\n".join(map(self._enum_declaration, self._properties_including_aliases)),
194 'first_property_id': self._first_enum_value,
195 'properties_count': len(self._properties),
196 'last_property_id': self._first_enum_value + len(self._properties) - 1,
197 'last_unresolved_property_id': max(property["enum_value"] for property in self._properties_including_aliases),
198 'max_name_length': max(map(len, self._properties)),
201 def generate_implementation(self):
202 enum_value_to_name = {property['enum_value']: property['name'] for property in self._properties_including_aliases}
203 property_offsets = []
204 property_names = []
205 current_offset = 0
206 for enum_value in range(self._first_enum_value, max(enum_value_to_name) + 1):
207 property_offsets.append(current_offset)
208 if enum_value in enum_value_to_name:
209 name = enum_value_to_name[enum_value]
210 property_names.append(name)
211 current_offset += len(name) + 1
213 css_name_and_enum_pairs = [(property['name'], property['property_id']) for property in self._properties_including_aliases]
215 gperf_input = GPERF_TEMPLATE % {
216 'license': license.license_for_generated_cpp(),
217 'class_name': self.class_name,
218 'property_name_strings': '\n'.join(' "%s\\0"' % name for name in property_names),
219 'property_name_offsets': '\n'.join(' %d,' % offset for offset in property_offsets),
220 'property_to_enum_map': '\n'.join('%s, %s' % property for property in css_name_and_enum_pairs),
222 # FIXME: If we could depend on Python 2.7, we would use subprocess.check_output
223 gperf_args = [self.gperf_path, '--key-positions=*', '-P', '-n']
224 gperf_args.extend(['-m', '50']) # Pick best of 50 attempts.
225 gperf_args.append('-D') # Allow duplicate hashes -> More compact code.
226 gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
227 return gperf.communicate(gperf_input)[0]
230 if __name__ == "__main__":
231 in_generator.Maker(CSSPropertyNamesWriter).main(sys.argv)