blob: d6445be73088af25bed72c7e7ed0027d06b80fdb [file] [log] [blame]
#! /usr/bin/perl
#
# This file is part of the WebKit project
#
# Copyright (C) 1999 Waldo Bastian (bastian@kde.org)
# Copyright (C) 2007, 2008, 2012, 2014, 2015 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
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# 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;
my $gperf;
GetOptions('defines=s' => \$defines,
'preprocessor=s' => \$preprocessor,
'gperf-executable=s' => \$gperf);
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 %namesHash;
my @duplicates = ();
my $numPredefinedProperties = 2;
my @names = ();
my %nameIsInherited;
my %propertiesWithStyleBuilderOptions;
my %styleBuilderOptions = (
AnimationProperty => 1, # Defined in Source/WebCore/css/StyleBuilderConverter.h
AutoFunctions => 1,
ConditionalConverter => 1,
Converter => 1,
Custom => 1,
FillLayerProperty => 1,
FontProperty => 1,
Getter => 1,
Initial => 1,
Longhands => 1,
NameForMethods => 1,
NoDefaultColor => 1,
SVG => 1,
SkipBuilder => 1,
Setter => 1,
VisitedLinkColorSupport => 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);
}
$_ =~ 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";
}
push @aliases, $_;
} else {
$nameIsInherited{$_} = 0;
$propertiesWithStyleBuilderOptions{$_} = {};
foreach my $option (@options) {
my ($optionName, $optionValue) = split(/=/, $option);
if ($optionName eq "Inherited") {
$nameIsInherited{$_} = 1;
} elsif ($styleBuilderOptions{$optionName}) {
$propertiesWithStyleBuilderOptions{$_}{$optionName} = $optionValue;
} else {
die "Unrecognized \"" . $optionName . "\" option for " . $_ . " property.";
}
}
my $id = $_;
$id =~ s/(^[^-])|-(.)/uc($1||$2)/ge;
$nameToId{$_} = $id;
push @names, $_;
}
}
if (@duplicates > 0) {
die 'Duplicate CSS property names: ', join(', ', @duplicates) . "\n";
}
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 */
#include "config.h"
#include \"CSSProperty.h\"
#include \"CSSPropertyNames.h\"
#include \"HashTools.h\"
#include <string.h>
#include <wtf/ASCIICType.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/WTFString.h>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored \"-Wunknown-pragmas\"
#pragma clang diagnostic ignored \"-Wdeprecated-register\"
#pragma clang diagnostic ignored \"-Wimplicit-fallthrough\"
#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";
foreach my $name (@names) {
print GPERF " \"$name\",\n";
}
print GPERF "};\n\n";
print GPERF << "EOF";
%}
%struct-type
struct Property;
%omit-struct-type
%language=C++
%readonly-tables
%global-table
%compare-strncmp
%define class-name CSSPropertyNamesHash
%define lookup-function-name findPropertyImpl
%define hash-function-name propery_hash_function
%define word-array-name property_wordlist
%enum
%%
EOF
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";
}
print GPERF<< "EOF";
%%
const Property* findProperty(const char* str, unsigned int len)
{
return CSSPropertyNamesHash::findPropertyImpl(str, len);
}
const char* getPropertyName(CSSPropertyID id)
{
if (id < firstCSSProperty)
return 0;
int index = id - firstCSSProperty;
if (index >= numCSSProperties)
return 0;
return propertyNameStrings[index];
}
const AtomicString& getPropertyNameAtomicString(CSSPropertyID id)
{
if (id < firstCSSProperty)
return nullAtom;
int index = id - firstCSSProperty;
if (index >= numCSSProperties)
return nullAtom;
static AtomicString* propertyStrings = new AtomicString[numCSSProperties]; // Intentionally never destroyed.
AtomicString& propertyString = propertyStrings[index];
if (propertyString.isNull()) {
const char* propertyName = propertyNameStrings[index];
propertyString = AtomicString(propertyName, strlen(propertyName), AtomicString::ConstructFromLiteral);
}
return propertyString;
}
String getPropertyNameString(CSSPropertyID id)
{
// We share the StringImpl with the AtomicStrings.
return getPropertyNameAtomicString(id).string();
}
String getJSPropertyName(CSSPropertyID id)
{
char result[maxCSSPropertyNameLength + 1];
const char* cssPropertyName = getPropertyName(id);
const char* propertyNamePointer = cssPropertyName;
if (!propertyNamePointer)
return emptyString();
char* resultPointer = result;
while (char character = *propertyNamePointer++) {
if (character == '-') {
char nextCharacter = *propertyNamePointer++;
if (!nextCharacter)
break;
character = (propertyNamePointer - 2 != cssPropertyName) ? toASCIIUpper(nextCharacter) : nextCharacter;
}
*resultPointer++ = character;
}
*resultPointer = '\\0';
return WTF::String(result);
}
static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
false, // CSSPropertyInvalid
true, // CSSPropertyCustom
EOF
foreach my $name (@names) {
my $id = $nameToId{$name};
my $value = $nameIsInherited{$name} ? "true " : "false";
print GPERF " $value, // CSSProperty$id\n";
}
print GPERF<< "EOF";
};
bool CSSProperty::isInheritedProperty(CSSPropertyID id)
{
ASSERT(id <= lastCSSProperty);
ASSERT(id != CSSPropertyInvalid);
return isInheritedPropertyTable[id];
}
} // namespace WebCore
#if defined(__clang__)
#pragma clang diagnostic pop
#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 */
#ifndef CSSPropertyNames_h
#define CSSPropertyNames_h
#include <string.h>
#include <wtf/HashFunctions.h>
#include <wtf/HashTraits.h>
namespace WTF {
class AtomicString;
class String;
}
namespace WebCore {
enum CSSPropertyID : uint16_t {
CSSPropertyInvalid = 0,
CSSPropertyCustom = 1,
EOF
my $first = $numPredefinedProperties;
my $i = $numPredefinedProperties;
my $maxLen = 0;
foreach my $name (@names) {
print HEADER " CSSProperty" . $nameToId{$name} . " = " . $i . ",\n";
$i = $i + 1;
if (length($name) > $maxLen) {
$maxLen = length($name);
}
}
my $num = $i - $first;
my $last = $i - 1;
print HEADER "};\n\n";
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 << "EOF";
const char* getPropertyName(CSSPropertyID);
const WTF::AtomicString& getPropertyNameAtomicString(CSSPropertyID id);
WTF::String getPropertyNameString(CSSPropertyID id);
WTF::String getJSPropertyName(CSSPropertyID);
inline CSSPropertyID convertToCSSPropertyID(int value)
{
ASSERT((value >= firstCSSProperty && value <= lastCSSProperty) || value == CSSPropertyInvalid || value == CSSPropertyCustom);
return static_cast<CSSPropertyID>(value);
}
} // namespace WebCore
namespace WTF {
template<> struct DefaultHash<WebCore::CSSPropertyID> { typedef IntHash<unsigned> Hash; };
template<> struct HashTraits<WebCore::CSSPropertyID> : GenericHashTraits<WebCore::CSSPropertyID> {
static const bool emptyValueIsZero = true;
static const bool needsDestruction = false;
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); }
};
}
#endif // CSSPropertyNames_h
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}{"NameForMethods"})) {
$nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
}
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}{"NameForMethods"})) {
$nameForMethods = $propertiesWithStyleBuilderOptions{$name}{"NameForMethods"};
}
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}{"FillLayerProperty"})) {
$propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initialFill" . $nameForMethods;
} else {
$propertiesWithStyleBuilderOptions{$name}{"Initial"} = "initial" . $nameForMethods;
}
}
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 . ".getValueID() == 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 . "AnimationList& list = styleResolver.style()->" . getEnsureAnimationsOrTransitionsMethod($name) . "();\n";
$setterContent .= $indent . "const AnimationList* 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 . "const FillLayer& 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 . "FillLayer* 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 . "FillLayer* 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}{"AutoFunctions"}) {
$setterContent .= $indent . " " . getAutoSetter($name, $style) . ";\n";
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
my $initialColor = "RenderStyle::" . $initial . "()";
$setterContent .= generateColorValueSetter($name, $initialColor, $indent . " ");
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
$setterContent .= generateAnimationPropertyInitialValueSetter($name, $indent . " ");
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
$setterContent .= $indent . " auto fontDescription = styleResolver.fontDescription();\n";
$setterContent .= $indent . " fontDescription." . $setter . "(FontCascadeDescription::" . $initial . "());\n";
$setterContent .= $indent . " styleResolver.setFontDescription(fontDescription);\n";
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FillLayerProperty"}) {
$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}{"AutoFunctions"}) {
$setterContent .= $indent . " if (" . getAutoGetter($name, $parentStyle) . ") {\n";
$setterContent .= $indent . " " . getAutoSetter($name, $style) . ";\n";
$setterContent .= $indent . " return;\n";
$setterContent .= $indent . " }\n";
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
$setterContent .= $indent . " Color color = " . $parentStyle . "->" . $getter . "();\n";
if (!exists($propertiesWithStyleBuilderOptions{$name}{"NoDefaultColor"})) {
$setterContent .= $indent . " if (!color.isValid())\n";
$setterContent .= $indent . " color = " . $parentStyle . "->color();\n";
}
$setterContent .= generateColorValueSetter($name, "color", $indent . " ");
$didCallSetValue = 1;
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"AnimationProperty"}) {
$setterContent .= generateAnimationPropertyInheritValueSetter($name, $indent . " ");
$didCallSetValue = 1;
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
$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}{"FillLayerProperty"}) {
$setterContent .= generateFillLayerPropertyInheritValueSetter($name, $indent . " ");
$didCallSetValue = 1;
}
if (!$didCallSetValue) {
my $inheritedValue = $parentStyle . "->" . ($isSVG ? "svgStyle()." : "") . $getter . "()";
$setterContent .= $indent . " " . generateSetValueStatement($name, $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}{"ConditionalConverter"})) {
$setterContent .= $indent . " auto convertedValue = StyleBuilderConverter::convert" . $propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"} . "(styleResolver, value);\n";
$convertedValue = "convertedValue.value()";
} else {
$convertedValue = "downcast<CSSPrimitiveValue>(value)";
}
my $setter = $propertiesWithStyleBuilderOptions{$name}{"Setter"};
my $style = "styleResolver.style()";
my $didCallSetValue = 0;
if (exists $propertiesWithStyleBuilderOptions{$name}{"AutoFunctions"}) {
$setterContent .= $indent . " if (downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueAuto) {\n";
$setterContent .= $indent . " ". getAutoSetter($name, $style) . ";\n";
$setterContent .= $indent . " return;\n";
$setterContent .= $indent . " }\n";
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"VisitedLinkColorSupport"}) {
$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}{"AnimationProperty"}) {
$setterContent .= generateAnimationPropertyValueSetter($name, $indent . " ");
$didCallSetValue = 1;
} elsif (exists $propertiesWithStyleBuilderOptions{$name}{"FontProperty"}) {
$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}{"FillLayerProperty"}) {
$setterContent .= generateFillLayerPropertyValueSetter($name, $indent . " ");
$didCallSetValue = 1;
}
if (!$didCallSetValue) {
if (exists($propertiesWithStyleBuilderOptions{$name}{"ConditionalConverter"})) {
$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 CSSPropertyNames.in 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}{"SkipBuilder"});
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}{"SkipBuilder"}) {
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";
}
print STYLEBUILDER << "EOF";
};
}
} // namespace WebCore
EOF
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 CSSPropertyNames.in by makeprop, do not edit */
#ifndef StylePropertyShorthandFunctions_h
#define StylePropertyShorthandFunctions_h
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
#endif // StylePropertyShorthandFunctions_h
EOF
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 CSSPropertyNames.in 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 = split(/\|/, $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: " . $nameToId{$propname} if !exists($nameToId{$propname});
push(@{$longhandToShorthands{$propname}}, $name);
print SHORTHANDS_CPP " CSSProperty" . $nameToId{$propname} . ",\n";
}
} else {
die "Unknown CSS property used in Longhands: " . $nameToId{$_} 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: $?";