diff options
Diffstat (limited to 'Source/WebCore/css/makeprop.pl')
-rwxr-xr-x | Source/WebCore/css/makeprop.pl | 958 |
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: $?"; |