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