423fba6b704001d528c46e72e307e9ebef664605
[WebKit-https.git] / Source / WebCore / css / makeprop.pl
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, 2014, 2015 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 #   Copyright (C) 2013 Google Inc. All rights reserved.
10 #
11 #   This library is free software; you can redistribute it and/or
12 #   modify it under the terms of the GNU Library General Public
13 #   License as published by the Free Software Foundation; either
14 #   version 2 of the License, or (at your option) any later version.
15 #
16 #   This library is distributed in the hope that it will be useful,
17 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 #   Library General Public License for more details.
20 #
21 #   You should have received a copy of the GNU Library General Public License
22 #   along with this library; see the file COPYING.LIB.  If not, write to
23 #   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 #   Boston, MA 02110-1301, USA.
25 use FindBin;
26 use lib "$FindBin::Bin/../bindings/scripts";
27
28 use Getopt::Long;
29 use preprocessor;
30 use strict;
31 use warnings;
32
33 my $defines;
34 my $preprocessor;
35 my $gperf;
36 GetOptions('defines=s' => \$defines,
37            'preprocessor=s' => \$preprocessor,
38            'gperf-executable=s' => \$gperf);
39
40 my @NAMES = applyPreprocessor("CSSPropertyNames.in", $defines, $preprocessor);
41 die "We've reached more than 1024 CSS properties, please make sure to update CSSProperty/StylePropertyMetadata accordingly" if (scalar(@NAMES) > 1024);
42
43 my %namesHash;
44 my @duplicates = ();
45
46 my $numPredefinedProperties = 2;
47 my @names = ();
48 my %nameIsInherited;
49 my %propertiesWithStyleBuilderOptions;
50 my %styleBuilderOptions = (
51   AnimationProperty => 1, # Defined in Source/WebCore/css/StyleBuilderConverter.h
52   AutoFunctions => 1,
53   ConditionalConverter => 1,
54   Converter => 1,
55   Custom => 1,
56   FillLayerProperty => 1,
57   FontProperty => 1,
58   Getter => 1,
59   Initial => 1,
60   Longhands => 1,
61   NameForMethods => 1,
62   NoDefaultColor => 1,
63   SVG => 1,
64   SkipBuilder => 1,
65   Setter => 1,
66   VisitedLinkColorSupport => 1,
67 );
68 my %nameToId;
69 my @aliases = ();
70 foreach (@NAMES) {
71   next if (m/(^\s*$)/);
72   next if (/^#/);
73
74   # Input may use a different EOL sequence than $/, so avoid chomp.
75   $_ =~ s/\s*\[(.+?)\]\r?$//;
76   my @options = ();
77   if ($1) {
78     @options = split(/\s*,\s*/, $1);
79   }
80
81   $_ =~ s/[\r\n]+$//g;
82   if (exists $namesHash{$_}) {
83     push @duplicates, $_;
84   } else {
85     $namesHash{$_} = 1;
86   }
87   if ($_ =~ /=/) {
88     if (@options) {
89         die "Options are specified on an alias $_: ", join(", ", @options) . "\n";
90     }
91     push @aliases, $_;
92   } else {
93     $nameIsInherited{$_} = 0;
94     $propertiesWithStyleBuilderOptions{$_} = {};
95     foreach my $option (@options) {
96       my ($optionName, $optionValue) = split(/=/, $option);
97       if ($optionName eq "Inherited") {
98         $nameIsInherited{$_} = 1;
99       } elsif ($styleBuilderOptions{$optionName}) {
100         $propertiesWithStyleBuilderOptions{$_}{$optionName} = $optionValue;
101       } else {
102         die "Unrecognized \"" . $optionName . "\" option for " . $_ . " property.";
103       }
104     }
105
106     my $id = $_;
107     $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge;
108     $nameToId{$_} = $id;
109
110     push @names, $_;
111   }
112 }
113
114 if (@duplicates > 0) {
115     die 'Duplicate CSS property names: ', join(', ', @duplicates) . "\n";
116 }
117
118 open GPERF, ">CSSPropertyNames.gperf" || die "Could not open CSSPropertyNames.gperf for writing";
119 print GPERF << "EOF";
120 %{
121 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
122 #include "config.h"
123 #include \"CSSProperty.h\"
124 #include \"CSSPropertyNames.h\"
125 #include \"HashTools.h\"
126 #include <string.h>
127
128 #include <wtf/ASCIICType.h>
129 #include <wtf/text/AtomicString.h>
130 #include <wtf/text/WTFString.h>
131
132 #if defined(__clang__)
133 #pragma clang diagnostic push
134 #pragma clang diagnostic ignored \"-Wunknown-pragmas\"
135 #pragma clang diagnostic ignored \"-Wdeprecated-register\"
136 #pragma clang diagnostic ignored \"-Wimplicit-fallthrough\"
137 #endif
138
139 namespace WebCore {
140
141 // Using std::numeric_limits<uint16_t>::max() here would be cleaner,
142 // but is not possible due to missing constexpr support in MSVC 2013.
143 static_assert(numCSSProperties + 1 <= 65535, "CSSPropertyID should fit into uint16_t.");
144
145 EOF
146
147 print GPERF "const char* const propertyNameStrings[numCSSProperties] = {\n";
148 foreach my $name (@names) {
149   print GPERF "    \"$name\",\n";
150 }
151 print GPERF "};\n\n";
152
153 print GPERF << "EOF";
154 %}
155 %struct-type
156 struct Property;
157 %omit-struct-type
158 %language=C++
159 %readonly-tables
160 %global-table
161 %compare-strncmp
162 %define class-name CSSPropertyNamesHash
163 %define lookup-function-name findPropertyImpl
164 %define hash-function-name propery_hash_function
165 %define word-array-name property_wordlist
166 %enum
167 %%
168 EOF
169
170 foreach my $name (@names) {
171   print GPERF $name . ", CSSProperty" . $nameToId{$name} . "\n";
172 }
173
174 foreach my $alias (@aliases) {
175   $alias =~ /^([^\s]*)[\s]*=[\s]*([^\s]*)/;
176   my $name = $1;
177   print GPERF $name . ", CSSProperty" . $nameToId{$2} . "\n";
178 }
179
180 print GPERF<< "EOF";
181 %%
182 const Property* findProperty(const char* str, unsigned int len)
183 {
184     return CSSPropertyNamesHash::findPropertyImpl(str, len);
185 }
186
187 const char* getPropertyName(CSSPropertyID id)
188 {
189     if (id < firstCSSProperty)
190         return 0;
191     int index = id - firstCSSProperty;
192     if (index >= numCSSProperties)
193         return 0;
194     return propertyNameStrings[index];
195 }
196
197 const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
198 {
199     if (id < firstCSSProperty)
200         return nullAtom;
201     int index = id - firstCSSProperty;
202     if (index >= numCSSProperties)
203         return nullAtom;
204
205     static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
206     AtomicString& propertyString = propertyStrings[index];
207     if (propertyString.isNull()) {
208         const char* propertyName = propertyNameStrings[index];
209         propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
210     }
211     return propertyString;
212 }
213
214 String getPropertyNameString(CSSPropertyID id)
215 {
216     // We share the StringImpl with the AtomicStrings.
217     return getPropertyNameAtomicString(id).string();
218 }
219
220 String getJSPropertyName(CSSPropertyID id)
221 {
222     char result[maxCSSPropertyNameLength + 1];
223     const char* cssPropertyName = getPropertyName(id);
224     const char* propertyNamePointer = cssPropertyName;
225     if (!propertyNamePointer)
226         return emptyString();
227
228     char* resultPointer = result;
229     while (char character = *propertyNamePointer++) {
230         if (character == '-') {
231             char nextCharacter = *propertyNamePointer++;
232             if (!nextCharacter)
233                 break;
234             character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
235         }
236         *resultPointer++ = character;
237     }
238     *resultPointer = '\\0';
239     return WTF::String(result);
240 }
241
242 static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
243     false, // CSSPropertyInvalid
244     true, // CSSPropertyCustom
245 EOF
246
247 foreach my $name (@names) {
248   my $id = $nameToId{$name};
249   my $value = $nameIsInherited{$name} ? "true " : "false";
250   print GPERF "    $value, // CSSProperty$id\n";
251 }
252
253 print GPERF<< "EOF";
254 };
255
256 bool CSSProperty::isInheritedProperty(CSSPropertyID id)
257 {
258     ASSERT(id <= lastCSSProperty);
259     ASSERT(id != CSSPropertyInvalid);
260     return isInheritedPropertyTable[id];
261 }
262
263 } // namespace WebCore
264
265 #if defined(__clang__)
266 #pragma clang diagnostic pop
267 #endif
268 EOF
269
270 close GPERF;
271
272 open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing";
273 print HEADER << "EOF";
274 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
275
276 #ifndef CSSPropertyNames_h
277 #define CSSPropertyNames_h
278
279 #include <string.h>
280 #include <wtf/HashFunctions.h>
281 #include <wtf/HashTraits.h>
282
283 namespace WTF {
284 class AtomicString;
285 class String;
286 }
287
288 namespace WebCore {
289
290 enum CSSPropertyID : uint16_t {
291     CSSPropertyInvalid = 0,
292     CSSPropertyCustom = 1,
293 EOF
294
295 my $first = $numPredefinedProperties;
296 my $i = $numPredefinedProperties;
297 my $maxLen = 0;
298 foreach my $name (@names) {
299   print HEADER "    CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
300   $i = $i + 1;
301   if (length($name) > $maxLen) {
302     $maxLen = length($name);
303   }
304 }
305 my $num = $i - $first;
306 my $last = $i - 1;
307
308 print HEADER "};\n\n";
309 print HEADER "const int firstCSSProperty = $first;\n";
310 print HEADER "const int numCSSProperties = $num;\n";
311 print HEADER "const int lastCSSProperty = $last;\n";
312 print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
313
314 print HEADER << "EOF";
315
316 const char* getPropertyName(CSSPropertyID);
317 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
318 WTF::String getPropertyNameString(CSSPropertyID id);
319 WTF::String getJSPropertyName(CSSPropertyID);
320
321 inline CSSPropertyID convertToCSSPropertyID(int value)
322 {
323     ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
324     return static_cast<CSSPropertyID>(value);
325 }
326
327 } // namespace WebCore
328
329 namespace WTF {
330 template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
331 template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
332     static const bool emptyValueIsZero = true;
333     static const bool needsDestruction = false;
334     static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
335     static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
336 };
337 }
338
339 #endif // CSSPropertyNames_h
340
341 EOF
342
343 close HEADER;
344
345 #
346 # StyleBuilder.cpp generator.
347 #
348
349 sub getScopeForFunction {
350   my $name = shift;
351   my $builderFunction = shift;
352
353   return $propertiesWithStyleBuilderOptions{$name}{"Custom"}{$builderFunction} ? "StyleBuilderCustom" : "StyleBuilderFunctions";
354 }
355
356 sub getNameForMethods {
357   my $name = shift;
358
359   my $nameForMethods = $nameToId{$name};
360   $nameForMethods =~ s/Webkit//g;
361   if (exists($propertiesWithStyleBuilderOptions{$name}{"NameForMethods"})) {
362     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
363   }
364   return $nameForMethods;
365 }
366
367 sub getAutoGetter {
368   my $name = shift;
369   my $renderStyle = shift;
370
371   return $renderStyle . "->hasAuto" . getNameForMethods($name) . "()";
372 }
373
374 sub getAutoSetter {
375   my $name = shift;
376   my $renderStyle = shift;
377
378   return $renderStyle . "->setHasAuto" . getNameForMethods($name) . "()";
379 }
380
381 sub getVisitedLinkSetter {
382   my $name = shift;
383   my $renderStyle = shift;
384
385   return $renderStyle . "->setVisitedLink" . getNameForMethods($name);
386 }
387
388 sub getClearFunction {
389   my $name = shift;
390
391   return "clear" . getNameForMethods($name);
392 }
393
394 sub getEnsureAnimationsOrTransitionsMethod {
395   my $name = shift;
396
397   return "ensureAnimations" if $name =~ /animation-/;
398   return "ensureTransitions" if $name =~ /transition-/;
399   die "Unrecognized animation property name.";
400 }
401
402 sub getAnimationsOrTransitionsMethod {
403   my $name = shift;
404
405   return "animations" if $name =~ /animation-/;
406   return "transitions" if $name =~ /transition-/;
407   die "Unrecognized animation property name.";
408 }
409
410 sub getTestFunction {
411   my $name = shift;
412
413   return "is" . getNameForMethods($name) . "Set";
414 }
415
416 sub getAnimationMapfunction {
417   my $name = shift;
418
419   return "mapAnimation" . getNameForMethods($name);
420 }
421
422 sub getLayersFunction {
423   my $name = shift;
424
425   return "backgroundLayers" if $name =~ /background-/;
426   return "maskLayers" if $name =~ /mask-/;
427   die "Unrecognized FillLayer property name.";
428 }
429
430 sub getLayersAccessorFunction {
431   my $name = shift;
432
433   return "ensureBackgroundLayers" if $name =~ /background-/;
434   return "ensureMaskLayers" if $name =~ /mask-/;
435   die "Unrecognized FillLayer property name.";
436 }
437
438 sub getFillLayerType {
439 my $name = shift;
440
441   return "BackgroundFillLayer" if $name =~ /background-/;
442   return "MaskFillLayer" if $name =~ /mask-/;
443 }
444
445 sub getFillLayerMapfunction {
446   my $name = shift;
447
448   return "mapFill" . getNameForMethods($name);
449 }
450
451
452 foreach my $name (@names) {
453   my $nameForMethods = getNameForMethods($name);
454   $nameForMethods =~ s/Webkit//g;
455   if (exists($propertiesWithStyleBuilderOptions{$name}{"NameForMethods"})) {
456     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
457   }
458
459   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Getter"})) {
460     $propertiesWithStyleBuilderOptions{$name}{"Getter"} = lcfirst($nameForMethods);
461   }
462   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Setter"})) {
463     $propertiesWithStyleBuilderOptions{$name}{"Setter"} = "set" . $nameForMethods;
464   }
465   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Initial"})) {
466     if (exists($propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"})) {
467       $propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initialFill" . $nameForMethods;
468     } else {
469       $propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initial" . $nameForMethods;
470     }
471   }
472   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Custom"})) {
473     $propertiesWithStyleBuilderOptions{$name}{"Custom"} = "";
474   } elsif ($propertiesWithStyleBuilderOptions{$name}{"Custom"} eq "All") {
475     $propertiesWithStyleBuilderOptions{$name}{"Custom"} = "Initial|Inherit|Value";
476   }
477   my %customValues = map { $_ => 1 } split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"Custom"});
478   $propertiesWithStyleBuilderOptions{$name}{"Custom"} = \%customValues;
479 }
480
481 use constant {
482   NOT_FOR_VISITED_LINK => 0,
483   FOR_VISITED_LINK => 1,
484 };
485
486 sub colorFromPrimitiveValue {
487   my $primitiveValue = shift;
488   my $forVisitedLink = @_ ? shift : NOT_FOR_VISITED_LINK;
489
490   return "styleResolver.colorFromPrimitiveValue(" . $primitiveValue . ", /* forVisitedLink */ " . ($forVisitedLink ? "true" : "false") . ")";
491 }
492
493 use constant {
494   VALUE_IS_COLOR => 0,
495   VALUE_IS_PRIMITIVE => 1,
496 };
497
498 sub generateColorValueSetter {
499   my $name = shift;
500   my $value = shift;
501   my $indent = shift;
502   my $valueIsPrimitive = @_ ? shift : VALUE_IS_COLOR;
503
504   my $style = "styleResolver.style()";
505   my $setterContent .= $indent . "if (styleResolver.applyPropertyToRegularStyle())\n";
506   my $setValue = $style . "->" . $propertiesWithStyleBuilderOptions{$name}{"Setter"};
507   my $color = $valueIsPrimitive ? colorFromPrimitiveValue($value) : $value;
508   $setterContent .= $indent . "    " . $setValue . "(" . $color . ");\n";
509   $setterContent .= $indent . "if (styleResolver.applyPropertyToVisitedLinkStyle())\n";
510   $color = $valueIsPrimitive ? colorFromPrimitiveValue($value, FOR_VISITED_LINK) : $value;
511   $setterContent .= $indent . "    " . getVisitedLinkSetter($name, $style) . "(" . $color . ");\n";
512
513   return $setterContent;
514 }
515
516 sub handleCurrentColorValue {
517   my $name = shift;
518   my $primitiveValue = shift;
519   my $indent = shift;
520
521   my $code = $indent . "if (" . $primitiveValue . ".valueID() == CSSValueCurrentcolor) {\n";
522   $code .= $indent . "    applyInherit" . $nameToId{$name} . "(styleResolver);\n";
523   $code .= $indent . "    return;\n";
524   $code .= $indent . "}\n";
525   return $code;
526 }
527
528 sub generateAnimationPropertyInitialValueSetter {
529   my $name = shift;
530   my $indent = shift;
531
532   my $setterContent = "";
533   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
534   $setterContent .= $indent . "if (list.isEmpty())\n";
535   $setterContent .= $indent . "    list.append(Animation::create());\n";
536   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
537   my $initial = $propertiesWithStyleBuilderOptions{$name}{"Initial"};
538   $setterContent .= $indent . "list.animation(0)." . $setter . "(Animation::" . $initial . "());\n";
539   if ($name eq "-webkit-transition-property") {
540     $setterContent .= $indent . "list.animation(0).setAnimationMode(Animation::AnimateAll);\n";
541   }
542   $setterContent .= $indent . "for (size_t i = 1; i < list.size(); ++i)\n";
543   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
544
545   return $setterContent;
546 }
547
548 sub generateAnimationPropertyInheritValueSetter {
549   my $name = shift;
550   my $indent = shift;
551
552   my $setterContent = "";
553   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
554   $setterContent .= $indent . "const AnimationList* parentList = styleResolver.parentStyle()->" . getAnimationsOrTransitionsMethod($name) . "();\n";
555   $setterContent .= $indent . "size_t i = 0, parentSize = parentList ? parentList->size() : 0;\n";
556   $setterContent .= $indent . "for ( ; i < parentSize && parentList->animation(i)." . getTestFunction($name) . "(); ++i) {\n";
557   $setterContent .= $indent . "    if (list.size() <= i)\n";
558   $setterContent .= $indent . "        list.append(Animation::create());\n";
559   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
560   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
561   $setterContent .= $indent . "    list.animation(i)." . $setter . "(parentList->animation(i)." . $getter . "());\n";
562   $setterContent .= $indent . "    list.animation(i).setAnimationMode(parentList->animation(i).animationMode());\n";
563   $setterContent .= $indent . "}\n";
564   $setterContent .= "\n";
565   $setterContent .= $indent . "/* Reset any remaining animations to not have the property set. */\n";
566   $setterContent .= $indent . "for ( ; i < list.size(); ++i)\n";
567   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
568
569   return $setterContent;
570 }
571
572 sub generateAnimationPropertyValueSetter {
573   my $name = shift;
574   my $indent = shift;
575
576   my $setterContent = "";
577   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
578   $setterContent .= $indent . "size_t childIndex = 0;\n";
579   $setterContent .= $indent . "if (is<CSSValueList>(value)) {\n";
580   $setterContent .= $indent . "    /* Walk each value and put it into an animation, creating new animations as needed. */\n";
581   $setterContent .= $indent . "    for (auto& currentValue : downcast<CSSValueList>(value)) {\n";
582   $setterContent .= $indent . "        if (childIndex <= list.size())\n";
583   $setterContent .= $indent . "            list.append(Animation::create());\n";
584   $setterContent .= $indent . "        styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), currentValue);\n";
585   $setterContent .= $indent . "        ++childIndex;\n";
586   $setterContent .= $indent . "    }\n";
587   $setterContent .= $indent . "} else {\n";
588   $setterContent .= $indent . "    if (list.isEmpty())\n";
589   $setterContent .= $indent . "        list.append(Animation::create());\n";
590   $setterContent .= $indent . "    styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), value);\n";
591   $setterContent .= $indent . "    childIndex = 1;\n";
592   $setterContent .= $indent . "}\n";
593   $setterContent .= $indent . "for ( ; childIndex < list.size(); ++childIndex) {\n";
594   $setterContent .= $indent . "    /* Reset all remaining animations to not have the property set. */\n";
595   $setterContent .= $indent . "    list.animation(childIndex)." . getClearFunction($name) . "();\n";
596   $setterContent .= $indent . "}\n";
597
598   return $setterContent;
599 }
600
601 sub generateFillLayerPropertyInitialValueSetter {
602   my $name = shift;
603   my $indent = shift;
604
605   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
606   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
607   my $clearFunction = getClearFunction($name);
608   my $testFunction = getTestFunction($name);
609   my $initial = "FillLayer::" . $propertiesWithStyleBuilderOptions{$name}{"Initial"} . "(" . getFillLayerType($name) . ")";
610
611   my $setterContent = "";
612   $setterContent .= $indent . "// Check for (single-layer) no-op before clearing anything.\n";
613   $setterContent .= $indent . "const FillLayer& layers = *styleResolver.style()->" . getLayersFunction($name) . "();\n";
614   $setterContent .= $indent . "if (!layers.next() && (!layers." . $testFunction . "() || layers." . $getter . "() == $initial))\n";
615   $setterContent .= $indent . "    return;\n";
616   $setterContent .= "\n";
617   $setterContent .= $indent . "FillLayer* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
618   $setterContent .= $indent . "child->" . $setter . "(" . $initial . ");\n";
619   $setterContent .= $indent . "for (child = child->next(); child; child = child->next())\n";
620   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
621
622   return $setterContent;
623 }
624
625 sub generateFillLayerPropertyInheritValueSetter {
626   my $name = shift;
627   my $indent = shift;
628
629   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
630   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
631   my $clearFunction = getClearFunction($name);
632   my $testFunction = getTestFunction($name);
633
634   my $setterContent = "";
635   $setterContent .= $indent . "// Check for no-op before copying anything.\n";
636   $setterContent .= $indent . "if (*styleResolver.parentStyle()->" . getLayersFunction($name) ."() == *styleResolver.style()->" . getLayersFunction($name) . "())\n";
637   $setterContent .= $indent . "    return;\n";
638   $setterContent .= "\n";
639   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
640   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
641   $setterContent .= $indent . "for (auto* parent = styleResolver.parentStyle()->" . getLayersFunction($name) . "(); parent && parent->" . $testFunction . "(); parent = parent->next()) {\n";
642   $setterContent .= $indent . "    if (!child) {\n";
643   $setterContent .= $indent . "        previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
644   $setterContent .= $indent . "        child = previousChild->next();\n";
645   $setterContent .= $indent . "    }\n";
646   $setterContent .= $indent . "    child->" . $setter . "(parent->" . $getter . "());\n";
647   $setterContent .= $indent . "    previousChild = child;\n";
648   $setterContent .= $indent . "    child = previousChild->next();\n";
649   $setterContent .= $indent . "}\n";
650   $setterContent .= $indent . "for (; child; child = child->next())\n";
651   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
652
653   return $setterContent;
654 }
655
656 sub generateFillLayerPropertyValueSetter {
657   my $name = shift;
658   my $indent = shift;
659
660   my $CSSPropertyId = "CSSProperty" . $nameToId{$name};
661
662   my $setterContent = "";
663   $setterContent .= $indent . "FillLayer* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
664   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
665   $setterContent .= $indent . "if (is<CSSValueList>(value) && !is<CSSImageSetValue>(value)) {\n";
666   $setterContent .= $indent . "    // Walk each value and put it into a layer, creating new layers as needed.\n";
667   $setterContent .= $indent . "    for (auto& item : downcast<CSSValueList>(value)) {\n";
668   $setterContent .= $indent . "        if (!child) {\n";
669   $setterContent .= $indent . "            previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
670   $setterContent .= $indent . "            child = previousChild->next();\n";
671   $setterContent .= $indent . "        }\n";
672   $setterContent .= $indent . "        styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, item);\n";
673   $setterContent .= $indent . "        previousChild = child;\n";
674   $setterContent .= $indent . "        child = child->next();\n";
675   $setterContent .= $indent . "    }\n";
676   $setterContent .= $indent . "} else {\n";
677   $setterContent .= $indent . "    styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, value);\n";
678   $setterContent .= $indent . "    child = child->next();\n";
679   $setterContent .= $indent . "}\n";
680   $setterContent .= $indent . "for (; child; child = child->next())\n";
681   $setterContent .= $indent . "    child->" . getClearFunction($name) . "();\n";
682
683   return $setterContent;
684 }
685
686 sub generateSetValueStatement
687 {
688   my $name = shift;
689   my $value = shift;
690
691   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
692   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
693   return "styleResolver.style()->" .  ($isSVG ? "accessSVGStyle()." : "") . $setter . "(" . $value . ")";
694 }
695
696 sub generateInitialValueSetter {
697   my $name = shift;
698   my $indent = shift;
699
700   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
701   my $initial = $propertiesWithStyleBuilderOptions{$name}{"Initial"};
702   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
703   my $setterContent = "";
704   $setterContent .= $indent . "static void applyInitial" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
705   $setterContent .= $indent . "{\n";
706   my $style = "styleResolver.style()";
707   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
708     $setterContent .= $indent . "    " . getAutoSetter($name, $style) . ";\n";
709   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
710       my $initialColor = "RenderStyle::" . $initial . "()";
711       $setterContent .= generateColorValueSetter($name, $initialColor, $indent . "    ");
712   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
713     $setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . "    ");
714   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
715     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
716     $setterContent .= $indent . "    fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
717     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
718   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
719     $setterContent .= generateFillLayerPropertyInitialValueSetter($name, $indent . "    ");
720   } else {
721     my $initialValue = ($isSVG ? "SVGRenderStyle" : "RenderStyle") . "::" . $initial . "()";
722     $setterContent .= $indent . "    " . generateSetValueStatement($name, $initialValue) . ";\n";
723   }
724   $setterContent .= $indent . "}\n";
725
726   return $setterContent;
727 }
728
729 sub generateInheritValueSetter {
730   my $name = shift;
731   my $indent = shift;
732
733   my $setterContent = "";
734   $setterContent .= $indent . "static void applyInherit" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
735   $setterContent .= $indent . "{\n";
736   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
737   my $parentStyle = "styleResolver.parentStyle()";
738   my $style = "styleResolver.style()";
739   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
740   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
741   my $didCallSetValue = 0;
742   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
743     $setterContent .= $indent . "    if (" . getAutoGetter($name, $parentStyle) . ") {\n";
744     $setterContent .= $indent . "        " . getAutoSetter($name, $style) . ";\n";
745     $setterContent .= $indent . "        return;\n";
746     $setterContent .= $indent . "    }\n";
747   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
748     $setterContent .= $indent . "    Color color = " . $parentStyle . "->" . $getter . "();\n";
749     if (!exists($propertiesWithStyleBuilderOptions{$name}{"NoDefaultColor"})) {
750       $setterContent .= $indent . "    if (!color.isValid())\n";
751       $setterContent .= $indent . "        color = " . $parentStyle . "->color();\n";
752     }
753     $setterContent .= generateColorValueSetter($name, "color", $indent . "    ");
754     $didCallSetValue = 1;
755   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
756     $setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . "    ");
757     $didCallSetValue = 1;
758   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
759     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
760     $setterContent .= $indent . "    fontDescription." . $setter . "(styleResolver.parentFontDescription()." . $getter . "());\n";
761     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
762     $didCallSetValue = 1;
763   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
764     $setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . "    ");
765     $didCallSetValue = 1;
766   }
767   if (!$didCallSetValue) {
768     my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") .  $getter . "()";
769     $setterContent .= $indent . "    " . generateSetValueStatement($name, $inheritedValue) . ";\n";
770   }
771   $setterContent .= $indent . "}\n";
772
773   return $setterContent;
774 }
775
776 sub generateValueSetter {
777   my $name = shift;
778   my $indent = shift;
779
780   my $setterContent = "";
781   $setterContent .= $indent . "static void applyValue" . $nameToId{$name} . "(StyleResolver& styleResolver, CSSValue& value)\n";
782   $setterContent .= $indent . "{\n";
783   my $convertedValue;
784   if (exists($propertiesWithStyleBuilderOptions{$name}{"Converter"})) {
785     $convertedValue = "StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"Converter"} . "(styleResolver, value)";
786   } elsif (exists($propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"})) {
787     $setterContent .= $indent . "    auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"} . "(styleResolver, value);\n";
788     $convertedValue = "convertedValue.value()";
789   } else {
790     $convertedValue = "downcast<CSSPrimitiveValue>(value)";
791   }
792
793   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
794   my $style = "styleResolver.style()";
795   my $didCallSetValue = 0;
796   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
797     $setterContent .= $indent . "    if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto) {\n";
798     $setterContent .= $indent . "        ". getAutoSetter($name, $style) . ";\n";
799     $setterContent .= $indent . "        return;\n";
800     $setterContent .= $indent . "    }\n";
801   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
802     $setterContent .= $indent . "    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);\n";
803     if ($name eq "color") {
804       # The "color" property supports "currentColor" value. We should add a parameter.
805       $setterContent .= handleCurrentColorValue($name, "primitiveValue", $indent . "    ");
806     }
807     $setterContent .= generateColorValueSetter($name, "primitiveValue", $indent . "    ", VALUE_IS_PRIMITIVE);
808     $didCallSetValue = 1;
809   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
810     $setterContent .= generateAnimationPropertyValueSetter($name, $indent . "    ");
811     $didCallSetValue = 1;
812   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
813     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
814     $setterContent .= $indent . "    fontDescription." . $setter . "(" . $convertedValue . ");\n";
815     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
816     $didCallSetValue = 1;
817   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
818     $setterContent .= generateFillLayerPropertyValueSetter($name, $indent . "    ");
819     $didCallSetValue = 1;
820   }
821   if (!$didCallSetValue) {
822     if (exists($propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"})) {
823       $setterContent .= $indent . "    if (convertedValue)\n";
824       $setterContent .= "    ";
825     }
826     $setterContent .= $indent . "    " . generateSetValueStatement($name, $convertedValue) . ";\n";
827   }
828   $setterContent .= $indent . "}\n";
829
830   return $setterContent;
831 }
832
833 open STYLEBUILDER, ">StyleBuilder.cpp" || die "Could not open StyleBuilder.cpp for writing";
834 print STYLEBUILDER << "EOF";
835 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
836
837 #include "config.h"
838 #include "StyleBuilder.h"
839
840 #include "CSSPrimitiveValueMappings.h"
841 #include "CSSProperty.h"
842 #include "RenderStyle.h"
843 #include "StyleBuilderConverter.h"
844 #include "StyleBuilderCustom.h"
845 #include "StylePropertyShorthand.h"
846 #include "StyleResolver.h"
847
848 namespace WebCore {
849
850 class StyleBuilderFunctions {
851 public:
852 EOF
853
854 foreach my $name (@names) {
855   # Skip Shorthand properties and properties that do not use the StyleBuilder.
856   next if (exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
857   next if (exists $propertiesWithStyleBuilderOptions{$name}{"SkipBuilder"});
858
859   my $indent = "    ";
860   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Initial"}) {
861     print STYLEBUILDER generateInitialValueSetter($name, $indent);
862   }
863   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Inherit"}) {
864     print STYLEBUILDER generateInheritValueSetter($name, $indent);
865   }
866   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Value"}) {
867     print STYLEBUILDER generateValueSetter($name, $indent);
868   }
869 }
870
871 print STYLEBUILDER << "EOF";
872 };
873
874 void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleResolver, CSSValue& value, bool isInitial, bool isInherit)
875 {
876     switch (property) {
877     case CSSPropertyInvalid:
878     case CSSPropertyCustom:
879         break;
880 EOF
881
882 foreach my $name (@names) {
883   print STYLEBUILDER "    case CSSProperty" . $nameToId{$name} . ":\n";
884   if (exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"}) {
885     print STYLEBUILDER "        ASSERT(isShorthandCSSProperty(property));\n";
886     print STYLEBUILDER "        ASSERT_NOT_REACHED();\n";
887   } elsif (!exists $propertiesWithStyleBuilderOptions{$name}{"SkipBuilder"}) {
888     print STYLEBUILDER "        if (isInitial)\n";
889     print STYLEBUILDER "            " . getScopeForFunction($name, "Initial") . "::applyInitial" . $nameToId{$name} . "(styleResolver);\n";
890     print STYLEBUILDER "        else if (isInherit)\n";
891     print STYLEBUILDER "            " . getScopeForFunction($name, "Inherit") . "::applyInherit" . $nameToId{$name} . "(styleResolver);\n";
892     print STYLEBUILDER "        else\n";
893     print STYLEBUILDER "            " . getScopeForFunction($name, "Value") . "::applyValue" . $nameToId{$name} . "(styleResolver, value);\n";
894   }
895   print STYLEBUILDER "        break;\n";
896 }
897
898 print STYLEBUILDER << "EOF";
899     };
900 }
901
902 } // namespace WebCore
903 EOF
904
905 close STYLEBUILDER;
906
907 # Generate StylePropertyShorthandsFunctions.
908 open SHORTHANDS_H, ">StylePropertyShorthandFunctions.h" || die "Could not open StylePropertyShorthandFunctions.h for writing";
909 print SHORTHANDS_H << "EOF";
910 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
911
912 #ifndef StylePropertyShorthandFunctions_h
913 #define StylePropertyShorthandFunctions_h
914
915 namespace WebCore {
916
917 class StylePropertyShorthand;
918
919 EOF
920
921 foreach my $name (@names) {
922   # Skip non-Shorthand properties.
923   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
924
925   print SHORTHANDS_H "StylePropertyShorthand " . lcfirst($nameToId{$name}) . "Shorthand();\n";
926 }
927
928 print SHORTHANDS_H << "EOF";
929
930 } // namespace WebCore
931
932 #endif // StylePropertyShorthandFunctions_h
933 EOF
934
935 close SHORTHANDS_H;
936
937 open SHORTHANDS_CPP, ">StylePropertyShorthandFunctions.cpp" || die "Could not open StylePropertyShorthandFunctions.cpp for writing";
938 print SHORTHANDS_CPP << "EOF";
939 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
940
941 #include "config.h"
942 #include "StylePropertyShorthandFunctions.h"
943
944 #include "StylePropertyShorthand.h"
945 #include <wtf/NeverDestroyed.h>
946
947 namespace WebCore {
948
949 EOF
950
951 my %longhandToShorthands = ();
952
953 foreach my $name (@names) {
954   # Skip non-Shorthand properties.
955   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
956
957   my $lowercaseId = lcfirst($nameToId{$name});
958   my @longhands = split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
959
960   print SHORTHANDS_CPP "StylePropertyShorthand " . $lowercaseId . "Shorthand()\n";
961   print SHORTHANDS_CPP "{\n";
962   print SHORTHANDS_CPP "    static const CSSPropertyID " . $lowercaseId . "Properties[] = {\n";
963   foreach (@longhands) {
964     if ($_ eq "all") {
965         foreach my $propname (@names) {
966             next if (exists $propertiesWithStyleBuilderOptions{$propname}{"Longhands"});
967             next if ($propname eq "direction" || $propname eq "unicode-bidi");
968             die "Unknown CSS property used in all shorthand: " . $nameToId{$propname} if !exists($nameToId{$propname});
969             push(@{$longhandToShorthands{$propname}}, $name);
970             print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$propname} . ",\n";
971         }
972     } else {
973         die "Unknown CSS property used in Longhands: " . $nameToId{$_} if !exists($nameToId{$_});
974         push(@{$longhandToShorthands{$_}}, $name);
975         print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$_} . ",\n";
976     }
977   }
978   print SHORTHANDS_CPP "    };\n";
979   print SHORTHANDS_CPP "    return StylePropertyShorthand(CSSProperty" . $nameToId{$name} . ", " . $lowercaseId . "Properties);\n";
980   print SHORTHANDS_CPP "}\n\n";
981 }
982
983 print SHORTHANDS_CPP << "EOF";
984 StylePropertyShorthand shorthandForProperty(CSSPropertyID propertyID)
985 {
986     static NeverDestroyed<StylePropertyShorthand> emptyShorthand;
987
988     switch (propertyID) {
989 EOF
990
991 foreach my $name (@names) {
992   # Skip non-Shorthand properties.
993   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
994
995   print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$name} . ":\n";
996   print SHORTHANDS_CPP "        return " . lcfirst($nameToId{$name}) . "Shorthand();\n";
997 }
998
999 print SHORTHANDS_CPP << "EOF";
1000     default:
1001         return emptyShorthand;
1002     }
1003 }
1004 EOF
1005
1006 print SHORTHANDS_CPP << "EOF";
1007 StylePropertyShorthandVector matchingShorthandsForLonghand(CSSPropertyID propertyID)
1008 {
1009     switch (propertyID) {
1010 EOF
1011
1012 sub constructShorthandsVector {
1013   my $shorthands = shift;
1014
1015   my $vector = "StylePropertyShorthandVector{";
1016   foreach my $i (0 .. $#$shorthands) {
1017     $vector .= ", " unless $i == 0;
1018     $vector .= lcfirst($nameToId{$shorthands->[$i]}) . "Shorthand()";
1019   }
1020   $vector .= "}";
1021   return $vector;
1022 }
1023
1024 my %vectorToLonghands = ();
1025 for my $longhand (sort keys %longhandToShorthands) {
1026   my @shorthands = sort(@{$longhandToShorthands{$longhand}});
1027   push(@{$vectorToLonghands{constructShorthandsVector(\@shorthands)}}, $longhand);
1028 }
1029
1030 for my $vector (sort keys %vectorToLonghands) {
1031   foreach (@{$vectorToLonghands{$vector}}) {
1032     print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$_} . ":\n";
1033   }
1034   print SHORTHANDS_CPP "        return " . $vector . ";\n";
1035 }
1036
1037 print SHORTHANDS_CPP << "EOF";
1038     default:
1039         return { };
1040     }
1041 }
1042 EOF
1043
1044 print SHORTHANDS_CPP << "EOF";
1045 } // namespace WebCore
1046 EOF
1047
1048 close SHORTHANDS_CPP;
1049
1050 if (not $gperf) {
1051     $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
1052 }
1053 system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";