8 from in_file import InFile
16 #ifndef %(class_name)s_h
17 #define %(class_name)s_h
19 #include "core/css/CSSParserMode.h"
20 #include "wtf/HashFunctions.h"
21 #include "wtf/HashTraits.h"
32 CSSPropertyInvalid = 0,
36 const int firstCSSProperty = %(first_property_id)s;
37 const int numCSSProperties = %(properties_count)s;
38 const int lastCSSProperty = %(last_property_id)d;
39 const size_t maxCSSPropertyNameLength = %(max_name_length)d;
41 const char* getPropertyName(CSSPropertyID);
42 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID);
43 WTF::String getPropertyNameString(CSSPropertyID);
44 WTF::String getJSPropertyName(CSSPropertyID);
45 bool isInternalProperty(CSSPropertyID id);
47 inline CSSPropertyID convertToCSSPropertyID(int value)
49 ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid);
50 return static_cast<CSSPropertyID>(value);
53 } // namespace WebCore
56 template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
57 template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
58 static const bool emptyValueIsZero = true;
59 static const bool needsDestruction = false;
60 static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
61 static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
65 #endif // %(class_name)s_h
73 #include "%(class_name)s.h"
74 #include "core/css/HashTools.h"
77 #include "wtf/ASCIICType.h"
78 #include "wtf/text/AtomicString.h"
79 #include "wtf/text/WTFString.h"
82 static const char propertyNameStringsPool[] = {
83 %(property_name_strings)s
86 static const unsigned short propertyNameStringsOffsets[] = {
87 %(property_name_offsets)s
98 %%define class-name %(class_name)sHash
99 %%define lookup-function-name findPropertyImpl
100 %%define hash-function-name propery_hash_function
101 %%define slot-name nameOffset
102 %%define word-array-name property_wordlist
105 %(property_to_enum_map)s
107 const Property* findProperty(register const char* str, register unsigned int len)
109 return %(class_name)sHash::findPropertyImpl(str, len);
112 const char* getPropertyName(CSSPropertyID id)
114 if (id < firstCSSProperty)
116 int index = id - firstCSSProperty;
117 if (index >= numCSSProperties)
119 return propertyNameStringsPool + propertyNameStringsOffsets[index];
122 const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
124 if (id < firstCSSProperty)
126 int index = id - firstCSSProperty;
127 if (index >= numCSSProperties)
130 static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
131 AtomicString& propertyString = propertyStrings[index];
132 if (propertyString.isNull()) {
133 const char* propertyName = propertyNameStringsPool + propertyNameStringsOffsets[index];
134 propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
136 return propertyString;
139 String getPropertyNameString(CSSPropertyID id)
141 // We share the StringImpl with the AtomicStrings.
142 return getPropertyNameAtomicString(id).string();
145 String getJSPropertyName(CSSPropertyID id)
147 char result[maxCSSPropertyNameLength + 1];
148 const char* cssPropertyName = getPropertyName(id);
149 const char* propertyNamePointer = cssPropertyName;
150 if (!propertyNamePointer)
151 return emptyString();
153 char* resultPointer = result;
154 while (char character = *propertyNamePointer++) {
155 if (character == '-') {
156 char nextCharacter = *propertyNamePointer++;
159 character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
161 *resultPointer++ = character;
163 *resultPointer = '\\0';
164 return String(result);
167 bool isInternalProperty(CSSPropertyID id)
170 %(internal_properties)s
177 } // namespace WebCore
181 class CSSPropertiesWriter(in_generator.Writer):
182 class_name = "CSSPropertyNames"
185 'is_internal': False,
188 def __init__(self, file_paths):
189 in_generator.Writer.__init__(self, file_paths)
190 self._outputs = {(self.class_name + ".h"): self.generate_header,
191 (self.class_name + ".cpp"): self.generate_implementation,
194 self._aliases = filter(lambda property: property['alias_for'], self.in_file.name_dictionaries)
195 for offset, property in enumerate(self._aliases):
196 # Aliases use the enum_name that they are an alias for.
197 property['enum_name'] = self._enum_name_from_property_name(property['alias_for'])
198 # Aliases do not get an enum_value.
200 self._properties = filter(lambda property: not property['alias_for'], self.in_file.name_dictionaries)
201 if len(self._properties) > 1024:
202 print "ERROR : There is more than 1024 CSS Properties, you need to update CSSProperty.h/StylePropertyMetadata m_propertyID accordingly."
204 self._first_property_id = 1 # We start after CSSPropertyInvalid.
205 property_id = self._first_property_id
206 for offset, property in enumerate(self._properties):
207 property['enum_name'] = self._enum_name_from_property_name(property['name'])
208 property['enum_value'] = self._first_property_id + offset
209 if property['name'].startswith('-internal-'):
210 property['is_internal'] = True
212 def _enum_name_from_property_name(self, property_name):
213 return "CSSProperty" + re.sub(r'(^[^-])|-(.)', lambda match: (match.group(1) or match.group(2)).upper(), property_name)
215 def _enum_declaration(self, property):
216 return " %(enum_name)s = %(enum_value)s," % property
218 def generate_header(self):
219 return HEADER_TEMPLATE % {
220 'license': license.license_for_generated_cpp(),
221 'class_name': self.class_name,
222 'property_enums': "\n".join(map(self._enum_declaration, self._properties)),
223 'first_property_id': self._first_property_id,
224 'properties_count': len(self._properties),
225 'last_property_id': self._first_property_id + len(self._properties) - 1,
226 'max_name_length': reduce(max, map(len, map(lambda property: property['name'], self._properties))),
229 def _case_properties(self, property):
230 return "case %(enum_name)s:" % property
232 def generate_implementation(self):
233 property_offsets = []
235 for property in self._properties:
236 property_offsets.append(current_offset)
237 current_offset += len(property["name"]) + 1
239 gperf_input = GPERF_TEMPLATE % {
240 'license': license.license_for_generated_cpp(),
241 'class_name': self.class_name,
242 'property_name_strings': '\n'.join(map(lambda property: ' "%(name)s\\0"' % property, self._properties)),
243 'property_name_offsets': '\n'.join(map(lambda offset: ' %d,' % offset, property_offsets)),
244 'property_to_enum_map': '\n'.join(map(lambda property: '%(name)s, %(enum_name)s' % property, self._properties + self._aliases)),
245 'internal_properties': '\n'.join(map(self._case_properties, filter(lambda property: property['is_internal'], self._properties))),
247 # FIXME: If we could depend on Python 2.7, we would use subprocess.check_output
248 gperf_args = [self.gperf_path, '--key-positions=*', '-P', '-D', '-n', '-s', '2']
249 gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
250 return gperf.communicate(gperf_input)[0]
253 if __name__ == "__main__":
254 in_generator.Maker(CSSPropertiesWriter).main(sys.argv)