Use #pragma once in WebCore
[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 #pragma once
277
278 #include <string.h>
279 #include <wtf/HashFunctions.h>
280 #include <wtf/HashTraits.h>
281
282 namespace WTF {
283 class AtomicString;
284 class String;
285 }
286
287 namespace WebCore {
288
289 enum CSSPropertyID : uint16_t {
290     CSSPropertyInvalid = 0,
291     CSSPropertyCustom = 1,
292 EOF
293
294 my $first = $numPredefinedProperties;
295 my $i = $numPredefinedProperties;
296 my $maxLen = 0;
297 foreach my $name (@names) {
298   print HEADER "    CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
299   $i = $i + 1;
300   if (length($name) > $maxLen) {
301     $maxLen = length($name);
302   }
303 }
304 my $num = $i - $first;
305 my $last = $i - 1;
306
307 print HEADER "};\n\n";
308 print HEADER "const int firstCSSProperty = $first;\n";
309 print HEADER "const int numCSSProperties = $num;\n";
310 print HEADER "const int lastCSSProperty = $last;\n";
311 print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
312
313 print HEADER << "EOF";
314
315 const char* getPropertyName(CSSPropertyID);
316 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
317 WTF::String getPropertyNameString(CSSPropertyID id);
318 WTF::String getJSPropertyName(CSSPropertyID);
319
320 inline CSSPropertyID convertToCSSPropertyID(int value)
321 {
322     ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
323     return static_cast<CSSPropertyID>(value);
324 }
325
326 } // namespace WebCore
327
328 namespace WTF {
329 template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
330 template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
331     static const bool emptyValueIsZero = true;
332     static const bool needsDestruction = false;
333     static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
334     static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
335 };
336 } // namespace WTF
337
338 EOF
339
340 close HEADER;
341
342 #
343 # StyleBuilder.cpp generator.
344 #
345
346 sub getScopeForFunction {
347   my $name = shift;
348   my $builderFunction = shift;
349
350   return $propertiesWithStyleBuilderOptions{$name}{"Custom"}{$builderFunction} ? "StyleBuilderCustom" : "StyleBuilderFunctions";
351 }
352
353 sub getNameForMethods {
354   my $name = shift;
355
356   my $nameForMethods = $nameToId{$name};
357   $nameForMethods =~ s/Webkit//g;
358   if (exists($propertiesWithStyleBuilderOptions{$name}{"NameForMethods"})) {
359     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
360   }
361   return $nameForMethods;
362 }
363
364 sub getAutoGetter {
365   my $name = shift;
366   my $renderStyle = shift;
367
368   return $renderStyle . "->hasAuto" . getNameForMethods($name) . "()";
369 }
370
371 sub getAutoSetter {
372   my $name = shift;
373   my $renderStyle = shift;
374
375   return $renderStyle . "->setHasAuto" . getNameForMethods($name) . "()";
376 }
377
378 sub getVisitedLinkSetter {
379   my $name = shift;
380   my $renderStyle = shift;
381
382   return $renderStyle . "->setVisitedLink" . getNameForMethods($name);
383 }
384
385 sub getClearFunction {
386   my $name = shift;
387
388   return "clear" . getNameForMethods($name);
389 }
390
391 sub getEnsureAnimationsOrTransitionsMethod {
392   my $name = shift;
393
394   return "ensureAnimations" if $name =~ /animation-/;
395   return "ensureTransitions" if $name =~ /transition-/;
396   die "Unrecognized animation property name.";
397 }
398
399 sub getAnimationsOrTransitionsMethod {
400   my $name = shift;
401
402   return "animations" if $name =~ /animation-/;
403   return "transitions" if $name =~ /transition-/;
404   die "Unrecognized animation property name.";
405 }
406
407 sub getTestFunction {
408   my $name = shift;
409
410   return "is" . getNameForMethods($name) . "Set";
411 }
412
413 sub getAnimationMapfunction {
414   my $name = shift;
415
416   return "mapAnimation" . getNameForMethods($name);
417 }
418
419 sub getLayersFunction {
420   my $name = shift;
421
422   return "backgroundLayers" if $name =~ /background-/;
423   return "maskLayers" if $name =~ /mask-/;
424   die "Unrecognized FillLayer property name.";
425 }
426
427 sub getLayersAccessorFunction {
428   my $name = shift;
429
430   return "ensureBackgroundLayers" if $name =~ /background-/;
431   return "ensureMaskLayers" if $name =~ /mask-/;
432   die "Unrecognized FillLayer property name.";
433 }
434
435 sub getFillLayerType {
436 my $name = shift;
437
438   return "BackgroundFillLayer" if $name =~ /background-/;
439   return "MaskFillLayer" if $name =~ /mask-/;
440 }
441
442 sub getFillLayerMapfunction {
443   my $name = shift;
444
445   return "mapFill" . getNameForMethods($name);
446 }
447
448
449 foreach my $name (@names) {
450   my $nameForMethods = getNameForMethods($name);
451   $nameForMethods =~ s/Webkit//g;
452   if (exists($propertiesWithStyleBuilderOptions{$name}{"NameForMethods"})) {
453     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
454   }
455
456   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Getter"})) {
457     $propertiesWithStyleBuilderOptions{$name}{"Getter"} = lcfirst($nameForMethods);
458   }
459   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Setter"})) {
460     $propertiesWithStyleBuilderOptions{$name}{"Setter"} = "set" . $nameForMethods;
461   }
462   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Initial"})) {
463     if (exists($propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"})) {
464       $propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initialFill" . $nameForMethods;
465     } else {
466       $propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initial" . $nameForMethods;
467     }
468   }
469   if (!exists($propertiesWithStyleBuilderOptions{$name}{"Custom"})) {
470     $propertiesWithStyleBuilderOptions{$name}{"Custom"} = "";
471   } elsif ($propertiesWithStyleBuilderOptions{$name}{"Custom"} eq "All") {
472     $propertiesWithStyleBuilderOptions{$name}{"Custom"} = "Initial|Inherit|Value";
473   }
474   my %customValues = map { $_ => 1 } split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"Custom"});
475   $propertiesWithStyleBuilderOptions{$name}{"Custom"} = \%customValues;
476 }
477
478 use constant {
479   NOT_FOR_VISITED_LINK => 0,
480   FOR_VISITED_LINK => 1,
481 };
482
483 sub colorFromPrimitiveValue {
484   my $primitiveValue = shift;
485   my $forVisitedLink = @_ ? shift : NOT_FOR_VISITED_LINK;
486
487   return "styleResolver.colorFromPrimitiveValue(" . $primitiveValue . ", /* forVisitedLink */ " . ($forVisitedLink ? "true" : "false") . ")";
488 }
489
490 use constant {
491   VALUE_IS_COLOR => 0,
492   VALUE_IS_PRIMITIVE => 1,
493 };
494
495 sub generateColorValueSetter {
496   my $name = shift;
497   my $value = shift;
498   my $indent = shift;
499   my $valueIsPrimitive = @_ ? shift : VALUE_IS_COLOR;
500
501   my $style = "styleResolver.style()";
502   my $setterContent .= $indent . "if (styleResolver.applyPropertyToRegularStyle())\n";
503   my $setValue = $style . "->" . $propertiesWithStyleBuilderOptions{$name}{"Setter"};
504   my $color = $valueIsPrimitive ? colorFromPrimitiveValue($value) : $value;
505   $setterContent .= $indent . "    " . $setValue . "(" . $color . ");\n";
506   $setterContent .= $indent . "if (styleResolver.applyPropertyToVisitedLinkStyle())\n";
507   $color = $valueIsPrimitive ? colorFromPrimitiveValue($value, FOR_VISITED_LINK) : $value;
508   $setterContent .= $indent . "    " . getVisitedLinkSetter($name, $style) . "(" . $color . ");\n";
509
510   return $setterContent;
511 }
512
513 sub handleCurrentColorValue {
514   my $name = shift;
515   my $primitiveValue = shift;
516   my $indent = shift;
517
518   my $code = $indent . "if (" . $primitiveValue . ".valueID() == CSSValueCurrentcolor) {\n";
519   $code .= $indent . "    applyInherit" . $nameToId{$name} . "(styleResolver);\n";
520   $code .= $indent . "    return;\n";
521   $code .= $indent . "}\n";
522   return $code;
523 }
524
525 sub generateAnimationPropertyInitialValueSetter {
526   my $name = shift;
527   my $indent = shift;
528
529   my $setterContent = "";
530   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
531   $setterContent .= $indent . "if (list.isEmpty())\n";
532   $setterContent .= $indent . "    list.append(Animation::create());\n";
533   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
534   my $initial = $propertiesWithStyleBuilderOptions{$name}{"Initial"};
535   $setterContent .= $indent . "list.animation(0)." . $setter . "(Animation::" . $initial . "());\n";
536   if ($name eq "-webkit-transition-property") {
537     $setterContent .= $indent . "list.animation(0).setAnimationMode(Animation::AnimateAll);\n";
538   }
539   $setterContent .= $indent . "for (size_t i = 1; i < list.size(); ++i)\n";
540   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
541
542   return $setterContent;
543 }
544
545 sub generateAnimationPropertyInheritValueSetter {
546   my $name = shift;
547   my $indent = shift;
548
549   my $setterContent = "";
550   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
551   $setterContent .= $indent . "const AnimationList* parentList = styleResolver.parentStyle()->" . getAnimationsOrTransitionsMethod($name) . "();\n";
552   $setterContent .= $indent . "size_t i = 0, parentSize = parentList ? parentList->size() : 0;\n";
553   $setterContent .= $indent . "for ( ; i < parentSize && parentList->animation(i)." . getTestFunction($name) . "(); ++i) {\n";
554   $setterContent .= $indent . "    if (list.size() <= i)\n";
555   $setterContent .= $indent . "        list.append(Animation::create());\n";
556   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
557   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
558   $setterContent .= $indent . "    list.animation(i)." . $setter . "(parentList->animation(i)." . $getter . "());\n";
559   $setterContent .= $indent . "    list.animation(i).setAnimationMode(parentList->animation(i).animationMode());\n";
560   $setterContent .= $indent . "}\n";
561   $setterContent .= "\n";
562   $setterContent .= $indent . "/* Reset any remaining animations to not have the property set. */\n";
563   $setterContent .= $indent . "for ( ; i < list.size(); ++i)\n";
564   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
565
566   return $setterContent;
567 }
568
569 sub generateAnimationPropertyValueSetter {
570   my $name = shift;
571   my $indent = shift;
572
573   my $setterContent = "";
574   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
575   $setterContent .= $indent . "size_t childIndex = 0;\n";
576   $setterContent .= $indent . "if (is<CSSValueList>(value)) {\n";
577   $setterContent .= $indent . "    /* Walk each value and put it into an animation, creating new animations as needed. */\n";
578   $setterContent .= $indent . "    for (auto& currentValue : downcast<CSSValueList>(value)) {\n";
579   $setterContent .= $indent . "        if (childIndex <= list.size())\n";
580   $setterContent .= $indent . "            list.append(Animation::create());\n";
581   $setterContent .= $indent . "        styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), currentValue);\n";
582   $setterContent .= $indent . "        ++childIndex;\n";
583   $setterContent .= $indent . "    }\n";
584   $setterContent .= $indent . "} else {\n";
585   $setterContent .= $indent . "    if (list.isEmpty())\n";
586   $setterContent .= $indent . "        list.append(Animation::create());\n";
587   $setterContent .= $indent . "    styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), value);\n";
588   $setterContent .= $indent . "    childIndex = 1;\n";
589   $setterContent .= $indent . "}\n";
590   $setterContent .= $indent . "for ( ; childIndex < list.size(); ++childIndex) {\n";
591   $setterContent .= $indent . "    /* Reset all remaining animations to not have the property set. */\n";
592   $setterContent .= $indent . "    list.animation(childIndex)." . getClearFunction($name) . "();\n";
593   $setterContent .= $indent . "}\n";
594
595   return $setterContent;
596 }
597
598 sub generateFillLayerPropertyInitialValueSetter {
599   my $name = shift;
600   my $indent = shift;
601
602   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
603   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
604   my $clearFunction = getClearFunction($name);
605   my $testFunction = getTestFunction($name);
606   my $initial = "FillLayer::" . $propertiesWithStyleBuilderOptions{$name}{"Initial"} . "(" . getFillLayerType($name) . ")";
607
608   my $setterContent = "";
609   $setterContent .= $indent . "// Check for (single-layer) no-op before clearing anything.\n";
610   $setterContent .= $indent . "const FillLayer& layers = *styleResolver.style()->" . getLayersFunction($name) . "();\n";
611   $setterContent .= $indent . "if (!layers.next() && (!layers." . $testFunction . "() || layers." . $getter . "() == $initial))\n";
612   $setterContent .= $indent . "    return;\n";
613   $setterContent .= "\n";
614   $setterContent .= $indent . "FillLayer* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
615   $setterContent .= $indent . "child->" . $setter . "(" . $initial . ");\n";
616   $setterContent .= $indent . "for (child = child->next(); child; child = child->next())\n";
617   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
618
619   return $setterContent;
620 }
621
622 sub generateFillLayerPropertyInheritValueSetter {
623   my $name = shift;
624   my $indent = shift;
625
626   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
627   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
628   my $clearFunction = getClearFunction($name);
629   my $testFunction = getTestFunction($name);
630
631   my $setterContent = "";
632   $setterContent .= $indent . "// Check for no-op before copying anything.\n";
633   $setterContent .= $indent . "if (*styleResolver.parentStyle()->" . getLayersFunction($name) ."() == *styleResolver.style()->" . getLayersFunction($name) . "())\n";
634   $setterContent .= $indent . "    return;\n";
635   $setterContent .= "\n";
636   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
637   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
638   $setterContent .= $indent . "for (auto* parent = styleResolver.parentStyle()->" . getLayersFunction($name) . "(); parent && parent->" . $testFunction . "(); parent = parent->next()) {\n";
639   $setterContent .= $indent . "    if (!child) {\n";
640   $setterContent .= $indent . "        previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
641   $setterContent .= $indent . "        child = previousChild->next();\n";
642   $setterContent .= $indent . "    }\n";
643   $setterContent .= $indent . "    child->" . $setter . "(parent->" . $getter . "());\n";
644   $setterContent .= $indent . "    previousChild = child;\n";
645   $setterContent .= $indent . "    child = previousChild->next();\n";
646   $setterContent .= $indent . "}\n";
647   $setterContent .= $indent . "for (; child; child = child->next())\n";
648   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
649
650   return $setterContent;
651 }
652
653 sub generateFillLayerPropertyValueSetter {
654   my $name = shift;
655   my $indent = shift;
656
657   my $CSSPropertyId = "CSSProperty" . $nameToId{$name};
658
659   my $setterContent = "";
660   $setterContent .= $indent . "FillLayer* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
661   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
662   $setterContent .= $indent . "if (is<CSSValueList>(value) && !is<CSSImageSetValue>(value)) {\n";
663   $setterContent .= $indent . "    // Walk each value and put it into a layer, creating new layers as needed.\n";
664   $setterContent .= $indent . "    for (auto& item : downcast<CSSValueList>(value)) {\n";
665   $setterContent .= $indent . "        if (!child) {\n";
666   $setterContent .= $indent . "            previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
667   $setterContent .= $indent . "            child = previousChild->next();\n";
668   $setterContent .= $indent . "        }\n";
669   $setterContent .= $indent . "        styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, item);\n";
670   $setterContent .= $indent . "        previousChild = child;\n";
671   $setterContent .= $indent . "        child = child->next();\n";
672   $setterContent .= $indent . "    }\n";
673   $setterContent .= $indent . "} else {\n";
674   $setterContent .= $indent . "    styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, value);\n";
675   $setterContent .= $indent . "    child = child->next();\n";
676   $setterContent .= $indent . "}\n";
677   $setterContent .= $indent . "for (; child; child = child->next())\n";
678   $setterContent .= $indent . "    child->" . getClearFunction($name) . "();\n";
679
680   return $setterContent;
681 }
682
683 sub generateSetValueStatement
684 {
685   my $name = shift;
686   my $value = shift;
687
688   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
689   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
690   return "styleResolver.style()->" .  ($isSVG ? "accessSVGStyle()." : "") . $setter . "(" . $value . ")";
691 }
692
693 sub generateInitialValueSetter {
694   my $name = shift;
695   my $indent = shift;
696
697   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
698   my $initial = $propertiesWithStyleBuilderOptions{$name}{"Initial"};
699   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
700   my $setterContent = "";
701   $setterContent .= $indent . "static void applyInitial" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
702   $setterContent .= $indent . "{\n";
703   my $style = "styleResolver.style()";
704   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
705     $setterContent .= $indent . "    " . getAutoSetter($name, $style) . ";\n";
706   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
707       my $initialColor = "RenderStyle::" . $initial . "()";
708       $setterContent .= generateColorValueSetter($name, $initialColor, $indent . "    ");
709   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
710     $setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . "    ");
711   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
712     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
713     $setterContent .= $indent . "    fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
714     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
715   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
716     $setterContent .= generateFillLayerPropertyInitialValueSetter($name, $indent . "    ");
717   } else {
718     my $initialValue = ($isSVG ? "SVGRenderStyle" : "RenderStyle") . "::" . $initial . "()";
719     $setterContent .= $indent . "    " . generateSetValueStatement($name, $initialValue) . ";\n";
720   }
721   $setterContent .= $indent . "}\n";
722
723   return $setterContent;
724 }
725
726 sub generateInheritValueSetter {
727   my $name = shift;
728   my $indent = shift;
729
730   my $setterContent = "";
731   $setterContent .= $indent . "static void applyInherit" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
732   $setterContent .= $indent . "{\n";
733   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"SVG"};
734   my $parentStyle = "styleResolver.parentStyle()";
735   my $style = "styleResolver.style()";
736   my $getter = $propertiesWithStyleBuilderOptions{$name}{"Getter"};
737   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
738   my $didCallSetValue = 0;
739   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
740     $setterContent .= $indent . "    if (" . getAutoGetter($name, $parentStyle) . ") {\n";
741     $setterContent .= $indent . "        " . getAutoSetter($name, $style) . ";\n";
742     $setterContent .= $indent . "        return;\n";
743     $setterContent .= $indent . "    }\n";
744   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
745     $setterContent .= $indent . "    Color color = " . $parentStyle . "->" . $getter . "();\n";
746     if (!exists($propertiesWithStyleBuilderOptions{$name}{"NoDefaultColor"})) {
747       $setterContent .= $indent . "    if (!color.isValid())\n";
748       $setterContent .= $indent . "        color = " . $parentStyle . "->color();\n";
749     }
750     $setterContent .= generateColorValueSetter($name, "color", $indent . "    ");
751     $didCallSetValue = 1;
752   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
753     $setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . "    ");
754     $didCallSetValue = 1;
755   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
756     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
757     $setterContent .= $indent . "    fontDescription." . $setter . "(styleResolver.parentFontDescription()." . $getter . "());\n";
758     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
759     $didCallSetValue = 1;
760   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
761     $setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . "    ");
762     $didCallSetValue = 1;
763   }
764   if (!$didCallSetValue) {
765     my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") .  $getter . "()";
766     $setterContent .= $indent . "    " . generateSetValueStatement($name, $inheritedValue) . ";\n";
767   }
768   $setterContent .= $indent . "}\n";
769
770   return $setterContent;
771 }
772
773 sub generateValueSetter {
774   my $name = shift;
775   my $indent = shift;
776
777   my $setterContent = "";
778   $setterContent .= $indent . "static void applyValue" . $nameToId{$name} . "(StyleResolver& styleResolver, CSSValue& value)\n";
779   $setterContent .= $indent . "{\n";
780   my $convertedValue;
781   if (exists($propertiesWithStyleBuilderOptions{$name}{"Converter"})) {
782     $convertedValue = "StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"Converter"} . "(styleResolver, value)";
783   } elsif (exists($propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"})) {
784     $setterContent .= $indent . "    auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"} . "(styleResolver, value);\n";
785     $convertedValue = "convertedValue.value()";
786   } else {
787     $convertedValue = "downcast<CSSPrimitiveValue>(value)";
788   }
789
790   my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
791   my $style = "styleResolver.style()";
792   my $didCallSetValue = 0;
793   if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
794     $setterContent .= $indent . "    if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto) {\n";
795     $setterContent .= $indent . "        ". getAutoSetter($name, $style) . ";\n";
796     $setterContent .= $indent . "        return;\n";
797     $setterContent .= $indent . "    }\n";
798   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
799     $setterContent .= $indent . "    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);\n";
800     if ($name eq "color") {
801       # The "color" property supports "currentColor" value. We should add a parameter.
802       $setterContent .= handleCurrentColorValue($name, "primitiveValue", $indent . "    ");
803     }
804     $setterContent .= generateColorValueSetter($name, "primitiveValue", $indent . "    ", VALUE_IS_PRIMITIVE);
805     $didCallSetValue = 1;
806   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
807     $setterContent .= generateAnimationPropertyValueSetter($name, $indent . "    ");
808     $didCallSetValue = 1;
809   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
810     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
811     $setterContent .= $indent . "    fontDescription." . $setter . "(" . $convertedValue . ");\n";
812     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
813     $didCallSetValue = 1;
814   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
815     $setterContent .= generateFillLayerPropertyValueSetter($name, $indent . "    ");
816     $didCallSetValue = 1;
817   }
818   if (!$didCallSetValue) {
819     if (exists($propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"})) {
820       $setterContent .= $indent . "    if (convertedValue)\n";
821       $setterContent .= "    ";
822     }
823     $setterContent .= $indent . "    " . generateSetValueStatement($name, $convertedValue) . ";\n";
824   }
825   $setterContent .= $indent . "}\n";
826
827   return $setterContent;
828 }
829
830 open STYLEBUILDER, ">StyleBuilder.cpp" || die "Could not open StyleBuilder.cpp for writing";
831 print STYLEBUILDER << "EOF";
832 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
833
834 #include "config.h"
835 #include "StyleBuilder.h"
836
837 #include "CSSPrimitiveValueMappings.h"
838 #include "CSSProperty.h"
839 #include "RenderStyle.h"
840 #include "StyleBuilderConverter.h"
841 #include "StyleBuilderCustom.h"
842 #include "StylePropertyShorthand.h"
843 #include "StyleResolver.h"
844
845 namespace WebCore {
846
847 class StyleBuilderFunctions {
848 public:
849 EOF
850
851 foreach my $name (@names) {
852   # Skip Shorthand properties and properties that do not use the StyleBuilder.
853   next if (exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
854   next if (exists $propertiesWithStyleBuilderOptions{$name}{"SkipBuilder"});
855
856   my $indent = "    ";
857   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Initial"}) {
858     print STYLEBUILDER generateInitialValueSetter($name, $indent);
859   }
860   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Inherit"}) {
861     print STYLEBUILDER generateInheritValueSetter($name, $indent);
862   }
863   if (!$propertiesWithStyleBuilderOptions{$name}{"Custom"}{"Value"}) {
864     print STYLEBUILDER generateValueSetter($name, $indent);
865   }
866 }
867
868 print STYLEBUILDER << "EOF";
869 };
870
871 void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleResolver, CSSValue& value, bool isInitial, bool isInherit)
872 {
873     switch (property) {
874     case CSSPropertyInvalid:
875     case CSSPropertyCustom:
876         break;
877 EOF
878
879 foreach my $name (@names) {
880   print STYLEBUILDER "    case CSSProperty" . $nameToId{$name} . ":\n";
881   if (exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"}) {
882     print STYLEBUILDER "        ASSERT(isShorthandCSSProperty(property));\n";
883     print STYLEBUILDER "        ASSERT_NOT_REACHED();\n";
884   } elsif (!exists $propertiesWithStyleBuilderOptions{$name}{"SkipBuilder"}) {
885     print STYLEBUILDER "        if (isInitial)\n";
886     print STYLEBUILDER "            " . getScopeForFunction($name, "Initial") . "::applyInitial" . $nameToId{$name} . "(styleResolver);\n";
887     print STYLEBUILDER "        else if (isInherit)\n";
888     print STYLEBUILDER "            " . getScopeForFunction($name, "Inherit") . "::applyInherit" . $nameToId{$name} . "(styleResolver);\n";
889     print STYLEBUILDER "        else\n";
890     print STYLEBUILDER "            " . getScopeForFunction($name, "Value") . "::applyValue" . $nameToId{$name} . "(styleResolver, value);\n";
891   }
892   print STYLEBUILDER "        break;\n";
893 }
894
895 print STYLEBUILDER << "EOF";
896     };
897 }
898
899 } // namespace WebCore
900 EOF
901
902 close STYLEBUILDER;
903
904 # Generate StylePropertyShorthandsFunctions.
905 open SHORTHANDS_H, ">StylePropertyShorthandFunctions.h" || die "Could not open StylePropertyShorthandFunctions.h for writing";
906 print SHORTHANDS_H << "EOF";
907 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
908
909 #pragma once
910
911 namespace WebCore {
912
913 class StylePropertyShorthand;
914
915 EOF
916
917 foreach my $name (@names) {
918   # Skip non-Shorthand properties.
919   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
920
921   print SHORTHANDS_H "StylePropertyShorthand " . lcfirst($nameToId{$name}) . "Shorthand();\n";
922 }
923
924 print SHORTHANDS_H << "EOF";
925
926 } // namespace WebCore
927 EOF
928
929 close SHORTHANDS_H;
930
931 open SHORTHANDS_CPP, ">StylePropertyShorthandFunctions.cpp" || die "Could not open StylePropertyShorthandFunctions.cpp for writing";
932 print SHORTHANDS_CPP << "EOF";
933 /* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
934
935 #include "config.h"
936 #include "StylePropertyShorthandFunctions.h"
937
938 #include "StylePropertyShorthand.h"
939 #include <wtf/NeverDestroyed.h>
940
941 namespace WebCore {
942
943 EOF
944
945 my %longhandToShorthands = ();
946
947 foreach my $name (@names) {
948   # Skip non-Shorthand properties.
949   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
950
951   my $lowercaseId = lcfirst($nameToId{$name});
952   my @longhands = split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
953
954   print SHORTHANDS_CPP "StylePropertyShorthand " . $lowercaseId . "Shorthand()\n";
955   print SHORTHANDS_CPP "{\n";
956   print SHORTHANDS_CPP "    static const CSSPropertyID " . $lowercaseId . "Properties[] = {\n";
957   foreach (@longhands) {
958     if ($_ eq "all") {
959         foreach my $propname (@names) {
960             next if (exists $propertiesWithStyleBuilderOptions{$propname}{"Longhands"});
961             next if ($propname eq "direction" || $propname eq "unicode-bidi");
962             die "Unknown CSS property used in all shorthand: " . $nameToId{$propname} if !exists($nameToId{$propname});
963             push(@{$longhandToShorthands{$propname}}, $name);
964             print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$propname} . ",\n";
965         }
966     } else {
967         die "Unknown CSS property used in Longhands: " . $nameToId{$_} if !exists($nameToId{$_});
968         push(@{$longhandToShorthands{$_}}, $name);
969         print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$_} . ",\n";
970     }
971   }
972   print SHORTHANDS_CPP "    };\n";
973   print SHORTHANDS_CPP "    return StylePropertyShorthand(CSSProperty" . $nameToId{$name} . ", " . $lowercaseId . "Properties);\n";
974   print SHORTHANDS_CPP "}\n\n";
975 }
976
977 print SHORTHANDS_CPP << "EOF";
978 StylePropertyShorthand shorthandForProperty(CSSPropertyID propertyID)
979 {
980     static NeverDestroyed<StylePropertyShorthand> emptyShorthand;
981
982     switch (propertyID) {
983 EOF
984
985 foreach my $name (@names) {
986   # Skip non-Shorthand properties.
987   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"Longhands"});
988
989   print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$name} . ":\n";
990   print SHORTHANDS_CPP "        return " . lcfirst($nameToId{$name}) . "Shorthand();\n";
991 }
992
993 print SHORTHANDS_CPP << "EOF";
994     default:
995         return emptyShorthand;
996     }
997 }
998 EOF
999
1000 print SHORTHANDS_CPP << "EOF";
1001 StylePropertyShorthandVector matchingShorthandsForLonghand(CSSPropertyID propertyID)
1002 {
1003     switch (propertyID) {
1004 EOF
1005
1006 sub constructShorthandsVector {
1007   my $shorthands = shift;
1008
1009   my $vector = "StylePropertyShorthandVector{";
1010   foreach my $i (0 .. $#$shorthands) {
1011     $vector .= ", " unless $i == 0;
1012     $vector .= lcfirst($nameToId{$shorthands->[$i]}) . "Shorthand()";
1013   }
1014   $vector .= "}";
1015   return $vector;
1016 }
1017
1018 my %vectorToLonghands = ();
1019 for my $longhand (sort keys %longhandToShorthands) {
1020   my @shorthands = sort(@{$longhandToShorthands{$longhand}});
1021   push(@{$vectorToLonghands{constructShorthandsVector(\@shorthands)}}, $longhand);
1022 }
1023
1024 for my $vector (sort keys %vectorToLonghands) {
1025   foreach (@{$vectorToLonghands{$vector}}) {
1026     print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$_} . ":\n";
1027   }
1028   print SHORTHANDS_CPP "        return " . $vector . ";\n";
1029 }
1030
1031 print SHORTHANDS_CPP << "EOF";
1032     default:
1033         return { };
1034     }
1035 }
1036 EOF
1037
1038 print SHORTHANDS_CPP << "EOF";
1039 } // namespace WebCore
1040 EOF
1041
1042 close SHORTHANDS_CPP;
1043
1044 if (not $gperf) {
1045     $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
1046 }
1047 system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";