summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/makeprop.pl
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/css/makeprop.pl')
-rwxr-xr-xSource/WebCore/css/makeprop.pl958
1 files changed, 898 insertions, 60 deletions
diff --git a/Source/WebCore/css/makeprop.pl b/Source/WebCore/css/makeprop.pl
index 726a19487..236cb23c3 100755
--- a/Source/WebCore/css/makeprop.pl
+++ b/Source/WebCore/css/makeprop.pl
@@ -3,9 +3,10 @@
# This file is part of the WebKit project
#
# Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
-# Copyright (C) 2007, 2008, 2012 Apple Inc. All rights reserved.
+# Copyright (C) 2007-2016 Apple Inc. All rights reserved.
# Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
+# Copyright (C) 2013 Google Inc. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
@@ -21,73 +22,176 @@
# along with this library; see the file COPYING.LIB. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
-use Getopt::Long;
-use preprocessor;
+
use strict;
use warnings;
-my $defines;
-my $preprocessor;
+use English;
+use File::Spec;
+use Getopt::Long;
+use JSON::PP;
+
+sub addProperty($$);
+sub isPropertyEnabled($);
+
+my $inputFile = "CSSProperties.json";
+
+my $defines = "";
+my $gperf;
GetOptions('defines=s' => \$defines,
- 'preprocessor=s' => \$preprocessor);
+ 'gperf-executable=s' => \$gperf);
+
+my $input;
+{
+ local $INPUT_RECORD_SEPARATOR; # No separator; read through until end-of-file.
+ open(JSON, "<", $inputFile) or die "Cannot open $inputFile.\n";
+ $input = <JSON>;
+ close(JSON);
+}
-my @NAMES = applyPreprocessor("CSSPropertyNames.in", $defines, $preprocessor);
-die "We've reached more than 1024 CSS properties, please make sure to update CSSProperty/StylePropertyMetadata accordingly" if (scalar(@NAMES) > 1024);
+my $jsonDecoder = JSON::PP->new->utf8;
+my $jsonHashRef = $jsonDecoder->decode($input);
+my $propertiesHashRef = $jsonHashRef->{properties};
+my @allNames = keys(%$propertiesHashRef);
+die "We've reached more than 1024 CSS properties, please make sure to update CSSProperty/StylePropertyMetadata accordingly" if @allNames > 1024;
-my %namesHash;
-my @duplicates = ();
+my %defines = map { $_ => 1 } split(/ /, $defines);
-my $numPredefinedProperties = 1;
-my @names = ();
+my @names;
+my @internalProprerties;
+my $numPredefinedProperties = 2;
my %nameIsInherited;
+my %nameIsHighPriority;
+my %propertiesWithStyleBuilderOptions;
+my %styleBuilderOptions = (
+ "animatable" => 1, # Defined in Source/WebCore/css/StyleBuilderConverter.h
+ "auto-functions" => 1,
+ "conditional-converter" => 1,
+ "converter" => 1,
+ "custom" => 1,
+ "fill-layer-property" => 1,
+ "font-property" => 1,
+ "getter" => 1,
+ "initial" => 1,
+ "longhands" => 1,
+ "name-for-methods" => 1,
+ "no-default-color" => 1,
+ "svg" => 1,
+ "skip-builder" => 1,
+ "setter" => 1,
+ "visited-link-color-support" => 1,
+);
my %nameToId;
-my @aliases = ();
-foreach (@NAMES) {
- next if (m/(^\s*$)/);
- next if (/^#/);
-
- # Input may use a different EOL sequence than $/, so avoid chomp.
- $_ =~ s/\s*\[(.+?)\]\r?$//;
- my @options = ();
- if ($1) {
- @options = split(/\s*,\s*/, $1);
- }
+my %nameToAliases;
- $_ =~ s/[\r\n]+$//g;
- if (exists $namesHash{$_}) {
- push @duplicates, $_;
- } else {
- $namesHash{$_} = 1;
- }
- if ($_ =~ /=/) {
- if (@options) {
- die "Options are specified on an alias $_: ", join(", ", @options) . "\n";
+for my $name (@allNames) {
+ my $value = $propertiesHashRef->{$name};
+ my $valueType = ref($value);
+ if ($valueType eq "HASH") {
+ if (isPropertyEnabled($value)) {
+ addProperty($name, $value);
+ }
+ } elsif ($valueType eq "ARRAY") {
+ for my $v (@$value) {
+ if (isPropertyEnabled($v)) {
+ addProperty($name, $v);
+ last;
+ }
+ }
+ } else {
+ die "$name does not have a supported value type. Only dictionary and array types are supported.";
}
- push @aliases, $_;
- } else {
- $nameIsInherited{$_} = 0;
- foreach my $option (@options) {
- if ($option eq "Inherited") {
- $nameIsInherited{$_} = 1;
- }
+}
+
+sub isPropertyEnabled($)
+{
+ my ($optionsHashRef) = @_;
+
+ if (!exists($optionsHashRef->{"codegen-properties"})) {
+ return 1;
+ }
+ if ($optionsHashRef->{"codegen-properties"}{"skip-codegen"}) {
+ return 0;
+ }
+ if (!exists($optionsHashRef->{"codegen-properties"}{"enable-if"})) {
+ return 1;
+ }
+ if (exists($defines{$optionsHashRef->{"codegen-properties"}{"enable-if"}})) {
+ return 1;
}
+ if (substr($optionsHashRef->{"codegen-properties"}{"enable-if"}, 0, 1) eq "!" && !exists($defines{substr($optionsHashRef->{"codegen-properties"}{"enable-if"}, 1)})) {
+ return 1;
+ }
+ return 0;
+}
+
+sub addProperty($$)
+{
+ my ($name, $optionsHashRef) = @_;
- my $id = $_;
+ push @names, $name;
+
+ my $id = $name;
$id =~ s/(^[^-])|-(.)/uc($1||$2)/ge;
- $nameToId{$_} = $id;
+ $nameToId{$name} = $id;
- push @names, $_;
- }
+ for my $optionName (keys %{$optionsHashRef}) {
+ if ($optionName eq "codegen-properties") {
+ my $codegenProperties = $optionsHashRef->{"codegen-properties"};
+ for my $codegenOptionName (keys %$codegenProperties) {
+ if ($codegenOptionName eq "enable-if") {
+ next;
+ } elsif ($codegenOptionName eq "skip-codegen") {
+ next;
+ } elsif ($codegenOptionName eq "high-priority") {
+ $nameIsHighPriority{$name} = 1;
+ } elsif ($codegenOptionName eq "aliases") {
+ $nameToAliases{$name} = $codegenProperties->{"aliases"};
+ } elsif ($styleBuilderOptions{$codegenOptionName}) {
+ $propertiesWithStyleBuilderOptions{$name}{$codegenOptionName} = $codegenProperties->{$codegenOptionName};
+ } elsif ($codegenOptionName eq "internal-only") {
+ # internal-only properties exist to make it easier to parse compound properties (e.g. background-repeat) as if they were shorthands.
+ push @internalProprerties, $name
+ } else {
+ die "Unrecognized codegen property \"$codegenOptionName\" for $name property.";
+ }
+ }
+ } elsif ($optionName eq "animatable") {
+ $propertiesWithStyleBuilderOptions{$name}{"animatable"} = $optionsHashRef->{"animatable"};
+ } elsif ($optionName eq "inherited") {
+ $nameIsInherited{$name} = 1;
+ } elsif ($optionName eq "values") {
+ # FIXME: Implement.
+ }
+ # We allow unrecognized options to pass through without error to support annotation.
+ }
}
-if (@duplicates > 0) {
- die 'Duplicate CSS property names: ', join(', ', @duplicates) . "\n";
+sub sortByDescendingPriorityAndName
+{
+ # Sort names with high priority to the front
+ if (!!$nameIsHighPriority{$a} < !!$nameIsHighPriority{$b}) {
+ return 1;
+ }
+ if (!!$nameIsHighPriority{$a} > !!$nameIsHighPriority{$b}) {
+ return -1;
+ }
+ # Sort names without leading '-' to the front
+ if (substr($a, 0, 1) eq "-" && substr($b, 0, 1) ne "-") {
+ return 1;
+ }
+ if (substr($a, 0, 1) ne "-" && substr($b, 0, 1) eq "-") {
+ return -1;
+ }
+ return $a cmp $b;
}
+@names = sort sortByDescendingPriorityAndName @names;
+
open GPERF, ">CSSPropertyNames.gperf" || die "Could not open CSSPropertyNames.gperf for writing";
print GPERF << "EOF";
%{
-/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
+/* This file is automatically generated from $inputFile by makeprop, do not edit */
#include "config.h"
#include \"CSSProperty.h\"
#include \"CSSPropertyNames.h\"
@@ -106,6 +210,11 @@ print GPERF << "EOF";
#endif
namespace WebCore {
+
+// Using std::numeric_limits<uint16_t>::max() here would be cleaner,
+// but is not possible due to missing constexpr support in MSVC 2013.
+static_assert(numCSSProperties + 1 <= 65535, "CSSPropertyID should fit into uint16_t.");
+
EOF
print GPERF "const char* const propertyNameStrings[numCSSProperties] = {\n";
@@ -135,19 +244,38 @@ foreach my $name (@names) {
print GPERF $name . ", CSSProperty" . $nameToId{$name} . "\n";
}
-foreach my $alias (@aliases) {
- $alias =~ /^([^\s]*)[\s]*=[\s]*([^\s]*)/;
- my $name = $1;
- print GPERF $name . ", CSSProperty" . $nameToId{$2} . "\n";
+for my $name (@names) {
+ if (!$nameToAliases{$name}) {
+ next;
+ }
+ for my $alias (@{$nameToAliases{$name}}) {
+ print GPERF $alias . ", CSSProperty" . $nameToId{$name} . "\n";
+ }
}
-print GPERF<< "EOF";
+print GPERF << "EOF";
%%
const Property* findProperty(const char* str, unsigned int len)
{
return CSSPropertyNamesHash::findPropertyImpl(str, len);
}
+bool isInternalCSSProperty(const CSSPropertyID id)
+{
+ switch (id) {
+EOF
+
+foreach my $name (@internalProprerties) {
+ print GPERF " case CSSPropertyID::CSSProperty" . $nameToId{$name} . ":\n";
+}
+
+print GPERF << "EOF";
+ return true;
+ default:
+ return false;
+ }
+}
+
const char* getPropertyName(CSSPropertyID id)
{
if (id < firstCSSProperty)
@@ -205,6 +333,7 @@ String getJSPropertyName(CSSPropertyID id)
static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
false, // CSSPropertyInvalid
+ true, // CSSPropertyCustom
EOF
foreach my $name (@names) {
@@ -218,7 +347,7 @@ print GPERF<< "EOF";
bool CSSProperty::isInheritedProperty(CSSPropertyID id)
{
- ASSERT(id >= 0 && id <= lastCSSProperty);
+ ASSERT(id <= lastCSSProperty);
ASSERT(id != CSSPropertyInvalid);
return isInheritedPropertyTable[id];
}
@@ -230,12 +359,13 @@ bool CSSProperty::isInheritedProperty(CSSPropertyID id)
#endif
EOF
+close GPERF;
+
open HEADER, ">CSSPropertyNames.h" || die "Could not open CSSPropertyNames.h for writing";
print HEADER << "EOF";
-/* This file is automatically generated from CSSPropertyNames.in by makeprop, do not edit */
+/* This file is automatically generated from $inputFile by makeprop, do not edit */
-#ifndef CSSPropertyNames_h
-#define CSSPropertyNames_h
+#pragma once
#include <string.h>
#include <wtf/HashFunctions.h>
@@ -248,14 +378,17 @@ class String;
namespace WebCore {
-enum CSSPropertyID {
+enum CSSPropertyID : uint16_t {
CSSPropertyInvalid = 0,
+ CSSPropertyCustom = 1,
EOF
my $first = $numPredefinedProperties;
my $i = $numPredefinedProperties;
my $maxLen = 0;
+my $lastHighPriorityPropertyName;
foreach my $name (@names) {
+ $lastHighPriorityPropertyName = $name if $nameIsHighPriority{$name}; # Assumes that @names is sorted by descending priorities.
print HEADER " CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
$i = $i + 1;
if (length($name) > $maxLen) {
@@ -270,9 +403,11 @@ print HEADER "const int firstCSSProperty = $first;\n";
print HEADER "const int numCSSProperties = $num;\n";
print HEADER "const int lastCSSProperty = $last;\n";
print HEADER "const size_t maxCSSPropertyNameLength = $maxLen;\n";
+print HEADER "const CSSPropertyID lastHighPriorityProperty = CSSProperty" . $nameToId{$lastHighPriorityPropertyName} . ";\n";
print HEADER << "EOF";
+bool isInternalCSSProperty(const CSSPropertyID);
const char* getPropertyName(CSSPropertyID);
const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
WTF::String getPropertyNameString(CSSPropertyID id);
@@ -280,7 +415,7 @@ WTF::String getJSPropertyName(CSSPropertyID);
inline CSSPropertyID convertToCSSPropertyID(int value)
{
- ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid);
+ ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
return static_cast<CSSPropertyID>(value);
}
@@ -294,13 +429,716 @@ template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore
static void constructDeletedValue(WebCore::CSSPropertyID& slot) { slot = static_cast<WebCore::CSSPropertyID>(WebCore::lastCSSProperty + 1); }
static bool isDeletedValue(WebCore::CSSPropertyID value) { return value == (WebCore::lastCSSProperty + 1); }
};
+} // namespace WTF
+
+EOF
+
+close HEADER;
+
+#
+# StyleBuilder.cpp generator.
+#
+
+sub getScopeForFunction {
+ my $name = shift;
+ my $builderFunction = shift;
+
+ return $propertiesWithStyleBuilderOptions{$name}{"custom"}{$builderFunction} ? "StyleBuilderCustom" : "StyleBuilderFunctions";
+}
+
+sub getNameForMethods {
+ my $name = shift;
+
+ my $nameForMethods = $nameToId{$name};
+ $nameForMethods =~ s/Webkit//g;
+ if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
+ $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
+ }
+ return $nameForMethods;
+}
+
+sub getAutoGetter {
+ my $name = shift;
+ my $renderStyle = shift;
+
+ return $renderStyle . "->hasAuto" . getNameForMethods($name) . "()";
+}
+
+sub getAutoSetter {
+ my $name = shift;
+ my $renderStyle = shift;
+
+ return $renderStyle . "->setHasAuto" . getNameForMethods($name) . "()";
+}
+
+sub getVisitedLinkSetter {
+ my $name = shift;
+ my $renderStyle = shift;
+
+ return $renderStyle . "->setVisitedLink" . getNameForMethods($name);
+}
+
+sub getClearFunction {
+ my $name = shift;
+
+ return "clear" . getNameForMethods($name);
+}
+
+sub getEnsureAnimationsOrTransitionsMethod {
+ my $name = shift;
+
+ return "ensureAnimations" if $name =~ /animation-/;
+ return "ensureTransitions" if $name =~ /transition-/;
+ die "Unrecognized animation property name.";
+}
+
+sub getAnimationsOrTransitionsMethod {
+ my $name = shift;
+
+ return "animations" if $name =~ /animation-/;
+ return "transitions" if $name =~ /transition-/;
+ die "Unrecognized animation property name.";
+}
+
+sub getTestFunction {
+ my $name = shift;
+
+ return "is" . getNameForMethods($name) . "Set";
+}
+
+sub getAnimationMapfunction {
+ my $name = shift;
+
+ return "mapAnimation" . getNameForMethods($name);
+}
+
+sub getLayersFunction {
+ my $name = shift;
+
+ return "backgroundLayers" if $name =~ /background-/;
+ return "maskLayers" if $name =~ /mask-/;
+ die "Unrecognized FillLayer property name.";
+}
+
+sub getLayersAccessorFunction {
+ my $name = shift;
+
+ return "ensureBackgroundLayers" if $name =~ /background-/;
+ return "ensureMaskLayers" if $name =~ /mask-/;
+ die "Unrecognized FillLayer property name.";
+}
+
+sub getFillLayerType {
+my $name = shift;
+
+ return "BackgroundFillLayer" if $name =~ /background-/;
+ return "MaskFillLayer" if $name =~ /mask-/;
+}
+
+sub getFillLayerMapfunction {
+ my $name = shift;
+
+ return "mapFill" . getNameForMethods($name);
+}
+
+
+foreach my $name (@names) {
+ my $nameForMethods = getNameForMethods($name);
+ $nameForMethods =~ s/Webkit//g;
+ if (exists($propertiesWithStyleBuilderOptions{$name}{"name-for-methods"})) {
+ $nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"name-for-methods"};
+ }
+
+ if (!exists($propertiesWithStyleBuilderOptions{$name}{"getter"})) {
+ $propertiesWithStyleBuilderOptions{$name}{"getter"} = lcfirst($nameForMethods);
+ }
+ if (!exists($propertiesWithStyleBuilderOptions{$name}{"setter"})) {
+ $propertiesWithStyleBuilderOptions{$name}{"setter"} = "set" . $nameForMethods;
+ }
+ if (!exists($propertiesWithStyleBuilderOptions{$name}{"initial"})) {
+ if (exists($propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"})) {
+ $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initialFill" . $nameForMethods;
+ } else {
+ $propertiesWithStyleBuilderOptions{$name}{"initial"} = "initial" . $nameForMethods;
+ }
+ }
+ # FIXME: Convert option custom from a string to an array.
+ if (!exists($propertiesWithStyleBuilderOptions{$name}{"custom"})) {
+ $propertiesWithStyleBuilderOptions{$name}{"custom"} = "";
+ } elsif ($propertiesWithStyleBuilderOptions{$name}{"custom"} eq "All") {
+ $propertiesWithStyleBuilderOptions{$name}{"custom"} = "Initial|Inherit|Value";
+ }
+ my %customValues = map { $_ => 1 } split(/\|/, $propertiesWithStyleBuilderOptions{$name}{"custom"});
+ $propertiesWithStyleBuilderOptions{$name}{"custom"} = \%customValues;
+}
+
+use constant {
+ NOT_FOR_VISITED_LINK => 0,
+ FOR_VISITED_LINK => 1,
+};
+
+sub colorFromPrimitiveValue {
+ my $primitiveValue = shift;
+ my $forVisitedLink = @_ ? shift : NOT_FOR_VISITED_LINK;
+
+ return "styleResolver.colorFromPrimitiveValue(" . $primitiveValue . ", /* forVisitedLink */ " . ($forVisitedLink ? "true" : "false") . ")";
+}
+
+use constant {
+ VALUE_IS_COLOR => 0,
+ VALUE_IS_PRIMITIVE => 1,
+};
+
+sub generateColorValueSetter {
+ my $name = shift;
+ my $value = shift;
+ my $indent = shift;
+ my $valueIsPrimitive = @_ ? shift : VALUE_IS_COLOR;
+
+ my $style = "styleResolver.style()";
+ my $setterContent .= $indent . "if (styleResolver.applyPropertyToRegularStyle())\n";
+ my $setValue = $style . "->" . $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $color = $valueIsPrimitive ? colorFromPrimitiveValue($value) : $value;
+ $setterContent .= $indent . " " . $setValue . "(" . $color . ");\n";
+ $setterContent .= $indent . "if (styleResolver.applyPropertyToVisitedLinkStyle())\n";
+ $color = $valueIsPrimitive ? colorFromPrimitiveValue($value, FOR_VISITED_LINK) : $value;
+ $setterContent .= $indent . " " . getVisitedLinkSetter($name, $style) . "(" . $color . ");\n";
+
+ return $setterContent;
+}
+
+sub handleCurrentColorValue {
+ my $name = shift;
+ my $primitiveValue = shift;
+ my $indent = shift;
+
+ my $code = $indent . "if (" . $primitiveValue . ".valueID() == CSSValueCurrentcolor) {\n";
+ $code .= $indent . " applyInherit" . $nameToId{$name} . "(styleResolver);\n";
+ $code .= $indent . " return;\n";
+ $code .= $indent . "}\n";
+ return $code;
+}
+
+sub generateAnimationPropertyInitialValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setterContent = "";
+ $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
+ $setterContent .= $indent . "if (list.isEmpty())\n";
+ $setterContent .= $indent . " list.append(Animation::create());\n";
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
+ $setterContent .= $indent . "list.animation(0)." . $setter . "(Animation::" . $initial . "());\n";
+ if ($name eq "-webkit-transition-property") {
+ $setterContent .= $indent . "list.animation(0).setAnimationMode(Animation::AnimateAll);\n";
+ }
+ $setterContent .= $indent . "for (size_t i = 1; i < list.size(); ++i)\n";
+ $setterContent .= $indent . " list.animation(i)." . getClearFunction($name) . "();\n";
+
+ return $setterContent;
+}
+
+sub generateAnimationPropertyInheritValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setterContent = "";
+ $setterContent .= $indent . "auto& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
+ $setterContent .= $indent . "auto* parentList = styleResolver.parentStyle()->" . getAnimationsOrTransitionsMethod($name) . "();\n";
+ $setterContent .= $indent . "size_t i = 0, parentSize = parentList ? parentList->size() : 0;\n";
+ $setterContent .= $indent . "for ( ; i < parentSize && parentList->animation(i)." . getTestFunction($name) . "(); ++i) {\n";
+ $setterContent .= $indent . " if (list.size() <= i)\n";
+ $setterContent .= $indent . " list.append(Animation::create());\n";
+ my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ $setterContent .= $indent . " list.animation(i)." . $setter . "(parentList->animation(i)." . $getter . "());\n";
+ $setterContent .= $indent . " list.animation(i).setAnimationMode(parentList->animation(i).animationMode());\n";
+ $setterContent .= $indent . "}\n";
+ $setterContent .= "\n";
+ $setterContent .= $indent . "// Reset any remaining animations to not have the property set.\n";
+ $setterContent .= $indent . "for ( ; i < list.size(); ++i)\n";
+ $setterContent .= $indent . " list.animation(i)." . getClearFunction($name) . "();\n";
+
+ return $setterContent;
+}
+
+sub generateAnimationPropertyValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setterContent = "";
+ $setterContent .= $indent . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
+ $setterContent .= $indent . "size_t childIndex = 0;\n";
+ $setterContent .= $indent . "if (is<CSSValueList>(value)) {\n";
+ $setterContent .= $indent . " /* Walk each value and put it into an animation, creating new animations as needed. */\n";
+ $setterContent .= $indent . " for (auto& currentValue : downcast<CSSValueList>(value)) {\n";
+ $setterContent .= $indent . " if (childIndex <= list.size())\n";
+ $setterContent .= $indent . " list.append(Animation::create());\n";
+ $setterContent .= $indent . " styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), currentValue);\n";
+ $setterContent .= $indent . " ++childIndex;\n";
+ $setterContent .= $indent . " }\n";
+ $setterContent .= $indent . "} else {\n";
+ $setterContent .= $indent . " if (list.isEmpty())\n";
+ $setterContent .= $indent . " list.append(Animation::create());\n";
+ $setterContent .= $indent . " styleResolver.styleMap()->" . getAnimationMapfunction($name) . "(list.animation(childIndex), value);\n";
+ $setterContent .= $indent . " childIndex = 1;\n";
+ $setterContent .= $indent . "}\n";
+ $setterContent .= $indent . "for ( ; childIndex < list.size(); ++childIndex) {\n";
+ $setterContent .= $indent . " /* Reset all remaining animations to not have the property set. */\n";
+ $setterContent .= $indent . " list.animation(childIndex)." . getClearFunction($name) . "();\n";
+ $setterContent .= $indent . "}\n";
+
+ return $setterContent;
+}
+
+sub generateFillLayerPropertyInitialValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $clearFunction = getClearFunction($name);
+ my $testFunction = getTestFunction($name);
+ my $initial = "FillLayer::" . $propertiesWithStyleBuilderOptions{$name}{"initial"} . "(" . getFillLayerType($name) . ")";
+
+ my $setterContent = "";
+ $setterContent .= $indent . "// Check for (single-layer) no-op before clearing anything.\n";
+ $setterContent .= $indent . "auto& layers = styleResolver.style()->" . getLayersFunction($name) . "();\n";
+ $setterContent .= $indent . "if (!layers.next() && (!layers." . $testFunction . "() || layers." . $getter . "() == $initial))\n";
+ $setterContent .= $indent . " return;\n";
+ $setterContent .= "\n";
+ $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
+ $setterContent .= $indent . "child->" . $setter . "(" . $initial . ");\n";
+ $setterContent .= $indent . "for (child = child->next(); child; child = child->next())\n";
+ $setterContent .= $indent . " child->" . $clearFunction . "();\n";
+
+ return $setterContent;
+}
+
+sub generateFillLayerPropertyInheritValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $clearFunction = getClearFunction($name);
+ my $testFunction = getTestFunction($name);
+
+ my $setterContent = "";
+ $setterContent .= $indent . "// Check for no-op before copying anything.\n";
+ $setterContent .= $indent . "if (styleResolver.parentStyle()->" . getLayersFunction($name) ."() == styleResolver.style()->" . getLayersFunction($name) . "())\n";
+ $setterContent .= $indent . " return;\n";
+ $setterContent .= "\n";
+ $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
+ $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
+ $setterContent .= $indent . "for (auto* parent = &styleResolver.parentStyle()->" . getLayersFunction($name) . "(); parent && parent->" . $testFunction . "(); parent = parent->next()) {\n";
+ $setterContent .= $indent . " if (!child) {\n";
+ $setterContent .= $indent . " previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
+ $setterContent .= $indent . " child = previousChild->next();\n";
+ $setterContent .= $indent . " }\n";
+ $setterContent .= $indent . " child->" . $setter . "(parent->" . $getter . "());\n";
+ $setterContent .= $indent . " previousChild = child;\n";
+ $setterContent .= $indent . " child = previousChild->next();\n";
+ $setterContent .= $indent . "}\n";
+ $setterContent .= $indent . "for (; child; child = child->next())\n";
+ $setterContent .= $indent . " child->" . $clearFunction . "();\n";
+
+ return $setterContent;
+}
+
+sub generateFillLayerPropertyValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $CSSPropertyId = "CSSProperty" . $nameToId{$name};
+
+ my $setterContent = "";
+ $setterContent .= $indent . "auto* child = &styleResolver.style()->" . getLayersAccessorFunction($name) . "();\n";
+ $setterContent .= $indent . "FillLayer* previousChild = nullptr;\n";
+ $setterContent .= $indent . "if (is<CSSValueList>(value) && !is<CSSImageSetValue>(value)) {\n";
+ $setterContent .= $indent . " // Walk each value and put it into a layer, creating new layers as needed.\n";
+ $setterContent .= $indent . " for (auto& item : downcast<CSSValueList>(value)) {\n";
+ $setterContent .= $indent . " if (!child) {\n";
+ $setterContent .= $indent . " previousChild->setNext(std::make_unique<FillLayer>(" . getFillLayerType($name) . "));\n";
+ $setterContent .= $indent . " child = previousChild->next();\n";
+ $setterContent .= $indent . " }\n";
+ $setterContent .= $indent . " styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, item);\n";
+ $setterContent .= $indent . " previousChild = child;\n";
+ $setterContent .= $indent . " child = child->next();\n";
+ $setterContent .= $indent . " }\n";
+ $setterContent .= $indent . "} else {\n";
+ $setterContent .= $indent . " styleResolver.styleMap()->" . getFillLayerMapfunction($name) . "(" . $CSSPropertyId . ", *child, value);\n";
+ $setterContent .= $indent . " child = child->next();\n";
+ $setterContent .= $indent . "}\n";
+ $setterContent .= $indent . "for (; child; child = child->next())\n";
+ $setterContent .= $indent . " child->" . getClearFunction($name) . "();\n";
+
+ return $setterContent;
+}
+
+sub generateSetValueStatement
+{
+ my $name = shift;
+ my $value = shift;
+
+ my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ return "styleResolver.style()->" . ($isSVG ? "accessSVGStyle()." : "") . $setter . "(" . $value . ")";
+}
+
+sub generateInitialValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $initial = $propertiesWithStyleBuilderOptions{$name}{"initial"};
+ my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
+ my $setterContent = "";
+ $setterContent .= $indent . "static void applyInitial" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
+ $setterContent .= $indent . "{\n";
+ my $style = "styleResolver.style()";
+ if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
+ $setterContent .= $indent . " " . getAutoSetter($name, $style) . ";\n";
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
+ my $initialColor = "RenderStyle::" . $initial . "()";
+ $setterContent .= generateColorValueSetter($name, $initialColor, $indent . " ");
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
+ $setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . " ");
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
+ $setterContent .= $indent . " auto fontDescription = styleResolver.fontDescription();\n";
+ $setterContent .= $indent . " fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
+ $setterContent .= $indent . " styleResolver.setFontDescription(fontDescription);\n";
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
+ $setterContent .= generateFillLayerPropertyInitialValueSetter($name, $indent . " ");
+ } else {
+ my $initialValue = ($isSVG ? "SVGRenderStyle" : "RenderStyle") . "::" . $initial . "()";
+ $setterContent .= $indent . " " . generateSetValueStatement($name, $initialValue) . ";\n";
+ }
+ $setterContent .= $indent . "}\n";
+
+ return $setterContent;
+}
+
+sub generateInheritValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setterContent = "";
+ $setterContent .= $indent . "static void applyInherit" . $nameToId{$name} . "(StyleResolver& styleResolver)\n";
+ $setterContent .= $indent . "{\n";
+ my $isSVG = exists $propertiesWithStyleBuilderOptions{$name}{"svg"};
+ my $parentStyle = "styleResolver.parentStyle()";
+ my $style = "styleResolver.style()";
+ my $getter = $propertiesWithStyleBuilderOptions{$name}{"getter"};
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $didCallSetValue = 0;
+ if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
+ $setterContent .= $indent . " if (" . getAutoGetter($name, $parentStyle) . ") {\n";
+ $setterContent .= $indent . " " . getAutoSetter($name, $style) . ";\n";
+ $setterContent .= $indent . " return;\n";
+ $setterContent .= $indent . " }\n";
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
+ $setterContent .= $indent . " Color color = " . $parentStyle . "->" . $getter . "();\n";
+ if (!exists($propertiesWithStyleBuilderOptions{$name}{"no-default-color"})) {
+ $setterContent .= $indent . " if (!color.isValid())\n";
+ $setterContent .= $indent . " color = " . $parentStyle . "->color();\n";
+ }
+ $setterContent .= generateColorValueSetter($name, "color", $indent . " ");
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
+ $setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . " ");
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
+ $setterContent .= $indent . " auto fontDescription = styleResolver.fontDescription();\n";
+ $setterContent .= $indent . " fontDescription." . $setter . "(styleResolver.parentFontDescription()." . $getter . "());\n";
+ $setterContent .= $indent . " styleResolver.setFontDescription(fontDescription);\n";
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
+ $setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . " ");
+ $didCallSetValue = 1;
+ }
+ if (!$didCallSetValue) {
+ my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") . $getter . "()";
+ $setterContent .= $indent . " " . generateSetValueStatement($name, "forwardInheritedValue(" . $inheritedValue . ")") . ";\n";
+ }
+ $setterContent .= $indent . "}\n";
+
+ return $setterContent;
+}
+
+sub generateValueSetter {
+ my $name = shift;
+ my $indent = shift;
+
+ my $setterContent = "";
+ $setterContent .= $indent . "static void applyValue" . $nameToId{$name} . "(StyleResolver& styleResolver, CSSValue& value)\n";
+ $setterContent .= $indent . "{\n";
+ my $convertedValue;
+ if (exists($propertiesWithStyleBuilderOptions{$name}{"converter"})) {
+ $convertedValue = "StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"converter"} . "(styleResolver, value)";
+ } elsif (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
+ $setterContent .= $indent . " auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"conditional-converter"} . "(styleResolver, value);\n";
+ $convertedValue = "WTFMove(convertedValue.value())";
+ } else {
+ $convertedValue = "downcast<CSSPrimitiveValue>(value)";
+ }
+
+ my $setter = $propertiesWithStyleBuilderOptions{$name}{"setter"};
+ my $style = "styleResolver.style()";
+ my $didCallSetValue = 0;
+ if (exists $propertiesWithStyleBuilderOptions{$name}{"auto-functions"}) {
+ $setterContent .= $indent . " if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto) {\n";
+ $setterContent .= $indent . " ". getAutoSetter($name, $style) . ";\n";
+ $setterContent .= $indent . " return;\n";
+ $setterContent .= $indent . " }\n";
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"visited-link-color-support"}) {
+ $setterContent .= $indent . " auto& primitiveValue = downcast<CSSPrimitiveValue>(value);\n";
+ if ($name eq "color") {
+ # The "color" property supports "currentColor" value. We should add a parameter.
+ $setterContent .= handleCurrentColorValue($name, "primitiveValue", $indent . " ");
+ }
+ $setterContent .= generateColorValueSetter($name, "primitiveValue", $indent . " ", VALUE_IS_PRIMITIVE);
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"animatable"}) {
+ $setterContent .= generateAnimationPropertyValueSetter($name, $indent . " ");
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"font-property"}) {
+ $setterContent .= $indent . " auto fontDescription = styleResolver.fontDescription();\n";
+ $setterContent .= $indent . " fontDescription." . $setter . "(" . $convertedValue . ");\n";
+ $setterContent .= $indent . " styleResolver.setFontDescription(fontDescription);\n";
+ $didCallSetValue = 1;
+ } elsif (exists $propertiesWithStyleBuilderOptions{$name}{"fill-layer-property"}) {
+ $setterContent .= generateFillLayerPropertyValueSetter($name, $indent . " ");
+ $didCallSetValue = 1;
+ }
+ if (!$didCallSetValue) {
+ if (exists($propertiesWithStyleBuilderOptions{$name}{"conditional-converter"})) {
+ $setterContent .= $indent . " if (convertedValue)\n";
+ $setterContent .= " ";
+ }
+ $setterContent .= $indent . " " . generateSetValueStatement($name, $convertedValue) . ";\n";
+ }
+ $setterContent .= $indent . "}\n";
+
+ return $setterContent;
+}
+
+open STYLEBUILDER, ">StyleBuilder.cpp" || die "Could not open StyleBuilder.cpp for writing";
+print STYLEBUILDER << "EOF";
+/* This file is automatically generated from $inputFile by makeprop, do not edit */
+
+#include "config.h"
+#include "StyleBuilder.h"
+
+#include "CSSPrimitiveValueMappings.h"
+#include "CSSProperty.h"
+#include "RenderStyle.h"
+#include "StyleBuilderConverter.h"
+#include "StyleBuilderCustom.h"
+#include "StylePropertyShorthand.h"
+#include "StyleResolver.h"
+
+namespace WebCore {
+
+class StyleBuilderFunctions {
+public:
+EOF
+
+foreach my $name (@names) {
+ # Skip Shorthand properties and properties that do not use the StyleBuilder.
+ next if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
+ next if (exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"});
+
+ my $indent = " ";
+ if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Initial"}) {
+ print STYLEBUILDER generateInitialValueSetter($name, $indent);
+ }
+ if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Inherit"}) {
+ print STYLEBUILDER generateInheritValueSetter($name, $indent);
+ }
+ if (!$propertiesWithStyleBuilderOptions{$name}{"custom"}{"Value"}) {
+ print STYLEBUILDER generateValueSetter($name, $indent);
+ }
+}
+
+print STYLEBUILDER << "EOF";
+};
+
+void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleResolver, CSSValue& value, bool isInitial, bool isInherit)
+{
+ switch (property) {
+ case CSSPropertyInvalid:
+ case CSSPropertyCustom:
+ break;
+EOF
+
+foreach my $name (@names) {
+ print STYLEBUILDER " case CSSProperty" . $nameToId{$name} . ":\n";
+ if (exists $propertiesWithStyleBuilderOptions{$name}{"longhands"}) {
+ print STYLEBUILDER " ASSERT(isShorthandCSSProperty(property));\n";
+ print STYLEBUILDER " ASSERT_NOT_REACHED();\n";
+ } elsif (!exists $propertiesWithStyleBuilderOptions{$name}{"skip-builder"}) {
+ print STYLEBUILDER " if (isInitial)\n";
+ print STYLEBUILDER " " . getScopeForFunction($name, "Initial") . "::applyInitial" . $nameToId{$name} . "(styleResolver);\n";
+ print STYLEBUILDER " else if (isInherit)\n";
+ print STYLEBUILDER " " . getScopeForFunction($name, "Inherit") . "::applyInherit" . $nameToId{$name} . "(styleResolver);\n";
+ print STYLEBUILDER " else\n";
+ print STYLEBUILDER " " . getScopeForFunction($name, "Value") . "::applyValue" . $nameToId{$name} . "(styleResolver, value);\n";
+ }
+ print STYLEBUILDER " break;\n";
}
-#endif // CSSPropertyNames_h
+print STYLEBUILDER << "EOF";
+ };
+}
+} // namespace WebCore
EOF
-close HEADER;
+close STYLEBUILDER;
+
+# Generate StylePropertyShorthandsFunctions.
+open SHORTHANDS_H, ">StylePropertyShorthandFunctions.h" || die "Could not open StylePropertyShorthandFunctions.h for writing";
+print SHORTHANDS_H << "EOF";
+/* This file is automatically generated from $inputFile by makeprop, do not edit */
+
+#pragma once
+
+namespace WebCore {
+
+class StylePropertyShorthand;
+
+EOF
+
+foreach my $name (@names) {
+ # Skip non-Shorthand properties.
+ next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
+
+ print SHORTHANDS_H "StylePropertyShorthand " . lcfirst($nameToId{$name}) . "Shorthand();\n";
+}
+
+print SHORTHANDS_H << "EOF";
+
+} // namespace WebCore
+EOF
-my $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
+close SHORTHANDS_H;
+
+open SHORTHANDS_CPP, ">StylePropertyShorthandFunctions.cpp" || die "Could not open StylePropertyShorthandFunctions.cpp for writing";
+print SHORTHANDS_CPP << "EOF";
+/* This file is automatically generated from $inputFile by makeprop, do not edit */
+
+#include "config.h"
+#include "StylePropertyShorthandFunctions.h"
+
+#include "StylePropertyShorthand.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+EOF
+
+my %longhandToShorthands = ();
+
+foreach my $name (@names) {
+ # Skip non-Shorthand properties.
+ next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
+
+ my $lowercaseId = lcfirst($nameToId{$name});
+ my @longhands = @{$propertiesWithStyleBuilderOptions{$name}{"longhands"}};
+
+ print SHORTHANDS_CPP "StylePropertyShorthand " . $lowercaseId . "Shorthand()\n";
+ print SHORTHANDS_CPP "{\n";
+ print SHORTHANDS_CPP " static const CSSPropertyID " . $lowercaseId . "Properties[] = {\n";
+ foreach (@longhands) {
+ if ($_ eq "all") {
+ foreach my $propname (@names) {
+ next if (exists $propertiesWithStyleBuilderOptions{$propname}{"longhands"});
+ next if ($propname eq "direction" || $propname eq "unicode-bidi");
+ die "Unknown CSS property used in all shorthand: $propname" if !exists($nameToId{$propname});
+ push(@{$longhandToShorthands{$propname}}, $name);
+ print SHORTHANDS_CPP " CSSProperty" . $nameToId{$propname} . ",\n";
+ }
+ } else {
+ die "Unknown CSS property used in longhands: $_" if !exists($nameToId{$_});
+ push(@{$longhandToShorthands{$_}}, $name);
+ print SHORTHANDS_CPP " CSSProperty" . $nameToId{$_} . ",\n";
+ }
+ }
+ print SHORTHANDS_CPP " };\n";
+ print SHORTHANDS_CPP " return StylePropertyShorthand(CSSProperty" . $nameToId{$name} . ", " . $lowercaseId . "Properties);\n";
+ print SHORTHANDS_CPP "}\n\n";
+}
+
+print SHORTHANDS_CPP << "EOF";
+StylePropertyShorthand shorthandForProperty(CSSPropertyID propertyID)
+{
+ static NeverDestroyed<StylePropertyShorthand> emptyShorthand;
+
+ switch (propertyID) {
+EOF
+
+foreach my $name (@names) {
+ # Skip non-Shorthand properties.
+ next if (!exists $propertiesWithStyleBuilderOptions{$name}{"longhands"});
+
+ print SHORTHANDS_CPP " case CSSProperty" . $nameToId{$name} . ":\n";
+ print SHORTHANDS_CPP " return " . lcfirst($nameToId{$name}) . "Shorthand();\n";
+}
+
+print SHORTHANDS_CPP << "EOF";
+ default:
+ return emptyShorthand;
+ }
+}
+EOF
+
+print SHORTHANDS_CPP << "EOF";
+StylePropertyShorthandVector matchingShorthandsForLonghand(CSSPropertyID propertyID)
+{
+ switch (propertyID) {
+EOF
+
+sub constructShorthandsVector {
+ my $shorthands = shift;
+
+ my $vector = "StylePropertyShorthandVector{";
+ foreach my $i (0 .. $#$shorthands) {
+ $vector .= ", " unless $i == 0;
+ $vector .= lcfirst($nameToId{$shorthands->[$i]}) . "Shorthand()";
+ }
+ $vector .= "}";
+ return $vector;
+}
+
+my %vectorToLonghands = ();
+for my $longhand (sort keys %longhandToShorthands) {
+ my @shorthands = sort(@{$longhandToShorthands{$longhand}});
+ push(@{$vectorToLonghands{constructShorthandsVector(\@shorthands)}}, $longhand);
+}
+
+for my $vector (sort keys %vectorToLonghands) {
+ foreach (@{$vectorToLonghands{$vector}}) {
+ print SHORTHANDS_CPP " case CSSProperty" . $nameToId{$_} . ":\n";
+ }
+ print SHORTHANDS_CPP " return " . $vector . ";\n";
+}
+
+print SHORTHANDS_CPP << "EOF";
+ default:
+ return { };
+ }
+}
+EOF
+
+print SHORTHANDS_CPP << "EOF";
+} // namespace WebCore
+EOF
+
+close SHORTHANDS_CPP;
+
+if (not $gperf) {
+ $gperf = $ENV{GPERF} ? $ENV{GPERF} : "gperf";
+}
system("\"$gperf\" --key-positions=\"*\" -D -n -s 2 CSSPropertyNames.gperf --output-file=CSSPropertyNames.cpp") == 0 || die "calling gperf failed: $?";