Use warning-ignoring macros more consistently and simply
[WebKit.git] / Source / WebCore / css / makeprop.pl
1 #! /usr/bin/env 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-2018 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
26 use strict;
27 use warnings;
28
29 use English;
30 use File::Spec;
31 use Getopt::Long;
32 use JSON::PP;
33
34 sub addProperty($$);
35 sub isPropertyEnabled($$);
36 sub removeInactiveCodegenProperties($$);
37
38 my $inputFile = "CSSProperties.json";
39
40 my $defines = "";
41 my $gperf;
42 GetOptions('defines=s' => \$defines,
43            'gperf-executable=s' => \$gperf);
44
45 my $input;
46 {
47     local $INPUT_RECORD_SEPARATOR; # No separator; read through until end-of-file.
48     open(JSON, "<", $inputFile) or die "Cannot open $inputFile.\n";
49     $input = <JSON>;
50     close(JSON);
51 }
52
53 my $jsonDecoder = JSON::PP->new->utf8;
54 my $jsonHashRef = $jsonDecoder->decode($input);
55 my $propertiesHashRef = $jsonHashRef->{properties};
56 my @allNames = keys(%$propertiesHashRef);
57 die "We've reached more than 1024 CSS properties, please make sure to update CSSProperty/StylePropertyMetadata accordingly" if @allNames > 1024;
58
59 my %defines = map { $_ => 1 } split(/ /, $defines);
60
61 my @names;
62 my @internalProprerties;
63 my $numPredefinedProperties = 2;
64 my %nameIsInherited;
65 my %nameIsHighPriority;
66 my %propertiesWithStyleBuilderOptions;
67 my %styleBuilderOptions = (
68     "animatable" => 1, # Defined in Source/WebCore/css/StyleBuilderConverter.h
69     "auto-functions" => 1,
70     "conditional-converter" => 1,
71     "converter" => 1,
72     "custom" => 1,
73     "fill-layer-property" => 1,
74     "font-property" => 1,
75     "getter" => 1,
76     "initial" => 1,
77     "longhands" => 1,
78     "name-for-methods" => 1,
79     "no-default-color" => 1,
80     "svg" => 1,
81     "skip-builder" => 1,
82     "setter" => 1,
83     "visited-link-color-support" => 1,
84 );
85 my %nameToId;
86 my %nameToAliases;
87
88 for my $name (@allNames) {
89     my $value = $propertiesHashRef->{$name};
90     my $valueType = ref($value);
91     
92     if ($valueType eq "HASH") {
93         removeInactiveCodegenProperties($name, \%$value);
94         if (isPropertyEnabled($name, $value)) {
95             addProperty($name, $value);
96         }
97     } else {
98         die "$name does not have a supported value type. Only dictionary types are supported.";
99     }
100 }
101
102 sub matchEnableFlags($)
103 {
104     my ($enable_flag) = @_;
105     
106     if (exists($defines{$enable_flag})) {
107         return 1;
108     }
109
110     if (substr($enable_flag, 0, 1) eq "!" && !exists($defines{substr($enable_flag, 1)})) {
111         return 1;
112     }
113     
114     return 0;
115 }
116
117 sub removeInactiveCodegenProperties($$)
118 {
119     my ($name, $propertyValue) = @_;
120
121     if (!exists($propertyValue->{"codegen-properties"})) {
122         return;
123     }
124     
125     my $codegen_properties = $propertyValue->{"codegen-properties"};
126     my $valueType = ref($codegen_properties);
127
128     if ($valueType ne "ARRAY") {
129         return;
130     }
131
132     # Pick one based on "enable-if"
133     my $matching_codegen_options;
134     foreach my $entry (@{$codegen_properties}) {
135         if (!exists($entry->{"enable-if"})) {
136             print "Found 'codegen-properties' array with an unconditional entry under '$name'. This is probably unintentional.\n";
137             $matching_codegen_options = $entry;
138             last;
139         }
140
141         my $enable_flags = $entry->{"enable-if"};
142         if (matchEnableFlags($enable_flags)) {
143             $matching_codegen_options = $entry;
144             last;
145         }
146
147         $matching_codegen_options = $entry;
148     }
149     
150     $propertyValue->{"codegen-properties"} = $matching_codegen_options;
151 }
152
153 sub isPropertyEnabled($$)
154 {
155     my ($name, $propertyValue) = @_;
156
157     if (!exists($propertyValue->{"codegen-properties"})) {
158         return 1;
159     }
160     
161     my $codegen_properties = $propertyValue->{"codegen-properties"};
162     if ($codegen_properties->{"skip-codegen"}) {
163         return 0;
164     }
165
166     if (!exists($codegen_properties->{"enable-if"})) {
167         return 1;
168     }
169
170     return matchEnableFlags($codegen_properties->{"enable-if"});
171 }
172
173 sub addProperty($$)
174 {
175     my ($name, $optionsHashRef) = @_;
176
177     push @names, $name;
178
179     my $id = $name;
180     $id =~ s/(^[^-])|-(.)/uc($1||$2)/ge;
181     $nameToId{$name} = $id;
182
183     for my $optionName (keys %{$optionsHashRef}) {
184         if ($optionName eq "codegen-properties") {
185             my $codegenProperties = $optionsHashRef->{"codegen-properties"};
186             for my $codegenOptionName (keys %$codegenProperties) {
187                 if ($codegenOptionName eq "enable-if") {
188                     next;
189                 } elsif ($codegenOptionName eq "skip-codegen") {
190                     next;
191                 } elsif ($codegenOptionName eq "comment") {
192                     next;
193                 } elsif ($codegenOptionName eq "high-priority") {
194                     $nameIsHighPriority{$name} = 1;
195                 } elsif ($codegenOptionName eq "aliases") {
196                     $nameToAliases{$name} = $codegenProperties->{"aliases"};
197                 } elsif ($styleBuilderOptions{$codegenOptionName}) {
198                     $propertiesWithStyleBuilderOptions{$name}{$codegenOptionName} = $codegenProperties->{$codegenOptionName};
199                 } elsif ($codegenOptionName eq "internal-only") {
200                     # internal-only properties exist to make it easier to parse compound properties (e.g. background-repeat) as if they were shorthands.
201                     push @internalProprerties, $name
202                 } else {
203                     die "Unrecognized codegen property \"$codegenOptionName\" for $name property.";
204                 }
205             }
206         } elsif ($optionName eq "animatable") {
207              $propertiesWithStyleBuilderOptions{$name}{"animatable"} = $optionsHashRef->{"animatable"};
208         } elsif ($optionName eq "inherited") {
209             $nameIsInherited{$name} = 1;
210         } elsif ($optionName eq "values") {
211             # FIXME: Implement.
212         }
213         # We allow unrecognized options to pass through without error to support annotation.
214     }
215 }
216
217 sub sortByDescendingPriorityAndName
218 {
219     # Sort names with high priority to the front
220     if (!!$nameIsHighPriority{$a} < !!$nameIsHighPriority{$b}) {
221         return 1;
222     }
223     if (!!$nameIsHighPriority{$a} > !!$nameIsHighPriority{$b}) {
224         return -1;
225     }
226     # Sort names without leading '-' to the front
227     if (substr($a, 0, 1) eq "-" && substr($b, 0, 1) ne "-") {
228         return 1;
229     }
230     if (substr($a, 0, 1) ne "-" && substr($b, 0, 1) eq "-") {
231         return -1;
232     }
233     return $a cmp $b;
234 }
235
236 @names = sort sortByDescendingPriorityAndName @names;
237
238 open GPERF, ">CSSPropertyNames.gperf" || die "Could not open CSSPropertyNames.gperf for writing";
239 print GPERF << "EOF";
240 %{
241 /* This file is automatically generated from $inputFile by makeprop, do not edit */
242 #include "config.h"
243 #include \"CSSProperty.h\"
244 #include \"CSSPropertyNames.h\"
245 #include \"HashTools.h\"
246 #include <wtf/ASCIICType.h>
247 #include <wtf/text/AtomicString.h>
248 #include <wtf/text/WTFString.h>
249 #include <string.h>
250
251 IGNORE_WARNINGS_BEGIN(\"implicit-fallthrough\")
252
253 // Older versions of gperf like to use the `register` keyword.
254 #define register
255
256 namespace WebCore {
257
258 // Using std::numeric_limits<uint16_t>::max() here would be cleaner,
259 // but is not possible due to missing constexpr support in MSVC 2013.
260 static_assert(numCSSProperties + 1 <= 65535, "CSSPropertyID should fit into uint16_t.");
261
262 EOF
263
264 print GPERF "const char* const propertyNameStrings[numCSSProperties] = {\n";
265 foreach my $name (@names) {
266   print GPERF "    \"$name\",\n";
267 }
268 print GPERF "};\n\n";
269
270 print GPERF << "EOF";
271 %}
272 %struct-type
273 struct Property;
274 %omit-struct-type
275 %language=C++
276 %readonly-tables
277 %global-table
278 %compare-strncmp
279 %define class-name CSSPropertyNamesHash
280 %define lookup-function-name findPropertyImpl
281 %define hash-function-name propery_hash_function
282 %define word-array-name property_wordlist
283 %enum
284 %%
285 EOF
286
287 foreach my $name (@names) {
288   print GPERF $name . ", CSSProperty" . $nameToId{$name} . "\n";
289 }
290
291 for my $name (@names) {
292     if (!$nameToAliases{$name}) {
293         next;
294     }
295     for my $alias (@{$nameToAliases{$name}}) {
296         print GPERF $alias . ", CSSProperty" . $nameToId{$name} . "\n";
297     }
298 }
299
300 print GPERF << "EOF";
301 %%
302 const Property* findProperty(const char* str, unsigned int len)
303 {
304     return CSSPropertyNamesHash::findPropertyImpl(str, len);
305 }
306
307 bool isInternalCSSProperty(const CSSPropertyID id)
308 {
309     switch (id) {
310 EOF
311
312 foreach my $name (sort @internalProprerties) {
313   print GPERF "    case CSSPropertyID::CSSProperty" . $nameToId{$name} . ":\n";
314 }
315
316 print GPERF << "EOF";
317         return true;
318     default:
319         return false;
320     }
321 }
322
323 const char* getPropertyName(CSSPropertyID id)
324 {
325     if (id < firstCSSProperty)
326         return 0;
327     int index = id - firstCSSProperty;
328     if (index >= numCSSProperties)
329         return 0;
330     return propertyNameStrings[index];
331 }
332
333 const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
334 {
335     if (id < firstCSSProperty)
336         return nullAtom();
337     int index = id - firstCSSProperty;
338     if (index >= numCSSProperties)
339         return nullAtom();
340
341     static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
342     AtomicString& propertyString = propertyStrings[index];
343     if (propertyString.isNull()) {
344         const char* propertyName = propertyNameStrings[index];
345         propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
346     }
347     return propertyString;
348 }
349
350 String getPropertyNameString(CSSPropertyID id)
351 {
352     // We share the StringImpl with the AtomicStrings.
353     return getPropertyNameAtomicString(id).string();
354 }
355
356 String getJSPropertyName(CSSPropertyID id)
357 {
358     char result[maxCSSPropertyNameLength + 1];
359     const char* cssPropertyName = getPropertyName(id);
360     const char* propertyNamePointer = cssPropertyName;
361     if (!propertyNamePointer)
362         return emptyString();
363
364     char* resultPointer = result;
365     while (char character = *propertyNamePointer++) {
366         if (character == '-') {
367             char nextCharacter = *propertyNamePointer++;
368             if (!nextCharacter)
369                 break;
370             character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
371         }
372         *resultPointer++ = character;
373     }
374     *resultPointer = '\\0';
375     return WTF::String(result);
376 }
377
378 static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
379     false, // CSSPropertyInvalid
380     true, // CSSPropertyCustom
381 EOF
382
383 foreach my $name (@names) {
384   my $id = $nameToId{$name};
385   my $value = $nameIsInherited{$name} ? "true " : "false";
386   print GPERF "    $value, // CSSProperty$id\n";
387 }
388
389 print GPERF<< "EOF";
390 };
391
392 bool CSSProperty::isInheritedProperty(CSSPropertyID id)
393 {
394     ASSERT(id <= lastCSSProperty);
395     ASSERT(id != CSSPropertyInvalid);
396     return isInheritedPropertyTable[id];
397 }
398
399 Vector<String> CSSProperty::aliasesForProperty(CSSPropertyID id)
400 {
401     switch (id) {
402 EOF
403
404 for my $name (@names) {
405     if (!$nameToAliases{$name}) {
406         next;
407     }
408     print GPERF "    case CSSPropertyID::CSSProperty" . $nameToId{$name} . ":\n";
409     print GPERF "        return { \"" . join("\"_s, \"", @{$nameToAliases{$name}}) . "\"_s };\n";
410 }
411
412 print GPERF << "EOF";
413     default:
414         return { };
415     }
416 }
417
418 } // namespace WebCore
419
420 IGNORE_WARNINGS_END
421 EOF
422
423 close GPERF;
424
425 open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing";
426 print HEADER << "EOF";
427 /* This file is automatically generated from $inputFile by makeprop, do not edit */
428
429 #pragma once
430
431 #include <string.h>
432 #include <wtf/Forward.h>
433 #include <wtf/HashFunctions.h>
434 #include <wtf/HashTraits.h>
435
436 namespace WebCore {
437
438 enum CSSPropertyID : uint16_t {
439     CSSPropertyInvalid = 0,
440     CSSPropertyCustom = 1,
441 EOF
442
443 my $first = $numPredefinedProperties;
444 my $i = $numPredefinedProperties;
445 my $maxLen = 0;
446 my $lastHighPriorityPropertyName;
447 foreach my $name (@names) {
448   $lastHighPriorityPropertyName = $name if $nameIsHighPriority{$name}; # Assumes that @names is sorted by descending priorities.
449   print HEADER "    CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
450   $i = $i + 1;
451   if (length($name) > $maxLen) {
452     $maxLen = length($name);
453   }
454 }
455 my $num = $i - $first;
456 my $last = $i - 1;
457
458 print HEADER "};\n\n";
459 print HEADER "const int firstCSSProperty = $first;\n";
460 print HEADER "const int numCSSProperties = $num;\n";
461 print HEADER "const int lastCSSProperty = $last;\n";
462 print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
463 print HEADER "const CSSPropertyID lastHighPriorityProperty = CSSProperty" . $nameToId{$lastHighPriorityPropertyName} . ";\n";
464
465 print HEADER << "EOF";
466
467 bool isInternalCSSProperty(const CSSPropertyID);
468 const char* getPropertyName(CSSPropertyID);
469 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
470 WTF::String getPropertyNameString(CSSPropertyID id);
471 WTF::String getJSPropertyName(CSSPropertyID);
472
473 inline CSSPropertyID convertToCSSPropertyID(int value)
474 {
475     ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
476     return static_cast<CSSPropertyID>(value);
477 }
478
479 } // namespace WebCore
480
481 namespace WTF {
482 template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
483 template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
484     static const bool emptyValueIsZero = true;
485     static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
486     static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
487 };
488 } // namespace WTF
489
490 EOF
491
492 close HEADER;
493
494 #
495 # StyleBuilder.cpp generator.
496 #
497
498 sub getScopeForFunction {
499   my $name = shift;
500   my $builderFunction = shift;
501
502   return $propertiesWithStyleBuilderOptions{$name}{"custom"}{$builderFunction} ? "StyleBuilderCustom" : "StyleBuilderFunctions";
503 }
504
505 sub getNameForMethods {
506   my $name = shift;
507
508   my $nameForMethods = $nameToId{$name};
509   $nameForMethods =~ s/Webkit//g;
510   if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
511     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
512   }
513   return $nameForMethods;
514 }
515
516 sub getAutoGetter {
517   my $name = shift;
518   my $renderStyle = shift;
519
520   return $renderStyle . "->hasAuto" . getNameForMethods($name) . "()";
521 }
522
523 sub getAutoSetter {
524   my $name = shift;
525   my $renderStyle = shift;
526
527   return $renderStyle . "->setHasAuto" . getNameForMethods($name) . "()";
528 }
529
530 sub getVisitedLinkSetter {
531   my $name = shift;
532   my $renderStyle = shift;
533
534   return $renderStyle . "->setVisitedLink" . getNameForMethods($name);
535 }
536
537 sub getClearFunction {
538   my $name = shift;
539
540   return "clear" . getNameForMethods($name);
541 }
542
543 sub getEnsureAnimationsOrTransitionsMethod {
544   my $name = shift;
545
546   return "ensureAnimations" if $name =~ /animation-/;
547   return "ensureTransitions" if $name =~ /transition-/;
548   die "Unrecognized animation property name.";
549 }
550
551 sub getAnimationsOrTransitionsMethod {
552   my $name = shift;
553
554   return "animations" if $name =~ /animation-/;
555   return "transitions" if $name =~ /transition-/;
556   die "Unrecognized animation property name.";
557 }
558
559 sub getTestFunction {
560   my $name = shift;
561
562   return "is" . getNameForMethods($name) . "Set";
563 }
564
565 sub getAnimationMapfunction {
566   my $name = shift;
567
568   return "mapAnimation" . getNameForMethods($name);
569 }
570
571 sub getLayersFunction {
572   my $name = shift;
573
574   return "backgroundLayers" if $name =~ /background-/;
575   return "maskLayers" if $name =~ /mask-/;
576   die "Unrecognized FillLayer property name.";
577 }
578
579 sub getLayersAccessorFunction {
580   my $name = shift;
581
582   return "ensureBackgroundLayers" if $name =~ /background-/;
583   return "ensureMaskLayers" if $name =~ /mask-/;
584   die "Unrecognized FillLayer property name.";
585 }
586
587 sub getFillLayerType {
588 my $name = shift;
589
590   return "FillLayerType::Background" if $name =~ /background-/;
591   return "FillLayerType::Mask" if $name =~ /mask-/;
592 }
593
594 sub getFillLayerMapfunction {
595   my $name = shift;
596
597   return "mapFill" . getNameForMethods($name);
598 }
599
600
601 foreach my $name (@names) {
602   my $nameForMethods = getNameForMethods($name);
603   $nameForMethods =~ s/Webkit//g;
604   if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
605     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
606   }
607
608   if (!exists($propertiesWithStyleBuilderOptions{$name}{"getter"})) {
609     $propertiesWithStyleBuilderOptions{$name}{"getter"} = lcfirst($nameForMethods);
610   }
611   if (!exists($propertiesWithStyleBuilderOptions{$name}{"setter"})) {
612     $propertiesWithStyleBuilderOptions{$name}{"setter"} = "set" . $nameForMethods;
613   }
614   if (!exists($propertiesWithStyleBuilderOptions{$name}{"initial"})) {
615     if (exists($propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"})) {
616       $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initialFill" . $nameForMethods;
617     } else {
618       $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initial" . $nameForMethods;
619     }
620   }
621   # FIXME: Convert option custom from a string to an array.
622   if (!exists($propertiesWithStyleBuilderOptions{$name}{"custom"})) {
623     $propertiesWithStyleBuilderOptions{$name}{"custom"} = "";
624   } elsif ($propertiesWithStyleBuilderOptions{$name}{"custom"} eq "All") {
625     $propertiesWithStyleBuilderOptions{$name}{"custom"} = "Initial|Inherit|Value";
626   }
627   my %customValues = map { $_ => 1 } split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"custom"});
628   $propertiesWithStyleBuilderOptions{$name}{"custom"} = \%customValues;
629 }
630
631 use constant {
632   NOT_FOR_VISITED_LINK => 0,
633   FOR_VISITED_LINK => 1,
634 };
635
636 sub colorFromPrimitiveValue {
637   my $primitiveValue = shift;
638   my $forVisitedLink = @_ ? shift : NOT_FOR_VISITED_LINK;
639
640   return "styleResolver.colorFromPrimitiveValue(" . $primitiveValue . ", /* forVisitedLink */ " . ($forVisitedLink ? "true" : "false") . ")";
641 }
642
643 use constant {
644   VALUE_IS_COLOR => 0,
645   VALUE_IS_PRIMITIVE => 1,
646 };
647
648 sub generateColorValueSetter {
649   my $name = shift;
650   my $value = shift;
651   my $indent = shift;
652   my $valueIsPrimitive = @_ ? shift : VALUE_IS_COLOR;
653
654   my $style = "styleResolver.style()";
655   my $setterContent .= $indent . "if (styleResolver.applyPropertyToRegularStyle())\n";
656   my $setValue = $style . "->" . $propertiesWithStyleBuilderOptions{$name}{"setter"};
657   my $color = $valueIsPrimitive ? colorFromPrimitiveValue($value) : $value;
658   $setterContent .= $indent . "    " . $setValue . "(" . $color . ");\n";
659   $setterContent .= $indent . "if (styleResolver.applyPropertyToVisitedLinkStyle())\n";
660   $color = $valueIsPrimitive ? colorFromPrimitiveValue($value, FOR_VISITED_LINK) : $value;
661   $setterContent .= $indent . "    " . getVisitedLinkSetter($name, $style) . "(" . $color . ");\n";
662
663   return $setterContent;
664 }
665
666 sub handleCurrentColorValue {
667   my $name = shift;
668   my $primitiveValue = shift;
669   my $indent = shift;
670
671   my $code = $indent . "if (" . $primitiveValue . ".valueID() == CSSValueCurrentcolor) {\n";
672   $code .= $indent . "    applyInherit" . $nameToId{$name} . "(styleResolver);\n";
673   $code .= $indent . "    return;\n";
674   $code .= $indent . "}\n";
675   return $code;
676 }
677
678 sub generateAnimationPropertyInitialValueSetter {
679   my $name = shift;
680   my $indent = shift;
681
682   my $setterContent = "";
683   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
684   $setterContent .= $indent . "if (list.isEmpty())\n";
685   $setterContent .= $indent . "    list.append(Animation::create());\n";
686   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
687   my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
688   $setterContent .= $indent . "list.animation(0)." . $setter . "(Animation::" . $initial . "());\n";
689   if ($name eq "-webkit-transition-property") {
690     $setterContent .= $indent . "list.animation(0).setAnimationMode(Animation::AnimateAll);\n";
691   }
692   $setterContent .= $indent . "for (size_t i = 1; i < list.size(); ++i)\n";
693   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
694
695   return $setterContent;
696 }
697
698 sub generateAnimationPropertyInheritValueSetter {
699   my $name = shift;
700   my $indent = shift;
701
702   my $setterContent = "";
703   $setterContent .= $indent . "auto& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
704   $setterContent .= $indent . "auto* parentList = styleResolver.parentStyle()->" . getAnimationsOrTransitionsMethod($name) . "();\n";
705   $setterContent .= $indent . "size_t i = 0, parentSize = parentList ? parentList->size() : 0;\n";
706   $setterContent .= $indent . "for ( ; i < parentSize && parentList->animation(i)." . getTestFunction($name) . "(); ++i) {\n";
707   $setterContent .= $indent . "    if (list.size() <= i)\n";
708   $setterContent .= $indent . "        list.append(Animation::create());\n";
709   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
710   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
711   $setterContent .= $indent . "    list.animation(i)." . $setter . "(parentList->animation(i)." . $getter . "());\n";
712   $setterContent .= $indent . "    list.animation(i).setAnimationMode(parentList->animation(i).animationMode());\n";
713   $setterContent .= $indent . "}\n";
714   $setterContent .= "\n";
715   $setterContent .= $indent . "// Reset any remaining animations to not have the property set.\n";
716   $setterContent .= $indent . "for ( ; i < list.size(); ++i)\n";
717   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
718
719   return $setterContent;
720 }
721
722 sub generateAnimationPropertyValueSetter {
723   my $name = shift;
724   my $indent = shift;
725
726   my $setterContent = "";
727   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
728   $setterContent .= $indent . "size_t childIndex = 0;\n";
729   $setterContent .= $indent . "if (is<CSSValueList>(value)) {\n";
730   $setterContent .= $indent . "    /* Walk each value and put it into an animation, creating new animations as needed. */\n";
731   $setterContent .= $indent . "    for (auto& currentValue : downcast<CSSValueList>(value)) {\n";
732   $setterContent .= $indent . "        if (childIndex <= list.size())\n";
733   $setterContent .= $indent . "            list.append(Animation::create());\n";
734   $setterContent .= $indent . "        styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), currentValue);\n";
735   $setterContent .= $indent . "        ++childIndex;\n";
736   $setterContent .= $indent . "    }\n";
737   $setterContent .= $indent . "} else {\n";
738   $setterContent .= $indent . "    if (list.isEmpty())\n";
739   $setterContent .= $indent . "        list.append(Animation::create());\n";
740   $setterContent .= $indent . "    styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), value);\n";
741   $setterContent .= $indent . "    childIndex = 1;\n";
742   $setterContent .= $indent . "}\n";
743   $setterContent .= $indent . "for ( ; childIndex < list.size(); ++childIndex) {\n";
744   $setterContent .= $indent . "    /* Reset all remaining animations to not have the property set. */\n";
745   $setterContent .= $indent . "    list.animation(childIndex)." . getClearFunction($name) . "();\n";
746   $setterContent .= $indent . "}\n";
747
748   return $setterContent;
749 }
750
751 sub generateFillLayerPropertyInitialValueSetter {
752   my $name = shift;
753   my $indent = shift;
754
755   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
756   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
757   my $clearFunction = getClearFunction($name);
758   my $testFunction = getTestFunction($name);
759   my $initial = "FillLayer::" . $propertiesWithStyleBuilderOptions{$name}{"initial"} . "(" . getFillLayerType($name) . ")";
760
761   my $setterContent = "";
762   $setterContent .= $indent . "// Check for (single-layer) no-op before clearing anything.\n";
763   $setterContent .= $indent . "auto& layers = styleResolver.style()->" . getLayersFunction($name) . "();\n";
764   $setterContent .= $indent . "if (!layers.next() && (!layers." . $testFunction . "() || layers." . $getter . "() == $initial))\n";
765   $setterContent .= $indent . "    return;\n";
766   $setterContent .= "\n";
767   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
768   $setterContent .= $indent . "child->" . $setter . "(" . $initial . ");\n";
769   $setterContent .= $indent . "for (child = child->next(); child; child = child->next())\n";
770   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
771
772   return $setterContent;
773 }
774
775 sub generateFillLayerPropertyInheritValueSetter {
776   my $name = shift;
777   my $indent = shift;
778
779   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
780   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
781   my $clearFunction = getClearFunction($name);
782   my $testFunction = getTestFunction($name);
783
784   my $setterContent = "";
785   $setterContent .= $indent . "// Check for no-op before copying anything.\n";
786   $setterContent .= $indent . "if (styleResolver.parentStyle()->" . getLayersFunction($name) ."() == styleResolver.style()->" . getLayersFunction($name) . "())\n";
787   $setterContent .= $indent . "    return;\n";
788   $setterContent .= "\n";
789   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
790   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
791   $setterContent .= $indent . "for (auto* parent = &styleResolver.parentStyle()->" . getLayersFunction($name) . "(); parent && parent->" . $testFunction . "(); parent = parent->next()) {\n";
792   $setterContent .= $indent . "    if (!child) {\n";
793   $setterContent .= $indent . "        previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
794   $setterContent .= $indent . "        child = previousChild->next();\n";
795   $setterContent .= $indent . "    }\n";
796   $setterContent .= $indent . "    child->" . $setter . "(parent->" . $getter . "());\n";
797   $setterContent .= $indent . "    previousChild = child;\n";
798   $setterContent .= $indent . "    child = previousChild->next();\n";
799   $setterContent .= $indent . "}\n";
800   $setterContent .= $indent . "for (; child; child = child->next())\n";
801   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
802
803   return $setterContent;
804 }
805
806 sub generateFillLayerPropertyValueSetter {
807   my $name = shift;
808   my $indent = shift;
809
810   my $CSSPropertyId = "CSSProperty" . $nameToId{$name};
811
812   my $setterContent = "";
813   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
814   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
815   $setterContent .= $indent . "if (is<CSSValueList>(value) && !is<CSSImageSetValue>(value)) {\n";
816   $setterContent .= $indent . "    // Walk each value and put it into a layer, creating new layers as needed.\n";
817   $setterContent .= $indent . "    for (auto& item : downcast<CSSValueList>(value)) {\n";
818   $setterContent .= $indent . "        if (!child) {\n";
819   $setterContent .= $indent . "            previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
820   $setterContent .= $indent . "            child = previousChild->next();\n";
821   $setterContent .= $indent . "        }\n";
822   $setterContent .= $indent . "        styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, item);\n";
823   $setterContent .= $indent . "        previousChild = child;\n";
824   $setterContent .= $indent . "        child = child->next();\n";
825   $setterContent .= $indent . "    }\n";
826   $setterContent .= $indent . "} else {\n";
827   $setterContent .= $indent . "    styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, value);\n";
828   $setterContent .= $indent . "    child = child->next();\n";
829   $setterContent .= $indent . "}\n";
830   $setterContent .= $indent . "for (; child; child = child->next())\n";
831   $setterContent .= $indent . "    child->" . getClearFunction($name) . "();\n";
832
833   return $setterContent;
834 }
835
836 sub generateSetValueStatement
837 {
838   my $name = shift;
839   my $value = shift;
840
841   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
842   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
843   return "styleResolver.style()->" .  ($isSVG ? "accessSVGStyle()." : "") . $setter . "(" . $value . ")";
844 }
845
846 sub generateInitialValueSetter {
847   my $name = shift;
848   my $indent = shift;
849
850   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
851   my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
852   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
853   my $setterContent = "";
854   $setterContent .= $indent . "static void applyInitial" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
855   $setterContent .= $indent . "{\n";
856   my $style = "styleResolver.style()";
857   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
858     $setterContent .= $indent . "    " . getAutoSetter($name, $style) . ";\n";
859   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
860       my $initialColor = "RenderStyle::" . $initial . "()";
861       $setterContent .= generateColorValueSetter($name, $initialColor, $indent . "    ");
862   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
863     $setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . "    ");
864   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
865     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
866     $setterContent .= $indent . "    fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
867     $setterContent .= $indent . "    styleResolver.setFontDescription(WTFMove(fontDescription));\n";
868   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
869     $setterContent .= generateFillLayerPropertyInitialValueSetter($name, $indent . "    ");
870   } else {
871     my $initialValue = ($isSVG ? "SVGRenderStyle" : "RenderStyle") . "::" . $initial . "()";
872     $setterContent .= $indent . "    " . generateSetValueStatement($name, $initialValue) . ";\n";
873   }
874   $setterContent .= $indent . "}\n";
875
876   return $setterContent;
877 }
878
879 sub generateInheritValueSetter {
880   my $name = shift;
881   my $indent = shift;
882
883   my $setterContent = "";
884   $setterContent .= $indent . "static void applyInherit" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
885   $setterContent .= $indent . "{\n";
886   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
887   my $parentStyle = "styleResolver.parentStyle()";
888   my $style = "styleResolver.style()";
889   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
890   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
891   my $didCallSetValue = 0;
892   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
893     $setterContent .= $indent . "    if (" . getAutoGetter($name, $parentStyle) . ") {\n";
894     $setterContent .= $indent . "        " . getAutoSetter($name, $style) . ";\n";
895     $setterContent .= $indent . "        return;\n";
896     $setterContent .= $indent . "    }\n";
897   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
898     $setterContent .= $indent . "    Color color = " . $parentStyle . "->" . $getter . "();\n";
899     if (!exists($propertiesWithStyleBuilderOptions{$name}{"no-default-color"})) {
900       $setterContent .= $indent . "    if (!color.isValid())\n";
901       $setterContent .= $indent . "        color = " . $parentStyle . "->color();\n";
902     }
903     $setterContent .= generateColorValueSetter($name, "color", $indent . "    ");
904     $didCallSetValue = 1;
905   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
906     $setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . "    ");
907     $didCallSetValue = 1;
908   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
909     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
910     $setterContent .= $indent . "    fontDescription." . $setter . "(styleResolver.parentFontDescription()." . $getter . "());\n";
911     $setterContent .= $indent . "    styleResolver.setFontDescription(WTFMove(fontDescription));\n";
912     $didCallSetValue = 1;
913   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
914     $setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . "    ");
915     $didCallSetValue = 1;
916   }
917   if (!$didCallSetValue) {
918     my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") .  $getter . "()";
919     $setterContent .= $indent . "    " . generateSetValueStatement($name, "forwardInheritedValue(" . $inheritedValue . ")") . ";\n";
920   }
921   $setterContent .= $indent . "}\n";
922
923   return $setterContent;
924 }
925
926 sub generateValueSetter {
927   my $name = shift;
928   my $indent = shift;
929
930   my $setterContent = "";
931   $setterContent .= $indent . "static void applyValue" . $nameToId{$name} . "(StyleResolver& styleResolver, CSSValue& value)\n";
932   $setterContent .= $indent . "{\n";
933   my $convertedValue;
934   if (exists($propertiesWithStyleBuilderOptions{$name}{"converter"})) {
935     $convertedValue = "StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"converter"} . "(styleResolver, value)";
936   } elsif (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
937     $setterContent .= $indent . "    auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"conditional-converter"} . "(styleResolver, value);\n";
938     $convertedValue = "WTFMove(convertedValue.value())";
939   } else {
940     $convertedValue = "downcast<CSSPrimitiveValue>(value)";
941   }
942
943   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
944   my $style = "styleResolver.style()";
945   my $didCallSetValue = 0;
946   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
947     $setterContent .= $indent . "    if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto) {\n";
948     $setterContent .= $indent . "        ". getAutoSetter($name, $style) . ";\n";
949     $setterContent .= $indent . "        return;\n";
950     $setterContent .= $indent . "    }\n";
951   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
952     $setterContent .= $indent . "    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);\n";
953     if ($name eq "color") {
954       # The "color" property supports "currentColor" value. We should add a parameter.
955       $setterContent .= handleCurrentColorValue($name, "primitiveValue", $indent . "    ");
956     }
957     $setterContent .= generateColorValueSetter($name, "primitiveValue", $indent . "    ", VALUE_IS_PRIMITIVE);
958     $didCallSetValue = 1;
959   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
960     $setterContent .= generateAnimationPropertyValueSetter($name, $indent . "    ");
961     $didCallSetValue = 1;
962   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
963     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
964     $setterContent .= $indent . "    fontDescription." . $setter . "(" . $convertedValue . ");\n";
965     $setterContent .= $indent . "    styleResolver.setFontDescription(WTFMove(fontDescription));\n";
966     $didCallSetValue = 1;
967   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
968     $setterContent .= generateFillLayerPropertyValueSetter($name, $indent . "    ");
969     $didCallSetValue = 1;
970   }
971   if (!$didCallSetValue) {
972     if (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
973       $setterContent .= $indent . "    if (convertedValue)\n";
974       $setterContent .= "    ";
975     }
976     $setterContent .= $indent . "    " . generateSetValueStatement($name, $convertedValue) . ";\n";
977   }
978   $setterContent .= $indent . "}\n";
979
980   return $setterContent;
981 }
982
983 open STYLEBUILDER, ">StyleBuilder.cpp" || die "Could not open StyleBuilder.cpp for writing";
984 print STYLEBUILDER << "EOF";
985 /* This file is automatically generated from $inputFile by makeprop, do not edit */
986
987 #include "config.h"
988 #include "StyleBuilder.h"
989
990 #include "CSSPrimitiveValueMappings.h"
991 #include "CSSProperty.h"
992 #include "RenderStyle.h"
993 #include "StyleBuilderConverter.h"
994 #include "StyleBuilderCustom.h"
995 #include "StylePropertyShorthand.h"
996 #include "StyleResolver.h"
997
998 namespace WebCore {
999
1000 class StyleBuilderFunctions {
1001 public:
1002 EOF
1003
1004 foreach my $name (@names) {
1005   # Skip Shorthand properties and properties that do not use the StyleBuilder.
1006   next if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1007   next if (exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"});
1008
1009   my $indent = "    ";
1010   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Initial"}) {
1011     print STYLEBUILDER generateInitialValueSetter($name, $indent);
1012   }
1013   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Inherit"}) {
1014     print STYLEBUILDER generateInheritValueSetter($name, $indent);
1015   }
1016   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Value"}) {
1017     print STYLEBUILDER generateValueSetter($name, $indent);
1018   }
1019 }
1020
1021 print STYLEBUILDER << "EOF";
1022 };
1023
1024 void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleResolver, CSSValue& value, bool isInitial, bool isInherit, const CSSRegisteredCustomProperty* registered)
1025 {
1026     switch (property) {
1027     case CSSPropertyInvalid:
1028         break;
1029     case CSSPropertyCustom: {
1030         auto& customProperty = downcast<CSSCustomPropertyValue>(value);
1031         if (isInitial)
1032             StyleBuilderCustom::applyInitialCustomProperty(styleResolver, registered, customProperty.name());
1033         else if (isInherit)
1034             StyleBuilderCustom::applyInheritCustomProperty(styleResolver, registered, customProperty.name());
1035         else
1036             StyleBuilderCustom::applyValueCustomProperty(styleResolver, registered, customProperty);
1037         break;
1038     }
1039 EOF
1040
1041 foreach my $name (@names) {
1042   print STYLEBUILDER "    case CSSProperty" . $nameToId{$name} . ":\n";
1043   if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"}) {
1044     print STYLEBUILDER "        ASSERT(isShorthandCSSProperty(property));\n";
1045     print STYLEBUILDER "        ASSERT_NOT_REACHED();\n";
1046   } elsif (!exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"}) {
1047     print STYLEBUILDER "        if (isInitial)\n";
1048     print STYLEBUILDER "            " . getScopeForFunction($name, "Initial") . "::applyInitial" . $nameToId{$name} . "(styleResolver);\n";
1049     print STYLEBUILDER "        else if (isInherit)\n";
1050     print STYLEBUILDER "            " . getScopeForFunction($name, "Inherit") . "::applyInherit" . $nameToId{$name} . "(styleResolver);\n";
1051     print STYLEBUILDER "        else\n";
1052     print STYLEBUILDER "            " . getScopeForFunction($name, "Value") . "::applyValue" . $nameToId{$name} . "(styleResolver, value);\n";
1053   }
1054   print STYLEBUILDER "        break;\n";
1055 }
1056
1057 print STYLEBUILDER << "EOF";
1058     };
1059 }
1060
1061 } // namespace WebCore
1062 EOF
1063
1064 close STYLEBUILDER;
1065
1066 # Generate StylePropertyShorthandsFunctions.
1067 open SHORTHANDS_H, ">", "StylePropertyShorthandFunctions.h" or die "Could not open StylePropertyShorthandFunctions.h for writing\n";
1068 print SHORTHANDS_H << "EOF";
1069 // This file is automatically generated from $inputFile by the makeprop.pl script. Do not edit it.
1070
1071 #pragma once
1072
1073 namespace WebCore {
1074
1075 class StylePropertyShorthand;
1076
1077 EOF
1078
1079 foreach my $name (@names) {
1080   # Skip non-Shorthand properties.
1081   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1082
1083   print SHORTHANDS_H "StylePropertyShorthand " . lcfirst($nameToId{$name}) . "Shorthand();\n";
1084 }
1085
1086 print SHORTHANDS_H << "EOF";
1087
1088 } // namespace WebCore
1089 EOF
1090
1091 close SHORTHANDS_H;
1092
1093 open SHORTHANDS_CPP, ">", "StylePropertyShorthandFunctions.cpp" or die "Could not open StylePropertyShorthandFunctions.cpp for writing\n";
1094 print SHORTHANDS_CPP << "EOF";
1095 // This file is automatically generated from $inputFile by the makeprop.pl script. Do not edit it.
1096
1097 #include "config.h"
1098 #include "StylePropertyShorthandFunctions.h"
1099
1100 #include "StylePropertyShorthand.h"
1101
1102 namespace WebCore {
1103
1104 EOF
1105
1106 my %longhandToShorthands = ();
1107
1108 foreach my $name (@names) {
1109   # Skip non-Shorthand properties.
1110   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1111
1112   my $lowercaseId = lcfirst($nameToId{$name});
1113   my @longhands = @{$propertiesWithStyleBuilderOptions{$name}{"longhands"}};
1114
1115   print SHORTHANDS_CPP "StylePropertyShorthand " . $lowercaseId . "Shorthand()\n";
1116   print SHORTHANDS_CPP "{\n";
1117   print SHORTHANDS_CPP "    static const CSSPropertyID " . $lowercaseId . "Properties[] = {\n";
1118   foreach (@longhands) {
1119     if ($_ eq "all") {
1120         foreach my $propname (@names) {
1121             next if (exists $propertiesWithStyleBuilderOptions{$propname}{"longhands"});
1122             next if ($propname eq "direction" || $propname eq "unicode-bidi");
1123             die "Unknown CSS property used in all shorthand: $propname" if !exists($nameToId{$propname});
1124             push(@{$longhandToShorthands{$propname}}, $name);
1125             print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$propname} . ",\n";
1126         }
1127     } else {
1128         die "Unknown CSS property used in longhands: $_" if !exists($nameToId{$_});
1129         push(@{$longhandToShorthands{$_}}, $name);
1130         print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$_} . ",\n";
1131     }
1132   }
1133   print SHORTHANDS_CPP "    };\n";
1134   print SHORTHANDS_CPP "    return StylePropertyShorthand(CSSProperty" . $nameToId{$name} . ", " . $lowercaseId . "Properties);\n";
1135   print SHORTHANDS_CPP "}\n\n";
1136 }
1137
1138 print SHORTHANDS_CPP << "EOF";
1139 StylePropertyShorthand shorthandForProperty(CSSPropertyID propertyID)
1140 {
1141     switch (propertyID) {
1142 EOF
1143
1144 foreach my $name (@names) {
1145   # Skip non-Shorthand properties.
1146   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1147
1148   print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$name} . ":\n";
1149   print SHORTHANDS_CPP "        return " . lcfirst($nameToId{$name}) . "Shorthand();\n";
1150 }
1151
1152 print SHORTHANDS_CPP << "EOF";
1153     default:
1154         return { };
1155     }
1156 }
1157 EOF
1158
1159 print SHORTHANDS_CPP << "EOF";
1160 StylePropertyShorthandVector matchingShorthandsForLonghand(CSSPropertyID propertyID)
1161 {
1162     switch (propertyID) {
1163 EOF
1164
1165 sub constructShorthandsVector {
1166   my $shorthands = shift;
1167
1168   my $vector = "StylePropertyShorthandVector{";
1169   foreach my $i (0 .. $#$shorthands) {
1170     $vector .= ", " unless $i == 0;
1171     $vector .= lcfirst($nameToId{$shorthands->[$i]}) . "Shorthand()";
1172   }
1173   $vector .= "}";
1174   return $vector;
1175 }
1176
1177 my %vectorToLonghands = ();
1178 for my $longhand (sort keys %longhandToShorthands) {
1179   my @shorthands = sort(@{$longhandToShorthands{$longhand}});
1180   push(@{$vectorToLonghands{constructShorthandsVector(\@shorthands)}}, $longhand);
1181 }
1182
1183 for my $vector (sort keys %vectorToLonghands) {
1184   foreach (@{$vectorToLonghands{$vector}}) {
1185     print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$_} . ":\n";
1186   }
1187   print SHORTHANDS_CPP "        return " . $vector . ";\n";
1188 }
1189
1190 print SHORTHANDS_CPP << "EOF";
1191     default:
1192         return { };
1193     }
1194 }
1195 EOF
1196
1197 print SHORTHANDS_CPP << "EOF";
1198 } // namespace WebCore
1199 EOF
1200
1201 close SHORTHANDS_CPP;
1202
1203 if (not $gperf) {
1204     $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
1205 }
1206 system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";