Improve use of NeverDestroyed
[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-2017 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 <string.h>
247
248 #include <wtf/ASCIICType.h>
249 #include <wtf/text/AtomicString.h>
250 #include <wtf/text/WTFString.h>
251
252 #if defined(__clang__)
253 #pragma clang diagnostic push
254 #pragma clang diagnostic ignored \"-Wunknown-pragmas\"
255 #pragma clang diagnostic ignored \"-Wdeprecated-register\"
256 #pragma clang diagnostic ignored \"-Wimplicit-fallthrough\"
257 #endif
258
259 namespace WebCore {
260
261 // Using std::numeric_limits<uint16_t>::max() here would be cleaner,
262 // but is not possible due to missing constexpr support in MSVC 2013.
263 static_assert(numCSSProperties + 1 <= 65535, "CSSPropertyID should fit into uint16_t.");
264
265 EOF
266
267 print GPERF "const char* const propertyNameStrings[numCSSProperties] = {\n";
268 foreach my $name (@names) {
269   print GPERF "    \"$name\",\n";
270 }
271 print GPERF "};\n\n";
272
273 print GPERF << "EOF";
274 %}
275 %struct-type
276 struct Property;
277 %omit-struct-type
278 %language=C++
279 %readonly-tables
280 %global-table
281 %compare-strncmp
282 %define class-name CSSPropertyNamesHash
283 %define lookup-function-name findPropertyImpl
284 %define hash-function-name propery_hash_function
285 %define word-array-name property_wordlist
286 %enum
287 %%
288 EOF
289
290 foreach my $name (@names) {
291   print GPERF $name . ", CSSProperty" . $nameToId{$name} . "\n";
292 }
293
294 for my $name (@names) {
295     if (!$nameToAliases{$name}) {
296         next;
297     }
298     for my $alias (@{$nameToAliases{$name}}) {
299         print GPERF $alias . ", CSSProperty" . $nameToId{$name} . "\n";
300     }
301 }
302
303 print GPERF << "EOF";
304 %%
305 const Property* findProperty(const char* str, unsigned int len)
306 {
307     return CSSPropertyNamesHash::findPropertyImpl(str, len);
308 }
309
310 bool isInternalCSSProperty(const CSSPropertyID id)
311 {
312     switch (id) {
313 EOF
314
315 foreach my $name (sort @internalProprerties) {
316   print GPERF "    case CSSPropertyID::CSSProperty" . $nameToId{$name} . ":\n";
317 }
318
319 print GPERF << "EOF";
320         return true;
321     default:
322         return false;
323     }
324 }
325
326 const char* getPropertyName(CSSPropertyID id)
327 {
328     if (id < firstCSSProperty)
329         return 0;
330     int index = id - firstCSSProperty;
331     if (index >= numCSSProperties)
332         return 0;
333     return propertyNameStrings[index];
334 }
335
336 const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
337 {
338     if (id < firstCSSProperty)
339         return nullAtom();
340     int index = id - firstCSSProperty;
341     if (index >= numCSSProperties)
342         return nullAtom();
343
344     static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
345     AtomicString& propertyString = propertyStrings[index];
346     if (propertyString.isNull()) {
347         const char* propertyName = propertyNameStrings[index];
348         propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
349     }
350     return propertyString;
351 }
352
353 String getPropertyNameString(CSSPropertyID id)
354 {
355     // We share the StringImpl with the AtomicStrings.
356     return getPropertyNameAtomicString(id).string();
357 }
358
359 String getJSPropertyName(CSSPropertyID id)
360 {
361     char result[maxCSSPropertyNameLength + 1];
362     const char* cssPropertyName = getPropertyName(id);
363     const char* propertyNamePointer = cssPropertyName;
364     if (!propertyNamePointer)
365         return emptyString();
366
367     char* resultPointer = result;
368     while (char character = *propertyNamePointer++) {
369         if (character == '-') {
370             char nextCharacter = *propertyNamePointer++;
371             if (!nextCharacter)
372                 break;
373             character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
374         }
375         *resultPointer++ = character;
376     }
377     *resultPointer = '\\0';
378     return WTF::String(result);
379 }
380
381 static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
382     false, // CSSPropertyInvalid
383     true, // CSSPropertyCustom
384 EOF
385
386 foreach my $name (@names) {
387   my $id = $nameToId{$name};
388   my $value = $nameIsInherited{$name} ? "true " : "false";
389   print GPERF "    $value, // CSSProperty$id\n";
390 }
391
392 print GPERF<< "EOF";
393 };
394
395 bool CSSProperty::isInheritedProperty(CSSPropertyID id)
396 {
397     ASSERT(id <= lastCSSProperty);
398     ASSERT(id != CSSPropertyInvalid);
399     return isInheritedPropertyTable[id];
400 }
401
402 } // namespace WebCore
403
404 #if defined(__clang__)
405 #pragma clang diagnostic pop
406 #endif
407 EOF
408
409 close GPERF;
410
411 open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing";
412 print HEADER << "EOF";
413 /* This file is automatically generated from $inputFile by makeprop, do not edit */
414
415 #pragma once
416
417 #include <string.h>
418 #include <wtf/HashFunctions.h>
419 #include <wtf/HashTraits.h>
420
421 namespace WTF {
422 class AtomicString;
423 class String;
424 }
425
426 namespace WebCore {
427
428 enum CSSPropertyID : uint16_t {
429     CSSPropertyInvalid = 0,
430     CSSPropertyCustom = 1,
431 EOF
432
433 my $first = $numPredefinedProperties;
434 my $i = $numPredefinedProperties;
435 my $maxLen = 0;
436 my $lastHighPriorityPropertyName;
437 foreach my $name (@names) {
438   $lastHighPriorityPropertyName = $name if $nameIsHighPriority{$name}; # Assumes that @names is sorted by descending priorities.
439   print HEADER "    CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
440   $i = $i + 1;
441   if (length($name) > $maxLen) {
442     $maxLen = length($name);
443   }
444 }
445 my $num = $i - $first;
446 my $last = $i - 1;
447
448 print HEADER "};\n\n";
449 print HEADER "const int firstCSSProperty = $first;\n";
450 print HEADER "const int numCSSProperties = $num;\n";
451 print HEADER "const int lastCSSProperty = $last;\n";
452 print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
453 print HEADER "const CSSPropertyID lastHighPriorityProperty = CSSProperty" . $nameToId{$lastHighPriorityPropertyName} . ";\n";
454
455 print HEADER << "EOF";
456
457 bool isInternalCSSProperty(const CSSPropertyID);
458 const char* getPropertyName(CSSPropertyID);
459 const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
460 WTF::String getPropertyNameString(CSSPropertyID id);
461 WTF::String getJSPropertyName(CSSPropertyID);
462
463 inline CSSPropertyID convertToCSSPropertyID(int value)
464 {
465     ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
466     return static_cast<CSSPropertyID>(value);
467 }
468
469 } // namespace WebCore
470
471 namespace WTF {
472 template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
473 template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
474     static const bool emptyValueIsZero = true;
475     static const bool needsDestruction = false;
476     static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
477     static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
478 };
479 } // namespace WTF
480
481 EOF
482
483 close HEADER;
484
485 #
486 # StyleBuilder.cpp generator.
487 #
488
489 sub getScopeForFunction {
490   my $name = shift;
491   my $builderFunction = shift;
492
493   return $propertiesWithStyleBuilderOptions{$name}{"custom"}{$builderFunction} ? "StyleBuilderCustom" : "StyleBuilderFunctions";
494 }
495
496 sub getNameForMethods {
497   my $name = shift;
498
499   my $nameForMethods = $nameToId{$name};
500   $nameForMethods =~ s/Webkit//g;
501   if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
502     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
503   }
504   return $nameForMethods;
505 }
506
507 sub getAutoGetter {
508   my $name = shift;
509   my $renderStyle = shift;
510
511   return $renderStyle . "->hasAuto" . getNameForMethods($name) . "()";
512 }
513
514 sub getAutoSetter {
515   my $name = shift;
516   my $renderStyle = shift;
517
518   return $renderStyle . "->setHasAuto" . getNameForMethods($name) . "()";
519 }
520
521 sub getVisitedLinkSetter {
522   my $name = shift;
523   my $renderStyle = shift;
524
525   return $renderStyle . "->setVisitedLink" . getNameForMethods($name);
526 }
527
528 sub getClearFunction {
529   my $name = shift;
530
531   return "clear" . getNameForMethods($name);
532 }
533
534 sub getEnsureAnimationsOrTransitionsMethod {
535   my $name = shift;
536
537   return "ensureAnimations" if $name =~ /animation-/;
538   return "ensureTransitions" if $name =~ /transition-/;
539   die "Unrecognized animation property name.";
540 }
541
542 sub getAnimationsOrTransitionsMethod {
543   my $name = shift;
544
545   return "animations" if $name =~ /animation-/;
546   return "transitions" if $name =~ /transition-/;
547   die "Unrecognized animation property name.";
548 }
549
550 sub getTestFunction {
551   my $name = shift;
552
553   return "is" . getNameForMethods($name) . "Set";
554 }
555
556 sub getAnimationMapfunction {
557   my $name = shift;
558
559   return "mapAnimation" . getNameForMethods($name);
560 }
561
562 sub getLayersFunction {
563   my $name = shift;
564
565   return "backgroundLayers" if $name =~ /background-/;
566   return "maskLayers" if $name =~ /mask-/;
567   die "Unrecognized FillLayer property name.";
568 }
569
570 sub getLayersAccessorFunction {
571   my $name = shift;
572
573   return "ensureBackgroundLayers" if $name =~ /background-/;
574   return "ensureMaskLayers" if $name =~ /mask-/;
575   die "Unrecognized FillLayer property name.";
576 }
577
578 sub getFillLayerType {
579 my $name = shift;
580
581   return "BackgroundFillLayer" if $name =~ /background-/;
582   return "MaskFillLayer" if $name =~ /mask-/;
583 }
584
585 sub getFillLayerMapfunction {
586   my $name = shift;
587
588   return "mapFill" . getNameForMethods($name);
589 }
590
591
592 foreach my $name (@names) {
593   my $nameForMethods = getNameForMethods($name);
594   $nameForMethods =~ s/Webkit//g;
595   if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
596     $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
597   }
598
599   if (!exists($propertiesWithStyleBuilderOptions{$name}{"getter"})) {
600     $propertiesWithStyleBuilderOptions{$name}{"getter"} = lcfirst($nameForMethods);
601   }
602   if (!exists($propertiesWithStyleBuilderOptions{$name}{"setter"})) {
603     $propertiesWithStyleBuilderOptions{$name}{"setter"} = "set" . $nameForMethods;
604   }
605   if (!exists($propertiesWithStyleBuilderOptions{$name}{"initial"})) {
606     if (exists($propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"})) {
607       $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initialFill" . $nameForMethods;
608     } else {
609       $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initial" . $nameForMethods;
610     }
611   }
612   # FIXME: Convert option custom from a string to an array.
613   if (!exists($propertiesWithStyleBuilderOptions{$name}{"custom"})) {
614     $propertiesWithStyleBuilderOptions{$name}{"custom"} = "";
615   } elsif ($propertiesWithStyleBuilderOptions{$name}{"custom"} eq "All") {
616     $propertiesWithStyleBuilderOptions{$name}{"custom"} = "Initial|Inherit|Value";
617   }
618   my %customValues = map { $_ => 1 } split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"custom"});
619   $propertiesWithStyleBuilderOptions{$name}{"custom"} = \%customValues;
620 }
621
622 use constant {
623   NOT_FOR_VISITED_LINK => 0,
624   FOR_VISITED_LINK => 1,
625 };
626
627 sub colorFromPrimitiveValue {
628   my $primitiveValue = shift;
629   my $forVisitedLink = @_ ? shift : NOT_FOR_VISITED_LINK;
630
631   return "styleResolver.colorFromPrimitiveValue(" . $primitiveValue . ", /* forVisitedLink */ " . ($forVisitedLink ? "true" : "false") . ")";
632 }
633
634 use constant {
635   VALUE_IS_COLOR => 0,
636   VALUE_IS_PRIMITIVE => 1,
637 };
638
639 sub generateColorValueSetter {
640   my $name = shift;
641   my $value = shift;
642   my $indent = shift;
643   my $valueIsPrimitive = @_ ? shift : VALUE_IS_COLOR;
644
645   my $style = "styleResolver.style()";
646   my $setterContent .= $indent . "if (styleResolver.applyPropertyToRegularStyle())\n";
647   my $setValue = $style . "->" . $propertiesWithStyleBuilderOptions{$name}{"setter"};
648   my $color = $valueIsPrimitive ? colorFromPrimitiveValue($value) : $value;
649   $setterContent .= $indent . "    " . $setValue . "(" . $color . ");\n";
650   $setterContent .= $indent . "if (styleResolver.applyPropertyToVisitedLinkStyle())\n";
651   $color = $valueIsPrimitive ? colorFromPrimitiveValue($value, FOR_VISITED_LINK) : $value;
652   $setterContent .= $indent . "    " . getVisitedLinkSetter($name, $style) . "(" . $color . ");\n";
653
654   return $setterContent;
655 }
656
657 sub handleCurrentColorValue {
658   my $name = shift;
659   my $primitiveValue = shift;
660   my $indent = shift;
661
662   my $code = $indent . "if (" . $primitiveValue . ".valueID() == CSSValueCurrentcolor) {\n";
663   $code .= $indent . "    applyInherit" . $nameToId{$name} . "(styleResolver);\n";
664   $code .= $indent . "    return;\n";
665   $code .= $indent . "}\n";
666   return $code;
667 }
668
669 sub generateAnimationPropertyInitialValueSetter {
670   my $name = shift;
671   my $indent = shift;
672
673   my $setterContent = "";
674   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
675   $setterContent .= $indent . "if (list.isEmpty())\n";
676   $setterContent .= $indent . "    list.append(Animation::create());\n";
677   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
678   my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
679   $setterContent .= $indent . "list.animation(0)." . $setter . "(Animation::" . $initial . "());\n";
680   if ($name eq "-webkit-transition-property") {
681     $setterContent .= $indent . "list.animation(0).setAnimationMode(Animation::AnimateAll);\n";
682   }
683   $setterContent .= $indent . "for (size_t i = 1; i < list.size(); ++i)\n";
684   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
685
686   return $setterContent;
687 }
688
689 sub generateAnimationPropertyInheritValueSetter {
690   my $name = shift;
691   my $indent = shift;
692
693   my $setterContent = "";
694   $setterContent .= $indent . "auto& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
695   $setterContent .= $indent . "auto* parentList = styleResolver.parentStyle()->" . getAnimationsOrTransitionsMethod($name) . "();\n";
696   $setterContent .= $indent . "size_t i = 0, parentSize = parentList ? parentList->size() : 0;\n";
697   $setterContent .= $indent . "for ( ; i < parentSize && parentList->animation(i)." . getTestFunction($name) . "(); ++i) {\n";
698   $setterContent .= $indent . "    if (list.size() <= i)\n";
699   $setterContent .= $indent . "        list.append(Animation::create());\n";
700   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
701   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
702   $setterContent .= $indent . "    list.animation(i)." . $setter . "(parentList->animation(i)." . $getter . "());\n";
703   $setterContent .= $indent . "    list.animation(i).setAnimationMode(parentList->animation(i).animationMode());\n";
704   $setterContent .= $indent . "}\n";
705   $setterContent .= "\n";
706   $setterContent .= $indent . "// Reset any remaining animations to not have the property set.\n";
707   $setterContent .= $indent . "for ( ; i < list.size(); ++i)\n";
708   $setterContent .= $indent . "    list.animation(i)." . getClearFunction($name) . "();\n";
709
710   return $setterContent;
711 }
712
713 sub generateAnimationPropertyValueSetter {
714   my $name = shift;
715   my $indent = shift;
716
717   my $setterContent = "";
718   $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
719   $setterContent .= $indent . "size_t childIndex = 0;\n";
720   $setterContent .= $indent . "if (is<CSSValueList>(value)) {\n";
721   $setterContent .= $indent . "    /* Walk each value and put it into an animation, creating new animations as needed. */\n";
722   $setterContent .= $indent . "    for (auto& currentValue : downcast<CSSValueList>(value)) {\n";
723   $setterContent .= $indent . "        if (childIndex <= list.size())\n";
724   $setterContent .= $indent . "            list.append(Animation::create());\n";
725   $setterContent .= $indent . "        styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), currentValue);\n";
726   $setterContent .= $indent . "        ++childIndex;\n";
727   $setterContent .= $indent . "    }\n";
728   $setterContent .= $indent . "} else {\n";
729   $setterContent .= $indent . "    if (list.isEmpty())\n";
730   $setterContent .= $indent . "        list.append(Animation::create());\n";
731   $setterContent .= $indent . "    styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), value);\n";
732   $setterContent .= $indent . "    childIndex = 1;\n";
733   $setterContent .= $indent . "}\n";
734   $setterContent .= $indent . "for ( ; childIndex < list.size(); ++childIndex) {\n";
735   $setterContent .= $indent . "    /* Reset all remaining animations to not have the property set. */\n";
736   $setterContent .= $indent . "    list.animation(childIndex)." . getClearFunction($name) . "();\n";
737   $setterContent .= $indent . "}\n";
738
739   return $setterContent;
740 }
741
742 sub generateFillLayerPropertyInitialValueSetter {
743   my $name = shift;
744   my $indent = shift;
745
746   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
747   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
748   my $clearFunction = getClearFunction($name);
749   my $testFunction = getTestFunction($name);
750   my $initial = "FillLayer::" . $propertiesWithStyleBuilderOptions{$name}{"initial"} . "(" . getFillLayerType($name) . ")";
751
752   my $setterContent = "";
753   $setterContent .= $indent . "// Check for (single-layer) no-op before clearing anything.\n";
754   $setterContent .= $indent . "auto& layers = styleResolver.style()->" . getLayersFunction($name) . "();\n";
755   $setterContent .= $indent . "if (!layers.next() && (!layers." . $testFunction . "() || layers." . $getter . "() == $initial))\n";
756   $setterContent .= $indent . "    return;\n";
757   $setterContent .= "\n";
758   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
759   $setterContent .= $indent . "child->" . $setter . "(" . $initial . ");\n";
760   $setterContent .= $indent . "for (child = child->next(); child; child = child->next())\n";
761   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
762
763   return $setterContent;
764 }
765
766 sub generateFillLayerPropertyInheritValueSetter {
767   my $name = shift;
768   my $indent = shift;
769
770   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
771   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
772   my $clearFunction = getClearFunction($name);
773   my $testFunction = getTestFunction($name);
774
775   my $setterContent = "";
776   $setterContent .= $indent . "// Check for no-op before copying anything.\n";
777   $setterContent .= $indent . "if (styleResolver.parentStyle()->" . getLayersFunction($name) ."() == styleResolver.style()->" . getLayersFunction($name) . "())\n";
778   $setterContent .= $indent . "    return;\n";
779   $setterContent .= "\n";
780   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
781   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
782   $setterContent .= $indent . "for (auto* parent = &styleResolver.parentStyle()->" . getLayersFunction($name) . "(); parent && parent->" . $testFunction . "(); parent = parent->next()) {\n";
783   $setterContent .= $indent . "    if (!child) {\n";
784   $setterContent .= $indent . "        previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
785   $setterContent .= $indent . "        child = previousChild->next();\n";
786   $setterContent .= $indent . "    }\n";
787   $setterContent .= $indent . "    child->" . $setter . "(parent->" . $getter . "());\n";
788   $setterContent .= $indent . "    previousChild = child;\n";
789   $setterContent .= $indent . "    child = previousChild->next();\n";
790   $setterContent .= $indent . "}\n";
791   $setterContent .= $indent . "for (; child; child = child->next())\n";
792   $setterContent .= $indent . "    child->" . $clearFunction . "();\n";
793
794   return $setterContent;
795 }
796
797 sub generateFillLayerPropertyValueSetter {
798   my $name = shift;
799   my $indent = shift;
800
801   my $CSSPropertyId = "CSSProperty" . $nameToId{$name};
802
803   my $setterContent = "";
804   $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
805   $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
806   $setterContent .= $indent . "if (is<CSSValueList>(value) && !is<CSSImageSetValue>(value)) {\n";
807   $setterContent .= $indent . "    // Walk each value and put it into a layer, creating new layers as needed.\n";
808   $setterContent .= $indent . "    for (auto& item : downcast<CSSValueList>(value)) {\n";
809   $setterContent .= $indent . "        if (!child) {\n";
810   $setterContent .= $indent . "            previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
811   $setterContent .= $indent . "            child = previousChild->next();\n";
812   $setterContent .= $indent . "        }\n";
813   $setterContent .= $indent . "        styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, item);\n";
814   $setterContent .= $indent . "        previousChild = child;\n";
815   $setterContent .= $indent . "        child = child->next();\n";
816   $setterContent .= $indent . "    }\n";
817   $setterContent .= $indent . "} else {\n";
818   $setterContent .= $indent . "    styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, value);\n";
819   $setterContent .= $indent . "    child = child->next();\n";
820   $setterContent .= $indent . "}\n";
821   $setterContent .= $indent . "for (; child; child = child->next())\n";
822   $setterContent .= $indent . "    child->" . getClearFunction($name) . "();\n";
823
824   return $setterContent;
825 }
826
827 sub generateSetValueStatement
828 {
829   my $name = shift;
830   my $value = shift;
831
832   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
833   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
834   return "styleResolver.style()->" .  ($isSVG ? "accessSVGStyle()." : "") . $setter . "(" . $value . ")";
835 }
836
837 sub generateInitialValueSetter {
838   my $name = shift;
839   my $indent = shift;
840
841   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
842   my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
843   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
844   my $setterContent = "";
845   $setterContent .= $indent . "static void applyInitial" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
846   $setterContent .= $indent . "{\n";
847   my $style = "styleResolver.style()";
848   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
849     $setterContent .= $indent . "    " . getAutoSetter($name, $style) . ";\n";
850   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
851       my $initialColor = "RenderStyle::" . $initial . "()";
852       $setterContent .= generateColorValueSetter($name, $initialColor, $indent . "    ");
853   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
854     $setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . "    ");
855   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
856     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
857     $setterContent .= $indent . "    fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
858     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
859   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
860     $setterContent .= generateFillLayerPropertyInitialValueSetter($name, $indent . "    ");
861   } else {
862     my $initialValue = ($isSVG ? "SVGRenderStyle" : "RenderStyle") . "::" . $initial . "()";
863     $setterContent .= $indent . "    " . generateSetValueStatement($name, $initialValue) . ";\n";
864   }
865   $setterContent .= $indent . "}\n";
866
867   return $setterContent;
868 }
869
870 sub generateInheritValueSetter {
871   my $name = shift;
872   my $indent = shift;
873
874   my $setterContent = "";
875   $setterContent .= $indent . "static void applyInherit" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
876   $setterContent .= $indent . "{\n";
877   my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
878   my $parentStyle = "styleResolver.parentStyle()";
879   my $style = "styleResolver.style()";
880   my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
881   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
882   my $didCallSetValue = 0;
883   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
884     $setterContent .= $indent . "    if (" . getAutoGetter($name, $parentStyle) . ") {\n";
885     $setterContent .= $indent . "        " . getAutoSetter($name, $style) . ";\n";
886     $setterContent .= $indent . "        return;\n";
887     $setterContent .= $indent . "    }\n";
888   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
889     $setterContent .= $indent . "    Color color = " . $parentStyle . "->" . $getter . "();\n";
890     if (!exists($propertiesWithStyleBuilderOptions{$name}{"no-default-color"})) {
891       $setterContent .= $indent . "    if (!color.isValid())\n";
892       $setterContent .= $indent . "        color = " . $parentStyle . "->color();\n";
893     }
894     $setterContent .= generateColorValueSetter($name, "color", $indent . "    ");
895     $didCallSetValue = 1;
896   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
897     $setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . "    ");
898     $didCallSetValue = 1;
899   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
900     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
901     $setterContent .= $indent . "    fontDescription." . $setter . "(styleResolver.parentFontDescription()." . $getter . "());\n";
902     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
903     $didCallSetValue = 1;
904   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
905     $setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . "    ");
906     $didCallSetValue = 1;
907   }
908   if (!$didCallSetValue) {
909     my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") .  $getter . "()";
910     $setterContent .= $indent . "    " . generateSetValueStatement($name, "forwardInheritedValue(" . $inheritedValue . ")") . ";\n";
911   }
912   $setterContent .= $indent . "}\n";
913
914   return $setterContent;
915 }
916
917 sub generateValueSetter {
918   my $name = shift;
919   my $indent = shift;
920
921   my $setterContent = "";
922   $setterContent .= $indent . "static void applyValue" . $nameToId{$name} . "(StyleResolver& styleResolver, CSSValue& value)\n";
923   $setterContent .= $indent . "{\n";
924   my $convertedValue;
925   if (exists($propertiesWithStyleBuilderOptions{$name}{"converter"})) {
926     $convertedValue = "StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"converter"} . "(styleResolver, value)";
927   } elsif (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
928     $setterContent .= $indent . "    auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"conditional-converter"} . "(styleResolver, value);\n";
929     $convertedValue = "WTFMove(convertedValue.value())";
930   } else {
931     $convertedValue = "downcast<CSSPrimitiveValue>(value)";
932   }
933
934   my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
935   my $style = "styleResolver.style()";
936   my $didCallSetValue = 0;
937   if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
938     $setterContent .= $indent . "    if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto) {\n";
939     $setterContent .= $indent . "        ". getAutoSetter($name, $style) . ";\n";
940     $setterContent .= $indent . "        return;\n";
941     $setterContent .= $indent . "    }\n";
942   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
943     $setterContent .= $indent . "    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);\n";
944     if ($name eq "color") {
945       # The "color" property supports "currentColor" value. We should add a parameter.
946       $setterContent .= handleCurrentColorValue($name, "primitiveValue", $indent . "    ");
947     }
948     $setterContent .= generateColorValueSetter($name, "primitiveValue", $indent . "    ", VALUE_IS_PRIMITIVE);
949     $didCallSetValue = 1;
950   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
951     $setterContent .= generateAnimationPropertyValueSetter($name, $indent . "    ");
952     $didCallSetValue = 1;
953   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
954     $setterContent .= $indent . "    auto fontDescription = styleResolver.fontDescription();\n";
955     $setterContent .= $indent . "    fontDescription." . $setter . "(" . $convertedValue . ");\n";
956     $setterContent .= $indent . "    styleResolver.setFontDescription(fontDescription);\n";
957     $didCallSetValue = 1;
958   } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
959     $setterContent .= generateFillLayerPropertyValueSetter($name, $indent . "    ");
960     $didCallSetValue = 1;
961   }
962   if (!$didCallSetValue) {
963     if (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
964       $setterContent .= $indent . "    if (convertedValue)\n";
965       $setterContent .= "    ";
966     }
967     $setterContent .= $indent . "    " . generateSetValueStatement($name, $convertedValue) . ";\n";
968   }
969   $setterContent .= $indent . "}\n";
970
971   return $setterContent;
972 }
973
974 open STYLEBUILDER, ">StyleBuilder.cpp" || die "Could not open StyleBuilder.cpp for writing";
975 print STYLEBUILDER << "EOF";
976 /* This file is automatically generated from $inputFile by makeprop, do not edit */
977
978 #include "config.h"
979 #include "StyleBuilder.h"
980
981 #include "CSSPrimitiveValueMappings.h"
982 #include "CSSProperty.h"
983 #include "RenderStyle.h"
984 #include "StyleBuilderConverter.h"
985 #include "StyleBuilderCustom.h"
986 #include "StylePropertyShorthand.h"
987 #include "StyleResolver.h"
988
989 namespace WebCore {
990
991 class StyleBuilderFunctions {
992 public:
993 EOF
994
995 foreach my $name (@names) {
996   # Skip Shorthand properties and properties that do not use the StyleBuilder.
997   next if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
998   next if (exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"});
999
1000   my $indent = "    ";
1001   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Initial"}) {
1002     print STYLEBUILDER generateInitialValueSetter($name, $indent);
1003   }
1004   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Inherit"}) {
1005     print STYLEBUILDER generateInheritValueSetter($name, $indent);
1006   }
1007   if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Value"}) {
1008     print STYLEBUILDER generateValueSetter($name, $indent);
1009   }
1010 }
1011
1012 print STYLEBUILDER << "EOF";
1013 };
1014
1015 void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleResolver, CSSValue& value, bool isInitial, bool isInherit)
1016 {
1017     switch (property) {
1018     case CSSPropertyInvalid:
1019     case CSSPropertyCustom:
1020         break;
1021 EOF
1022
1023 foreach my $name (@names) {
1024   print STYLEBUILDER "    case CSSProperty" . $nameToId{$name} . ":\n";
1025   if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"}) {
1026     print STYLEBUILDER "        ASSERT(isShorthandCSSProperty(property));\n";
1027     print STYLEBUILDER "        ASSERT_NOT_REACHED();\n";
1028   } elsif (!exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"}) {
1029     print STYLEBUILDER "        if (isInitial)\n";
1030     print STYLEBUILDER "            " . getScopeForFunction($name, "Initial") . "::applyInitial" . $nameToId{$name} . "(styleResolver);\n";
1031     print STYLEBUILDER "        else if (isInherit)\n";
1032     print STYLEBUILDER "            " . getScopeForFunction($name, "Inherit") . "::applyInherit" . $nameToId{$name} . "(styleResolver);\n";
1033     print STYLEBUILDER "        else\n";
1034     print STYLEBUILDER "            " . getScopeForFunction($name, "Value") . "::applyValue" . $nameToId{$name} . "(styleResolver, value);\n";
1035   }
1036   print STYLEBUILDER "        break;\n";
1037 }
1038
1039 print STYLEBUILDER << "EOF";
1040     };
1041 }
1042
1043 } // namespace WebCore
1044 EOF
1045
1046 close STYLEBUILDER;
1047
1048 # Generate StylePropertyShorthandsFunctions.
1049 open SHORTHANDS_H, ">", "StylePropertyShorthandFunctions.h" or die "Could not open StylePropertyShorthandFunctions.h for writing\n";
1050 print SHORTHANDS_H << "EOF";
1051 // This file is automatically generated from $inputFile by the makeprop.pl script. Do not edit it.
1052
1053 #pragma once
1054
1055 namespace WebCore {
1056
1057 class StylePropertyShorthand;
1058
1059 EOF
1060
1061 foreach my $name (@names) {
1062   # Skip non-Shorthand properties.
1063   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1064
1065   print SHORTHANDS_H "StylePropertyShorthand " . lcfirst($nameToId{$name}) . "Shorthand();\n";
1066 }
1067
1068 print SHORTHANDS_H << "EOF";
1069
1070 } // namespace WebCore
1071 EOF
1072
1073 close SHORTHANDS_H;
1074
1075 open SHORTHANDS_CPP, ">", "StylePropertyShorthandFunctions.cpp" or die "Could not open StylePropertyShorthandFunctions.cpp for writing\n";
1076 print SHORTHANDS_CPP << "EOF";
1077 // This file is automatically generated from $inputFile by the makeprop.pl script. Do not edit it.
1078
1079 #include "config.h"
1080 #include "StylePropertyShorthandFunctions.h"
1081
1082 #include "StylePropertyShorthand.h"
1083
1084 namespace WebCore {
1085
1086 EOF
1087
1088 my %longhandToShorthands = ();
1089
1090 foreach my $name (@names) {
1091   # Skip non-Shorthand properties.
1092   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1093
1094   my $lowercaseId = lcfirst($nameToId{$name});
1095   my @longhands = @{$propertiesWithStyleBuilderOptions{$name}{"longhands"}};
1096
1097   print SHORTHANDS_CPP "StylePropertyShorthand " . $lowercaseId . "Shorthand()\n";
1098   print SHORTHANDS_CPP "{\n";
1099   print SHORTHANDS_CPP "    static const CSSPropertyID " . $lowercaseId . "Properties[] = {\n";
1100   foreach (@longhands) {
1101     if ($_ eq "all") {
1102         foreach my $propname (@names) {
1103             next if (exists $propertiesWithStyleBuilderOptions{$propname}{"longhands"});
1104             next if ($propname eq "direction" || $propname eq "unicode-bidi");
1105             die "Unknown CSS property used in all shorthand: $propname" if !exists($nameToId{$propname});
1106             push(@{$longhandToShorthands{$propname}}, $name);
1107             print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$propname} . ",\n";
1108         }
1109     } else {
1110         die "Unknown CSS property used in longhands: $_" if !exists($nameToId{$_});
1111         push(@{$longhandToShorthands{$_}}, $name);
1112         print SHORTHANDS_CPP "        CSSProperty" . $nameToId{$_} . ",\n";
1113     }
1114   }
1115   print SHORTHANDS_CPP "    };\n";
1116   print SHORTHANDS_CPP "    return StylePropertyShorthand(CSSProperty" . $nameToId{$name} . ", " . $lowercaseId . "Properties);\n";
1117   print SHORTHANDS_CPP "}\n\n";
1118 }
1119
1120 print SHORTHANDS_CPP << "EOF";
1121 StylePropertyShorthand shorthandForProperty(CSSPropertyID propertyID)
1122 {
1123     switch (propertyID) {
1124 EOF
1125
1126 foreach my $name (@names) {
1127   # Skip non-Shorthand properties.
1128   next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
1129
1130   print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$name} . ":\n";
1131   print SHORTHANDS_CPP "        return " . lcfirst($nameToId{$name}) . "Shorthand();\n";
1132 }
1133
1134 print SHORTHANDS_CPP << "EOF";
1135     default:
1136         return { };
1137     }
1138 }
1139 EOF
1140
1141 print SHORTHANDS_CPP << "EOF";
1142 StylePropertyShorthandVector matchingShorthandsForLonghand(CSSPropertyID propertyID)
1143 {
1144     switch (propertyID) {
1145 EOF
1146
1147 sub constructShorthandsVector {
1148   my $shorthands = shift;
1149
1150   my $vector = "StylePropertyShorthandVector{";
1151   foreach my $i (0 .. $#$shorthands) {
1152     $vector .= ", " unless $i == 0;
1153     $vector .= lcfirst($nameToId{$shorthands->[$i]}) . "Shorthand()";
1154   }
1155   $vector .= "}";
1156   return $vector;
1157 }
1158
1159 my %vectorToLonghands = ();
1160 for my $longhand (sort keys %longhandToShorthands) {
1161   my @shorthands = sort(@{$longhandToShorthands{$longhand}});
1162   push(@{$vectorToLonghands{constructShorthandsVector(\@shorthands)}}, $longhand);
1163 }
1164
1165 for my $vector (sort keys %vectorToLonghands) {
1166   foreach (@{$vectorToLonghands{$vector}}) {
1167     print SHORTHANDS_CPP "    case CSSProperty" . $nameToId{$_} . ":\n";
1168   }
1169   print SHORTHANDS_CPP "        return " . $vector . ";\n";
1170 }
1171
1172 print SHORTHANDS_CPP << "EOF";
1173     default:
1174         return { };
1175     }
1176 }
1177 EOF
1178
1179 print SHORTHANDS_CPP << "EOF";
1180 } // namespace WebCore
1181 EOF
1182
1183 close SHORTHANDS_CPP;
1184
1185 if (not $gperf) {
1186     $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
1187 }
1188 system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";