Add support for CSS Custom Properties (in preparation for implementing CSS Variables).
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Sep 2015 18:15:52 +0000 (18:15 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Sep 2015 18:15:52 +0000 (18:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=130397

Reviewed by Antti Koivisto.

Source/WebCore:

Added new tests in fast/css/custom-properties.

* WebCore.xcodeproj/project.pbxproj:
Add new header files to the project (CSSCustomPropertyValue and StyleCustomPropertyData).

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::customPropertyValue):
(WebCore::ComputedStyleExtractor::propertyValue):
If a custom property value is queried (i.e., it starts with "--"), then we use our
customPropertyValue lookup to go to the RenderStyle and fetch the appropriate custom property
value from the StyleCustomPropertyData.

(WebCore::CSSComputedStyleDeclaration::length):
(WebCore::CSSComputedStyleDeclaration::item):
Patched to include custom properties in the returned array. They appear at the end of the array
after the built-in properties.

(WebCore::ComputedStyleExtractor::propertyMatches):
Patched to check custom properties.

(WebCore::ComputedStyleExtractor::copyPropertiesInSet):
Make sure the custom properties get copied into the StyleDeclaration.

(WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
(WebCore::CSSComputedStyleDeclaration::getPropertyValue):
Patched to call customPropertyValue for custom properties.

* css/CSSComputedStyleDeclaration.h:
Add customPropertyValue() to ComputedStyleExtractor.

* css/CSSCustomPropertyValue.h: Added.
(WebCore::CSSCustomPropertyValue::create):
(WebCore::CSSCustomPropertyValue::equals):
(WebCore::CSSCustomPropertyValue::customCSSText):
(WebCore::CSSCustomPropertyValue::name):
(WebCore::CSSCustomPropertyValue::value):
(WebCore::CSSCustomPropertyValue::CSSCustomPropertyValue):
Custom properties are parsed as a property with an ID of CSSPropertyCustom and a CSSCustomPropertyValue
that holds both the name and the value of the property. Ultimately we might want to just ditch property IDs in
favor of AtomicStrings for all properties, and then the need to special case custom properties would go
away. For now, though, this is the way we work custom properties into the existing system.

* css/CSSGrammar.y.in:
Add a production for recognizing custom properties and storing them using a property ID of CSSPropertyCustom
and a CSSCustomPropertyValue that has the name/value pair.

* css/CSSParser.cpp:
(WebCore::filterProperties):
Patched to track seen custom properties and to handle them correctly.

(WebCore::CSSParser::createStyleProperties):
Pass in a seenCustomProperties table to ensure we bail when encountering the same custom property twice.

(WebCore::CSSParser::addCustomPropertyDeclaration):
Called from the grammar production to create the CSSCustomPropertyValue.

(WebCore::isCustomPropertyIdentifier):
Recognize the -- custom property during lexing.

(WebCore::CSSParser::parseIdentifier):
Patched to return a CUSTOM_PROPERTY token when a custom property is identified.

 * css/CSSParser.h:
(WebCore::isCustomPropertyName):
Add a helper function for asking if a property name is custom.

* css/CSSValue.cpp:
(WebCore::CSSValue::equals):
(WebCore::CSSValue::cssText):
(WebCore::CSSValue::destroy):
* css/CSSValue.h:
Patched to add support for CSSCustomPropertyValue.

* css/PropertySetCSSStyleDeclaration.cpp:
(WebCore::PropertySetCSSStyleDeclaration::getPropertyCSSValue):
(WebCore::PropertySetCSSStyleDeclaration::getPropertyValue):
(WebCore::PropertySetCSSStyleDeclaration::getPropertyPriority):
(WebCore::PropertySetCSSStyleDeclaration::setProperty):
(WebCore::PropertySetCSSStyleDeclaration::removeProperty):
Add code for handling custom properties in the CSS OM.

* css/StyleProperties.cpp:
(WebCore::StyleProperties::getPropertyValue):
(WebCore::StyleProperties::getCustomPropertyValue):
(WebCore::StyleProperties::getPropertyCSSValue):
(WebCore::StyleProperties::getCustomPropertyCSSValue):
(WebCore::MutableStyleProperties::removeProperty):
(WebCore::MutableStyleProperties::removeCustomProperty):
(WebCore::StyleProperties::propertyIsImportant):
(WebCore::StyleProperties::customPropertyIsImportant):
(WebCore::MutableStyleProperties::setProperty):
(WebCore::MutableStyleProperties::setCustomProperty):
(WebCore::MutableStyleProperties::addParsedProperty):
(WebCore::MutableStyleProperties::findPropertyIndex):
(WebCore::ImmutableStyleProperties::findCustomPropertyIndex):
(WebCore::MutableStyleProperties::findCustomPropertyIndex):
(WebCore::MutableStyleProperties::findCSSPropertyWithID):
(WebCore::MutableStyleProperties::findCustomCSSPropertyWithName):
(WebCore::StyleProperties::propertyMatches):
(WebCore::StyleProperties::PropertyReference::cssName):
* css/StyleProperties.h:
(WebCore::StyleProperties::findCustomPropertyIndex):
Patched to support handling custom properties in the CSS OM. We have to create equivalent methods that operate
on AtomicString propertyNames instead of on property IDs.

* css/StyleResolver.cpp:
(WebCore::StyleResolver::CascadedProperties::customProperties):
(WebCore::StyleResolver::styleForKeyframe):
(WebCore::StyleResolver::styleForPage):
(WebCore::StyleResolver::applyMatchedProperties):
(WebCore::StyleResolver::applyProperty):
(WebCore::StyleResolver::CascadedProperties::set):
(WebCore::StyleResolver::applyCascadedProperties):
The resolver has to hold a HashMap from AtomicStrings to Properties. It matches identically to how built-in
properties work except that an extensible table (HashMap) is used to hold the property data.

* css/makeprop.pl:
Patched to include the special CSSPropertyCustom value of 1 (just after the CSSPropertyInvalid id value but before the first
built-in property value).

* inspector/InspectorStyleSheet.cpp:
(WebCore::InspectorStyle::getText):
(WebCore::lowercasePropertyName):
(WebCore::InspectorStyle::populateAllProperties):
Patch inspector to not lowercase CSS custom property names, since they are case-sensitive.

* rendering/style/RenderStyle.h:
* rendering/style/StyleCustomPropertyData.h: Added.
(WebCore::StyleCustomPropertyData::create):
(WebCore::StyleCustomPropertyData::copy):
(WebCore::StyleCustomPropertyData::operator==):
(WebCore::StyleCustomPropertyData::operator!=):
(WebCore::StyleCustomPropertyData::setCustomPropertyValue):
(WebCore::StyleCustomPropertyData::getCustomPropertyValue):
(WebCore::StyleCustomPropertyData::hasCustomProperty):
(WebCore::StyleCustomPropertyData::StyleCustomPropertyData):
* rendering/style/StyleRareInheritedData.cpp:
(WebCore::StyleRareInheritedData::StyleRareInheritedData):
(WebCore::StyleRareInheritedData::operator==):
* rendering/style/StyleRareInheritedData.h:
The front end storage in the RenderStyle for custom properties. For now, custom properties are always inherited, so the
data is in StyleRareInheritedData.

LayoutTests:

* fast/css/custom-properties: Added.
* fast/css/custom-properties/computed-style-access-expected.html: Added.
* fast/css/custom-properties/computed-style-access-inherited-expected.html: Added.
* fast/css/custom-properties/computed-style-access-inherited.html: Added.
* fast/css/custom-properties/computed-style-access.html: Added.
* fast/css/custom-properties/inline-style-property-get-expected.html: Added.
* fast/css/custom-properties/inline-style-property-get.html: Added.
* fast/css/custom-properties/rule-property-get-css-value-expected.html: Added.
* fast/css/custom-properties/rule-property-get-css-value.html: Added.
* fast/css/custom-properties/rule-property-get-expected.html: Added.
* fast/css/custom-properties/rule-property-get.html: Added.
* fast/css/custom-properties/rule-property-priority-expected.html: Added.
* fast/css/custom-properties/rule-property-priority.html: Added.
* fast/css/custom-properties/rule-property-set-expected.html: Added.
* fast/css/custom-properties/rule-property-set.html: Added.
* fast/css/custom-properties/rule-serialization-expected.html: Added.
* fast/css/custom-properties/rule-serialization.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190209 268f45cc-cd09-0410-ab3c-d52691b4dbfc

37 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/custom-properties/computed-style-access-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/computed-style-access-inherited-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/computed-style-access-inherited.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/computed-style-access.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/inline-style-property-get-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/inline-style-property-get.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-get-css-value-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-get-css-value.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-get-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-get.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-priority-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-priority.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-set-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-property-set.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-serialization-expected.html [new file with mode: 0644]
LayoutTests/fast/css/custom-properties/rule-serialization.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSComputedStyleDeclaration.h
Source/WebCore/css/CSSCustomPropertyValue.h [new file with mode: 0644]
Source/WebCore/css/CSSGrammar.y.in
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSValue.cpp
Source/WebCore/css/CSSValue.h
Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
Source/WebCore/css/StyleProperties.cpp
Source/WebCore/css/StyleProperties.h
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/makeprop.pl
Source/WebCore/inspector/InspectorStyleSheet.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/StyleCustomPropertyData.h [new file with mode: 0644]
Source/WebCore/rendering/style/StyleRareInheritedData.cpp
Source/WebCore/rendering/style/StyleRareInheritedData.h

index 65bcce2..992c71f 100644 (file)
@@ -1,3 +1,28 @@
+2015-09-24  David Hyatt  <hyatt@apple.com>
+
+        Add support for CSS Custom Properties (in preparation for implementing CSS Variables).
+        https://bugs.webkit.org/show_bug.cgi?id=130397
+
+        Reviewed by Antti Koivisto.
+
+        * fast/css/custom-properties: Added.
+        * fast/css/custom-properties/computed-style-access-expected.html: Added.
+        * fast/css/custom-properties/computed-style-access-inherited-expected.html: Added.
+        * fast/css/custom-properties/computed-style-access-inherited.html: Added.
+        * fast/css/custom-properties/computed-style-access.html: Added.
+        * fast/css/custom-properties/inline-style-property-get-expected.html: Added.
+        * fast/css/custom-properties/inline-style-property-get.html: Added.
+        * fast/css/custom-properties/rule-property-get-css-value-expected.html: Added.
+        * fast/css/custom-properties/rule-property-get-css-value.html: Added.
+        * fast/css/custom-properties/rule-property-get-expected.html: Added.
+        * fast/css/custom-properties/rule-property-get.html: Added.
+        * fast/css/custom-properties/rule-property-priority-expected.html: Added.
+        * fast/css/custom-properties/rule-property-priority.html: Added.
+        * fast/css/custom-properties/rule-property-set-expected.html: Added.
+        * fast/css/custom-properties/rule-property-set.html: Added.
+        * fast/css/custom-properties/rule-serialization-expected.html: Added.
+        * fast/css/custom-properties/rule-serialization.html: Added.
+
 2015-09-24  ChangSeok Oh  <changseok.oh@collabora.com>
 
         Unreviewed, rebaseline media/media-controls-play-button-updates.html.
diff --git a/LayoutTests/fast/css/custom-properties/computed-style-access-expected.html b/LayoutTests/fast/css/custom-properties/computed-style-access-expected.html
new file mode 100644 (file)
index 0000000..a0b704e
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue("--one") + " " + document.styleSheets[0].cssRules[0].style.getPropertyValue("--two"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/computed-style-access-inherited-expected.html b/LayoutTests/fast/css/custom-properties/computed-style-access-inherited-expected.html
new file mode 100644 (file)
index 0000000..a0b704e
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue("--one") + " " + document.styleSheets[0].cssRules[0].style.getPropertyValue("--two"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/computed-style-access-inherited.html b/LayoutTests/fast/css/custom-properties/computed-style-access-inherited.html
new file mode 100644 (file)
index 0000000..47637ec
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --another: 20px; }
+</style>
+<body>
+<script>
+document.write(getComputedStyle(document.body).getPropertyValue("--one") + " " + getComputedStyle(document.body).getPropertyValue("--another"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/computed-style-access.html b/LayoutTests/fast/css/custom-properties/computed-style-access.html
new file mode 100644 (file)
index 0000000..6b1e437
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --another: 20px; }
+</style>
+<body>
+<script>
+document.write(getComputedStyle(document.documentElement).getPropertyValue("--one") + " " + getComputedStyle(document.documentElement).getPropertyValue("--another"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/inline-style-property-get-expected.html b/LayoutTests/fast/css/custom-properties/inline-style-property-get-expected.html
new file mode 100644 (file)
index 0000000..ddd3276
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+10px 20px
+</body>
+</html>
diff --git a/LayoutTests/fast/css/custom-properties/inline-style-property-get.html b/LayoutTests/fast/css/custom-properties/inline-style-property-get.html
new file mode 100644 (file)
index 0000000..f8eb3e8
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+<head>
+<body style="--one:10px; --two:20px">
+<script>
+document.write(document.body.style.getPropertyValue("--one") + " " + document.body.style.getPropertyValue("--two"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-get-css-value-expected.html b/LayoutTests/fast/css/custom-properties/rule-property-get-css-value-expected.html
new file mode 100644 (file)
index 0000000..ddd3276
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+10px 20px
+</body>
+</html>
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-get-css-value.html b/LayoutTests/fast/css/custom-properties/rule-property-get-css-value.html
new file mode 100644 (file)
index 0000000..78a52f7
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyCSSValue("--one").cssText + " " + document.styleSheets[0].cssRules[0].style.getPropertyCSSValue("--two").cssText)
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-get-expected.html b/LayoutTests/fast/css/custom-properties/rule-property-get-expected.html
new file mode 100644 (file)
index 0000000..ddd3276
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+10px 20px
+</body>
+</html>
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-get.html b/LayoutTests/fast/css/custom-properties/rule-property-get.html
new file mode 100644 (file)
index 0000000..a0b704e
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue("--one") + " " + document.styleSheets[0].cssRules[0].style.getPropertyValue("--two"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-priority-expected.html b/LayoutTests/fast/css/custom-properties/rule-property-priority-expected.html
new file mode 100644 (file)
index 0000000..62f8f9a
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+10px important
+</body>
+</html>
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-priority.html b/LayoutTests/fast/css/custom-properties/rule-property-priority.html
new file mode 100644 (file)
index 0000000..47710bb
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px !important; --one:50px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue("--one") + " " + document.styleSheets[0].cssRules[0].style.getPropertyPriority("--one"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-set-expected.html b/LayoutTests/fast/css/custom-properties/rule-property-set-expected.html
new file mode 100644 (file)
index 0000000..6432ca7
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+50px 30px
+</body>
+</html>
diff --git a/LayoutTests/fast/css/custom-properties/rule-property-set.html b/LayoutTests/fast/css/custom-properties/rule-property-set.html
new file mode 100644 (file)
index 0000000..f9b1d2c
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.styleSheets[0].cssRules[0].style.setProperty("--one", "5px")
+document.styleSheets[0].cssRules[0].style.removeProperty("--two")
+document.styleSheets[0].cssRules[0].style.setProperty("--two", "30px")
+document.styleSheets[0].cssRules[0].style.setProperty("--one", "50px")
+document.write(document.styleSheets[0].cssRules[0].style.getPropertyValue("--one") + " " + document.styleSheets[0].cssRules[0].style.getPropertyValue("--two"))
+</script>
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-serialization-expected.html b/LayoutTests/fast/css/custom-properties/rule-serialization-expected.html
new file mode 100644 (file)
index 0000000..7d6fc61
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+:root { --one: 10px; --two: 20px; }
+</body>
+</html.
diff --git a/LayoutTests/fast/css/custom-properties/rule-serialization.html b/LayoutTests/fast/css/custom-properties/rule-serialization.html
new file mode 100644 (file)
index 0000000..a3a3e1c
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+<head>
+<style>
+:root { --one: 10px; --two: 20px; }
+</style>
+<body>
+<script>
+document.write(document.styleSheets[0].cssRules[0].cssText)
+</script>
+</body>
+</html.
index 704433b..3f34e26 100644 (file)
@@ -1,3 +1,153 @@
+2015-09-24  David Hyatt  <hyatt@apple.com>
+
+        Add support for CSS Custom Properties (in preparation for implementing CSS Variables).
+        https://bugs.webkit.org/show_bug.cgi?id=130397
+
+        Reviewed by Antti Koivisto.
+
+        Added new tests in fast/css/custom-properties.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        Add new header files to the project (CSSCustomPropertyValue and StyleCustomPropertyData).
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::customPropertyValue):
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        If a custom property value is queried (i.e., it starts with "--"), then we use our
+        customPropertyValue lookup to go to the RenderStyle and fetch the appropriate custom property
+        value from the StyleCustomPropertyData.
+
+        (WebCore::CSSComputedStyleDeclaration::length):
+        (WebCore::CSSComputedStyleDeclaration::item):
+        Patched to include custom properties in the returned array. They appear at the end of the array
+        after the built-in properties.
+
+        (WebCore::ComputedStyleExtractor::propertyMatches):
+        Patched to check custom properties.
+
+        (WebCore::ComputedStyleExtractor::copyPropertiesInSet):
+        Make sure the custom properties get copied into the StyleDeclaration.
+
+        (WebCore::CSSComputedStyleDeclaration::getPropertyCSSValue):
+        (WebCore::CSSComputedStyleDeclaration::getPropertyValue):
+        Patched to call customPropertyValue for custom properties.
+
+        * css/CSSComputedStyleDeclaration.h:
+        Add customPropertyValue() to ComputedStyleExtractor.
+
+        * css/CSSCustomPropertyValue.h: Added.
+        (WebCore::CSSCustomPropertyValue::create):
+        (WebCore::CSSCustomPropertyValue::equals):
+        (WebCore::CSSCustomPropertyValue::customCSSText):
+        (WebCore::CSSCustomPropertyValue::name):
+        (WebCore::CSSCustomPropertyValue::value):
+        (WebCore::CSSCustomPropertyValue::CSSCustomPropertyValue):
+        Custom properties are parsed as a property with an ID of CSSPropertyCustom and a CSSCustomPropertyValue
+        that holds both the name and the value of the property. Ultimately we might want to just ditch property IDs in
+        favor of AtomicStrings for all properties, and then the need to special case custom properties would go
+        away. For now, though, this is the way we work custom properties into the existing system.
+
+        * css/CSSGrammar.y.in:
+        Add a production for recognizing custom properties and storing them using a property ID of CSSPropertyCustom
+        and a CSSCustomPropertyValue that has the name/value pair.
+
+        * css/CSSParser.cpp:
+        (WebCore::filterProperties):
+        Patched to track seen custom properties and to handle them correctly.
+
+        (WebCore::CSSParser::createStyleProperties):
+        Pass in a seenCustomProperties table to ensure we bail when encountering the same custom property twice.
+
+        (WebCore::CSSParser::addCustomPropertyDeclaration):
+        Called from the grammar production to create the CSSCustomPropertyValue.
+
+        (WebCore::isCustomPropertyIdentifier):
+        Recognize the -- custom property during lexing.
+
+        (WebCore::CSSParser::parseIdentifier):
+        Patched to return a CUSTOM_PROPERTY token when a custom property is identified.
+
+         * css/CSSParser.h:
+        (WebCore::isCustomPropertyName):
+        Add a helper function for asking if a property name is custom.
+
+        * css/CSSValue.cpp:
+        (WebCore::CSSValue::equals):
+        (WebCore::CSSValue::cssText):
+        (WebCore::CSSValue::destroy):
+        * css/CSSValue.h:
+        Patched to add support for CSSCustomPropertyValue.
+
+        * css/PropertySetCSSStyleDeclaration.cpp:
+        (WebCore::PropertySetCSSStyleDeclaration::getPropertyCSSValue):
+        (WebCore::PropertySetCSSStyleDeclaration::getPropertyValue):
+        (WebCore::PropertySetCSSStyleDeclaration::getPropertyPriority):
+        (WebCore::PropertySetCSSStyleDeclaration::setProperty):
+        (WebCore::PropertySetCSSStyleDeclaration::removeProperty):
+        Add code for handling custom properties in the CSS OM.
+
+        * css/StyleProperties.cpp:
+        (WebCore::StyleProperties::getPropertyValue):
+        (WebCore::StyleProperties::getCustomPropertyValue):
+        (WebCore::StyleProperties::getPropertyCSSValue):
+        (WebCore::StyleProperties::getCustomPropertyCSSValue):
+        (WebCore::MutableStyleProperties::removeProperty):
+        (WebCore::MutableStyleProperties::removeCustomProperty):
+        (WebCore::StyleProperties::propertyIsImportant):
+        (WebCore::StyleProperties::customPropertyIsImportant):
+        (WebCore::MutableStyleProperties::setProperty):
+        (WebCore::MutableStyleProperties::setCustomProperty):
+        (WebCore::MutableStyleProperties::addParsedProperty):
+        (WebCore::MutableStyleProperties::findPropertyIndex):
+        (WebCore::ImmutableStyleProperties::findCustomPropertyIndex):
+        (WebCore::MutableStyleProperties::findCustomPropertyIndex):
+        (WebCore::MutableStyleProperties::findCSSPropertyWithID):
+        (WebCore::MutableStyleProperties::findCustomCSSPropertyWithName):
+        (WebCore::StyleProperties::propertyMatches):
+        (WebCore::StyleProperties::PropertyReference::cssName):
+        * css/StyleProperties.h:
+        (WebCore::StyleProperties::findCustomPropertyIndex):
+        Patched to support handling custom properties in the CSS OM. We have to create equivalent methods that operate
+        on AtomicString propertyNames instead of on property IDs.
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::CascadedProperties::customProperties):
+        (WebCore::StyleResolver::styleForKeyframe):
+        (WebCore::StyleResolver::styleForPage):
+        (WebCore::StyleResolver::applyMatchedProperties):
+        (WebCore::StyleResolver::applyProperty):
+        (WebCore::StyleResolver::CascadedProperties::set):
+        (WebCore::StyleResolver::applyCascadedProperties):
+        The resolver has to hold a HashMap from AtomicStrings to Properties. It matches identically to how built-in
+        properties work except that an extensible table (HashMap) is used to hold the property data.
+
+        * css/makeprop.pl:
+        Patched to include the special CSSPropertyCustom value of 1 (just after the CSSPropertyInvalid id value but before the first
+        built-in property value).
+
+        * inspector/InspectorStyleSheet.cpp:
+        (WebCore::InspectorStyle::getText):
+        (WebCore::lowercasePropertyName):
+        (WebCore::InspectorStyle::populateAllProperties):
+        Patch inspector to not lowercase CSS custom property names, since they are case-sensitive.
+
+        * rendering/style/RenderStyle.h:
+        * rendering/style/StyleCustomPropertyData.h: Added.
+        (WebCore::StyleCustomPropertyData::create):
+        (WebCore::StyleCustomPropertyData::copy):
+        (WebCore::StyleCustomPropertyData::operator==):
+        (WebCore::StyleCustomPropertyData::operator!=):
+        (WebCore::StyleCustomPropertyData::setCustomPropertyValue):
+        (WebCore::StyleCustomPropertyData::getCustomPropertyValue):
+        (WebCore::StyleCustomPropertyData::hasCustomProperty):
+        (WebCore::StyleCustomPropertyData::StyleCustomPropertyData):
+        * rendering/style/StyleRareInheritedData.cpp:
+        (WebCore::StyleRareInheritedData::StyleRareInheritedData):
+        (WebCore::StyleRareInheritedData::operator==):
+        * rendering/style/StyleRareInheritedData.h:
+        The front end storage in the RenderStyle for custom properties. For now, custom properties are always inherited, so the
+        data is in StyleRareInheritedData.
+
 2015-09-24  Chris Dumez  <cdumez@apple.com>
 
         Optimize Range's lengthOfContentsInNode() for DocumentType Nodes
index 5c6fd45..5284030 100644 (file)
                BC772C5E0C4EB3440083285F /* MIMETypeRegistryMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC772C5D0C4EB3440083285F /* MIMETypeRegistryMac.mm */; };
                BC772E131331620C001EC9CE /* CSSLineBoxContainValue.h in Headers */ = {isa = PBXBuildFile; fileRef = BC772E121331620C001EC9CE /* CSSLineBoxContainValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC772E16133162C2001EC9CE /* CSSLineBoxContainValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC772E15133162C2001EC9CE /* CSSLineBoxContainValue.cpp */; };
+               BC779E141BB215BB00CAA8BF /* CSSCustomPropertyValue.h in Headers */ = {isa = PBXBuildFile; fileRef = BC779E131BB215BB00CAA8BF /* CSSCustomPropertyValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               BC779E171BB227CA00CAA8BF /* StyleCustomPropertyData.h in Headers */ = {isa = PBXBuildFile; fileRef = BC779E151BB226A200CAA8BF /* StyleCustomPropertyData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7F44A70B9E324E00A9D081 /* ImageObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BC7FA6200D1F0CBD00DB22A9 /* LiveNodeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7FA61E0D1F0CBD00DB22A9 /* LiveNodeList.cpp */; };
                BC7FA6210D1F0CBD00DB22A9 /* LiveNodeList.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7FA61F0D1F0CBD00DB22A9 /* LiveNodeList.h */; };
                BC772C5D0C4EB3440083285F /* MIMETypeRegistryMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = MIMETypeRegistryMac.mm; sourceTree = "<group>"; };
                BC772E121331620C001EC9CE /* CSSLineBoxContainValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSLineBoxContainValue.h; sourceTree = "<group>"; };
                BC772E15133162C2001EC9CE /* CSSLineBoxContainValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSSLineBoxContainValue.cpp; sourceTree = "<group>"; };
+               BC779E131BB215BB00CAA8BF /* CSSCustomPropertyValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSCustomPropertyValue.h; sourceTree = "<group>"; };
+               BC779E151BB226A200CAA8BF /* StyleCustomPropertyData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleCustomPropertyData.h; sourceTree = "<group>"; };
                BC7B2AF80450824100A8000F /* Scrollbar.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = Scrollbar.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                BC7F44A70B9E324E00A9D081 /* ImageObserver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ImageObserver.h; sourceTree = "<group>"; };
                BC7FA61E0D1F0CBD00DB22A9 /* LiveNodeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LiveNodeList.cpp; sourceTree = "<group>"; };
                                9393E602151A9A1800066F06 /* StyleCachedImageSet.cpp */,
                                9393E603151A9A1800066F06 /* StyleCachedImageSet.h */,
                                9DAC7C561AF2CB6400437C44 /* StyleContentAlignmentData.h */,
+                               BC779E151BB226A200CAA8BF /* StyleCustomPropertyData.h */,
                                BC5EB67E0E81D4A700B25965 /* StyleDashboardRegion.h */,
                                BC5EB8B60E8201BD00B25965 /* StyleDeprecatedFlexibleBoxData.cpp */,
                                BC5EB8B70E8201BD00B25965 /* StyleDeprecatedFlexibleBoxData.h */,
                                2D8FEBDB143E3EF70072502B /* CSSCrossfadeValue.h */,
                                AA0978ED0ABAA6E100874480 /* CSSCursorImageValue.cpp */,
                                AA0978EE0ABAA6E100874480 /* CSSCursorImageValue.h */,
+                               BC779E131BB215BB00CAA8BF /* CSSCustomPropertyValue.h */,
                                4A9CC81516BB9AC600EC645A /* CSSDefaultStyleSheets.cpp */,
                                4A9CC81616BB9AC600EC645A /* CSSDefaultStyleSheets.h */,
                                FB965B8217BBB62C00E835B9 /* CSSFilterImageValue.cpp */,
                                A8CFF04F0A154F09000A4234 /* FixedTableLayout.h in Headers */,
                                BC073BAA0C399B1F000F5979 /* FloatConversion.h in Headers */,
                                9A528E8417D7F52F00AA9518 /* FloatingObjects.h in Headers */,
+                               BC779E171BB227CA00CAA8BF /* StyleCustomPropertyData.h in Headers */,
                                FE699872192087E7006936BD /* FloatingPointEnvironment.h in Headers */,
                                B27535690B053814002CE64F /* FloatPoint.h in Headers */,
                                B2E27CA00B0F2B0900F17C7B /* FloatPoint3D.h in Headers */,
                                141DC053164834B900371E5A /* LayoutRect.h in Headers */,
                                A12538D413F9B60A00024754 /* LayoutRepainter.h in Headers */,
                                141DC054164834B900371E5A /* LayoutSize.h in Headers */,
+                               BC779E141BB215BB00CAA8BF /* CSSCustomPropertyValue.h in Headers */,
                                2D9066070BE141D400956998 /* LayoutState.h in Headers */,
                                141DC0481648348F00371E5A /* LayoutUnit.h in Headers */,
                                5103C2B91BA23A2600E26337 /* LegacyAny.h in Headers */,
index 5577e7b..929bbef 100644 (file)
@@ -32,6 +32,7 @@
 #include "CSSAspectRatioValue.h"
 #include "CSSBasicShapes.h"
 #include "CSSBorderImage.h"
+#include "CSSCustomPropertyValue.h"
 #include "CSSFontFeatureValue.h"
 #include "CSSFontValue.h"
 #include "CSSFunctionValue.h"
@@ -2095,6 +2096,20 @@ inline static bool isFlexOrGrid(ContainerNode* element)
     return element && element->computedStyle() && element->computedStyle()->isDisplayFlexibleOrGridBox();
 }
 
+RefPtr<CSSValue> ComputedStyleExtractor::customPropertyValue(const String& propertyName) const
+{
+    Node* styledNode = this->styledNode();
+    if (!styledNode)
+        return nullptr;
+
+    RefPtr<RenderStyle> style = computeRenderStyleForProperty(styledNode, m_pseudoElementSpecifier, CSSPropertyCustom);
+    if (!style || !style->hasCustomProperty(propertyName))
+        return nullptr;
+
+    String result = style->getCustomPropertyValue(propertyName);
+    return CSSCustomPropertyValue::create(propertyName, result);
+}
+
 RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID, EUpdateLayout updateLayout) const
 {
     Node* styledNode = this->styledNode();
@@ -3553,6 +3568,9 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
         case CSSPropertyWritingMode:
         case CSSPropertyWebkitSvgShadow:
             return svgPropertyValue(propertyID, DoNotUpdateLayout);
+        case CSSPropertyCustom:
+            ASSERT_NOT_REACHED();
+            return nullptr;
     }
 
     logUnimplementedPropertyID(propertyID);
@@ -3577,15 +3595,35 @@ unsigned CSSComputedStyleDeclaration::length() const
     if (!style)
         return 0;
 
-    return numComputedProperties;
+    const HashMap<AtomicString, String>* customProperties = style->customProperties();
+    return numComputedProperties + (customProperties ? customProperties->size() : 0);
 }
 
 String CSSComputedStyleDeclaration::item(unsigned i) const
 {
     if (i >= length())
         return emptyString();
+    
+    if (i < numComputedProperties)
+        return getPropertyNameString(computedProperties[i]);
+    
+    Node* node = m_node.get();
+    if (!node)
+        return emptyString();
 
-    return getPropertyNameString(computedProperties[i]);
+    RenderStyle* style = node->computedStyle(m_pseudoElementSpecifier);
+    if (!style)
+        return emptyString();
+    
+    unsigned index = i - numComputedProperties;
+    
+    const auto* customProperties = style->customProperties();
+    if (!customProperties || index >= customProperties->size())
+        return emptyString();
+    
+    Vector<String, 4> results;
+    copyKeysToVector(*customProperties, results);
+    return results.at(index);
 }
 
 bool ComputedStyleExtractor::propertyMatches(CSSPropertyID propertyID, const CSSValue* value) const
@@ -3666,6 +3704,22 @@ Ref<MutableStyleProperties> ComputedStyleExtractor::copyPropertiesInSet(const CS
         if (value)
             list.append(CSSProperty(set[i], value.release(), false));
     }
+    
+    auto* styledNode = this->styledNode();
+    if (styledNode) {
+        RefPtr<RenderStyle> style = computeRenderStyleForProperty(styledNode, m_pseudoElementSpecifier, CSSPropertyCustom);
+        if (style) {
+            const auto* customProperties = style->customProperties();
+            if (customProperties) {
+                HashMap<AtomicString, String>::const_iterator end = customProperties->end();
+                for (HashMap<AtomicString, String>::const_iterator it = customProperties->begin(); it != end; ++it) {
+                    RefPtr<CSSCustomPropertyValue> value = CSSCustomPropertyValue::create(it->key, it->value);
+                    list.append(CSSProperty(CSSPropertyCustom, value.release(), false));
+                }
+            }
+        }
+    }
+    
     return MutableStyleProperties::create(list.data(), list.size());
 }
 
@@ -3676,6 +3730,11 @@ CSSRule* CSSComputedStyleDeclaration::parentRule() const
 
 RefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(const String& propertyName)
 {
+    if (isCustomPropertyName(propertyName)) {
+        RefPtr<CSSValue> value = ComputedStyleExtractor(m_node, m_allowVisitedStyle, m_pseudoElementSpecifier).customPropertyValue(propertyName);
+        return value ? value->cloneForCSSOM() : nullptr;
+    }
+
     CSSPropertyID propertyID = cssPropertyID(propertyName);
     if (!propertyID)
         return nullptr;
@@ -3685,6 +3744,13 @@ RefPtr<CSSValue> CSSComputedStyleDeclaration::getPropertyCSSValue(const String&
 
 String CSSComputedStyleDeclaration::getPropertyValue(const String &propertyName)
 {
+    if (isCustomPropertyName(propertyName)) {
+        RefPtr<CSSValue> value = ComputedStyleExtractor(m_node, m_allowVisitedStyle, m_pseudoElementSpecifier).customPropertyValue(propertyName);
+        if (!value)
+            return String();
+        return value->cssText();
+    }
+
     CSSPropertyID propertyID = cssPropertyID(propertyName);
     if (!propertyID)
         return String();
index 6e91c93..fda17c7 100644 (file)
@@ -50,6 +50,7 @@ public:
     ComputedStyleExtractor(PassRefPtr<Node>, bool allowVisitedStyle = false, PseudoId = NOPSEUDO);
 
     RefPtr<CSSValue> propertyValue(CSSPropertyID, EUpdateLayout = UpdateLayout) const;
+    RefPtr<CSSValue> customPropertyValue(const String& propertyName) const;
 
     // Helper methods for HTML editing.
     Ref<MutableStyleProperties> copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const;
diff --git a/Source/WebCore/css/CSSCustomPropertyValue.h b/Source/WebCore/css/CSSCustomPropertyValue.h
new file mode 100644 (file)
index 0000000..8c4eef5
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CSSCustomPropertyValue_h
+#define CSSCustomPropertyValue_h
+
+#include "CSSValue.h"
+
+namespace WebCore {
+
+class CSSCustomPropertyValue : public CSSValue {
+public:
+    static Ref<CSSCustomPropertyValue> create(const AtomicString& name, const String& value)
+    {
+        return adoptRef(*new CSSCustomPropertyValue(name, value));
+    }
+    
+    bool equals(const CSSCustomPropertyValue& other) const { return m_name == other.m_name && m_value == other.m_value; }
+
+    String customCSSText() const { return value(); }
+
+    const AtomicString& name() const { return m_name; }
+    const String& value() const { return m_value; }
+    
+private:
+    CSSCustomPropertyValue(const AtomicString& name, const String& value)
+        : CSSValue(CustomPropertyClass)
+        , m_name(name)
+        , m_value(value)
+    {
+    }
+
+    const AtomicString m_name;
+    const String m_value;
+};
+
+} // namespace WebCore
+
+SPECIALIZE_TYPE_TRAITS_CSS_VALUE(CSSCustomPropertyValue, isCustomPropertyValue())
+
+#endif // CSSCustomPropertyValue_h
index 00742b7..f344f70 100644 (file)
@@ -88,6 +88,7 @@ static inline bool isCSSTokenAString(int yytype)
     case DIRFUNCTION:
     case ROLEFUNCTION:
 #endif
+    case CUSTOM_PROPERTY:
     case UNICODERANGE:
         return true;
     default:
@@ -244,6 +245,8 @@ static bool selectorListDoesNotMatchAnyPseudoElement(const Vector<std::unique_pt
 %token <string> ROLEFUNCTION
 #endif
 
+%token <string> CUSTOM_PROPERTY
+
 %token <string> UNICODERANGE
 
 %type <relation> combinator
@@ -1535,7 +1538,13 @@ decl_list_recovery:
     ;
 
 declaration:
-    property ':' maybe_space expr priority {
+    CUSTOM_PROPERTY maybe_space ':' maybe_space expr priority {
+        std::unique_ptr<CSSParserValueList> propertyValue($5);
+        parser->addCustomPropertyDeclaration($1, propertyValue.get(), $6);
+        $$ = true;
+        parser->markPropertyEnd($6, true);
+    }
+    | property ':' maybe_space expr priority {
         $$ = false;
         bool isPropertyParsed = false;
         std::unique_ptr<CSSParserValueList> propertyValue($4);
index 89178fb..3246982 100644 (file)
@@ -36,6 +36,7 @@
 #include "CSSContentDistributionValue.h"
 #include "CSSCrossfadeValue.h"
 #include "CSSCursorImageValue.h"
+#include "CSSCustomPropertyValue.h"
 #include "CSSFilterImageValue.h"
 #include "CSSFontFaceRule.h"
 #include "CSSFontFaceSrcValue.h"
@@ -1575,13 +1576,23 @@ CSSParser::SourceSize CSSParser::sourceSize(std::unique_ptr<MediaQueryExp>&& exp
     return SourceSize(WTF::move(expression), WTF::move(value));
 }
 
-static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties)
+static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenCustomProperties)
 {
     // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
     for (int i = input.size() - 1; i >= 0; --i) {
         const CSSProperty& property = input[i];
         if (property.isImportant() != important)
             continue;
+        
+        if (property.id() == CSSPropertyCustom) {
+            const AtomicString& name = downcast<CSSCustomPropertyValue>(*property.value()).name();
+            if (seenCustomProperties.contains(name))
+                continue;
+            seenCustomProperties.add(name);
+            output[--unusedEntries] = property;
+            continue;
+        }
+
         const unsigned propertyIDIndex = property.id() - firstCSSProperty;
         ASSERT(propertyIDIndex < seenProperties.size());
         if (seenProperties[propertyIDIndex])
@@ -1598,8 +1609,9 @@ Ref<ImmutableStyleProperties> CSSParser::createStyleProperties()
     Vector<CSSProperty, 256> results(unusedEntries);
 
     // Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
-    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties);
-    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties);
+    HashSet<AtomicString> seenCustomProperties;
+    filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
+    filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
     if (unusedEntries)
         results.remove(0, unusedEntries);
 
@@ -4124,7 +4136,29 @@ bool CSSParser::parseAlt(CSSPropertyID propID, bool important)
 
     return false;
 }
-    
+
+void CSSParser::addCustomPropertyDeclaration(const CSSParserString& name, CSSParserValueList* value, bool important)
+{
+    if (!value)
+        return;
+
+    // The custom property comes in as a parsed set of CSSParserValues collected into a list.
+    // For CSS variables, we just want to treat the entire set of values as a string, so what we do
+    // is build up a set of CSSValues and serialize them using cssText, separating multiple values
+    // with spaces.
+    AtomicString propertyName = name;
+    StringBuilder builder;
+    for (unsigned i = 0; i < value->size(); i++) {
+        if (i)
+            builder.append(' ');
+        RefPtr<CSSValue> cssValue = value->valueAt(i)->createCSSValue();
+        if (!cssValue)
+            return;
+        builder.append(cssValue->cssText());
+    }
+    addProperty(CSSPropertyCustom, CSSCustomPropertyValue::create(propertyName, builder.toString().lower()), important, false);
+}
+
 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
 // in CSS 2.1 this got somewhat reduced:
 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
@@ -10887,6 +10921,13 @@ static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter)
 }
 
 template <typename CharacterType>
+static inline bool isCustomPropertyIdentifier(CharacterType* currentCharacter)
+{
+    return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128
+        || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1]));
+}
+
+template <typename CharacterType>
 static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString)
 {
     // Compare an character memory data with a zero terminated string.
@@ -11125,10 +11166,6 @@ inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestChara
 template <typename CharacterType>
 inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape)
 {
-    // If a valid identifier start is found, we can safely
-    // parse the identifier until the next invalid character.
-    ASSERT(isIdentifierStart<CharacterType>());
-
     CharacterType* start = currentCharacter<CharacterType>();
     if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) {
         // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue
@@ -12068,6 +12105,11 @@ restartAfterComment:
             }
             resultString.setLength(result - tokenStart<SrcCharacterType>());
             yylval->string = resultString;
+        } else if (currentCharacter<SrcCharacterType>()[0] == '-' && isIdentifierStartAfterDash(currentCharacter<SrcCharacterType>() + 1)) {
+            --currentCharacter<SrcCharacterType>();
+            parseIdentifier(result, resultString, hasEscape);
+            m_token = CUSTOM_PROPERTY;
+            yylval->string = resultString;
         } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') {
             currentCharacter<SrcCharacterType>() += 2;
             m_token = SGML_CD;
index 660b438..043d8ba 100644 (file)
@@ -143,6 +143,8 @@ public:
     bool parseQuotes(CSSPropertyID, bool important);
     bool parseAlt(CSSPropertyID, bool important);
     
+    void addCustomPropertyDeclaration(const CSSParserString&, CSSParserValueList*, bool important);
+    
     RefPtr<CSSValue> parseAttr(CSSParserValueList& args);
 
     RefPtr<CSSValue> parseBackgroundColor();
@@ -755,6 +757,11 @@ inline UChar CSSParser::tokenStartChar()
     return *m_tokenStart.ptr16;
 }
 
+inline bool isCustomPropertyName(const String& propertyName)
+{
+    return propertyName.length() > 2 && propertyName.characterAt(0) == '-' && propertyName.characterAt(1) == '-';
+}
+
 inline int cssyylex(void* yylval, CSSParser* parser)
 {
     return parser->lex(yylval);
index 9db6ebe..792230c 100644 (file)
@@ -36,6 +36,7 @@
 #include "CSSContentDistributionValue.h"
 #include "CSSCrossfadeValue.h"
 #include "CSSCursorImageValue.h"
+#include "CSSCustomPropertyValue.h"
 #include "CSSFilterImageValue.h"
 #include "CSSFontFaceSrcValue.h"
 #include "CSSFontFeatureValue.h"
@@ -236,6 +237,9 @@ bool CSSValue::equals(const CSSValue& other) const
 #endif
         case CSSContentDistributionClass:
             return compareCSSValues<CSSContentDistributionValue>(*this, other);
+        case CustomPropertyClass:
+            return compareCSSValues<CSSCustomPropertyValue>(*this, other);
+        
         default:
             ASSERT_NOT_REACHED();
             return false;
@@ -330,7 +334,10 @@ String CSSValue::cssText() const
 #endif
     case CSSContentDistributionClass:
         return downcast<CSSContentDistributionValue>(*this).customCSSText();
+    case CustomPropertyClass:
+        return downcast<CSSCustomPropertyValue>(*this).customCSSText();
     }
+
     ASSERT_NOT_REACHED();
     return String();
 }
@@ -453,6 +460,9 @@ void CSSValue::destroy()
     case CSSContentDistributionClass:
         delete downcast<CSSContentDistributionValue>(this);
         return;
+    case CustomPropertyClass:
+        delete downcast<CSSCustomPropertyValue>(this);
+        return;
     }
     ASSERT_NOT_REACHED();
 }
index 1aa9aa2..2ad3af3 100644 (file)
@@ -73,6 +73,7 @@ public:
     bool isCanvasValue() const { return m_classType == CanvasClass; }
     bool isCrossfadeValue() const { return m_classType == CrossfadeClass; }
     bool isCursorImageValue() const { return m_classType == CursorImageClass; }
+    bool isCustomPropertyValue() const { return m_classType == CustomPropertyClass; }
     bool isFunctionValue() const { return m_classType == FunctionClass; }
     bool isFontFeatureValue() const { return m_classType == FontFeatureClass; }
     bool isFontFaceSrcValue() const { return m_classType == FontFaceSrcClass; }
@@ -176,7 +177,8 @@ protected:
 #endif
 
         CSSContentDistributionClass,
-
+        CustomPropertyClass,
+        
         // List class types must appear after ValueListClass.
         ValueListClass,
 #if ENABLE(CSS_IMAGE_SET)
index 0aa2318..f427820 100644 (file)
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "PropertySetCSSStyleDeclaration.h"
 
+#include "CSSCustomPropertyValue.h"
 #include "CSSParser.h"
 #include "CSSStyleSheet.h"
 #include "HTMLNames.h"
@@ -162,6 +163,13 @@ void PropertySetCSSStyleDeclaration::setCssText(const String& text, ExceptionCod
 
 RefPtr<CSSValue> PropertySetCSSStyleDeclaration::getPropertyCSSValue(const String& propertyName)
 {
+    if (isCustomPropertyName(propertyName)) {
+        RefPtr<CSSValue> value = m_propertySet->getCustomPropertyCSSValue(propertyName);
+        if (!value)
+            return nullptr;
+        return cloneAndCacheForCSSOM(value.get());
+    }
+    
     CSSPropertyID propertyID = cssPropertyID(propertyName);
     if (!propertyID)
         return nullptr;
@@ -170,6 +178,9 @@ RefPtr<CSSValue> PropertySetCSSStyleDeclaration::getPropertyCSSValue(const Strin
 
 String PropertySetCSSStyleDeclaration::getPropertyValue(const String& propertyName)
 {
+    if (isCustomPropertyName(propertyName))
+        return m_propertySet->getCustomPropertyValue(propertyName);
+
     CSSPropertyID propertyID = cssPropertyID(propertyName);
     if (!propertyID)
         return String();
@@ -178,6 +189,9 @@ String PropertySetCSSStyleDeclaration::getPropertyValue(const String& propertyNa
 
 String PropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
 {
+    if (isCustomPropertyName(propertyName))
+        return m_propertySet->customPropertyIsImportant(propertyName) ? "important" : "";
+
     CSSPropertyID propertyID = cssPropertyID(propertyName);
     if (!propertyID)
         return String();
@@ -203,7 +217,10 @@ bool PropertySetCSSStyleDeclaration::isPropertyImplicit(const String& propertyNa
 void PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, const String& value, const String& priority, ExceptionCode& ec)
 {
     StyleAttributeMutationScope mutationScope(this);
+    
     CSSPropertyID propertyID = cssPropertyID(propertyName);
+    if (isCustomPropertyName(propertyName))
+        propertyID = CSSPropertyCustom;
     if (!propertyID)
         return;
 
@@ -213,7 +230,7 @@ void PropertySetCSSStyleDeclaration::setProperty(const String& propertyName, con
     bool important = priority.find("important", 0, false) != notFound;
 
     ec = 0;
-    bool changed = m_propertySet->setProperty(propertyID, value, important, contextStyleSheet());
+    bool changed = propertyID != CSSPropertyCustom ? m_propertySet->setProperty(propertyID, value, important, contextStyleSheet()) : m_propertySet->setCustomProperty(propertyName, value, important, contextStyleSheet());
 
     didMutate(changed ? PropertyChanged : NoChanges);
 
@@ -228,6 +245,8 @@ String PropertySetCSSStyleDeclaration::removeProperty(const String& propertyName
 {
     StyleAttributeMutationScope mutationScope(this);
     CSSPropertyID propertyID = cssPropertyID(propertyName);
+    if (isCustomPropertyName(propertyName))
+        propertyID = CSSPropertyCustom;
     if (!propertyID)
         return String();
 
@@ -236,7 +255,7 @@ String PropertySetCSSStyleDeclaration::removeProperty(const String& propertyName
 
     ec = 0;
     String result;
-    bool changed = m_propertySet->removeProperty(propertyID, &result);
+    bool changed = propertyID != CSSPropertyCustom ? m_propertySet->removeProperty(propertyID, &result) : m_propertySet->removeCustomProperty(propertyName, &result);
 
     didMutate(changed ? PropertyChanged : NoChanges);
 
index 58723e1..dd45dc2 100644 (file)
@@ -24,6 +24,7 @@
 #include "StyleProperties.h"
 
 #include "CSSComputedStyleDeclaration.h"
+#include "CSSCustomPropertyValue.h"
 #include "CSSParser.h"
 #include "CSSValueKeywords.h"
 #include "CSSValueList.h"
@@ -220,6 +221,14 @@ String StyleProperties::getPropertyValue(CSSPropertyID propertyID) const
     }
 }
 
+String StyleProperties::getCustomPropertyValue(const String& propertyName) const
+{
+    RefPtr<CSSValue> value = getCustomPropertyCSSValue(propertyName);
+    if (value)
+        return value->cssText();
+    return String();
+}
+
 String StyleProperties::borderSpacingValue(const StylePropertyShorthand& shorthand) const
 {
     RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(shorthand.properties()[0]);
@@ -587,6 +596,14 @@ PassRefPtr<CSSValue> StyleProperties::getPropertyCSSValue(CSSPropertyID property
     return propertyAt(foundPropertyIndex).value();
 }
 
+RefPtr<CSSValue> StyleProperties::getCustomPropertyCSSValue(const String& propertyName) const
+{
+    int foundPropertyIndex = findCustomPropertyIndex(propertyName);
+    if (foundPropertyIndex == -1)
+        return nullptr;
+    return propertyAt(foundPropertyIndex).value();
+}
+
 bool MutableStyleProperties::removeShorthandProperty(CSSPropertyID propertyID)
 {
     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
@@ -631,6 +648,25 @@ bool MutableStyleProperties::removeProperty(CSSPropertyID propertyID, String* re
     return true;
 }
 
+bool MutableStyleProperties::removeCustomProperty(const String& propertyName, String* returnText)
+{
+    int foundPropertyIndex = findCustomPropertyIndex(propertyName);
+    if (foundPropertyIndex == -1) {
+        if (returnText)
+            *returnText = "";
+        return false;
+    }
+
+    if (returnText)
+        *returnText = propertyAt(foundPropertyIndex).value()->cssText();
+
+    // A more efficient removal strategy would involve marking entries as empty
+    // and sweeping them when the vector grows too big.
+    m_propertyVector.remove(foundPropertyIndex);
+
+    return true;
+}
+
 void MutableStyleProperties::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)
 {
     int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID));
@@ -656,6 +692,14 @@ bool StyleProperties::propertyIsImportant(CSSPropertyID propertyID) const
     return true;
 }
 
+bool StyleProperties::customPropertyIsImportant(const String& propertyName) const
+{
+    int foundPropertyIndex = findCustomPropertyIndex(propertyName);
+    if (foundPropertyIndex != -1)
+        return propertyAt(foundPropertyIndex).isImportant();
+    return false;
+}
+
 String StyleProperties::getPropertyShorthand(CSSPropertyID propertyID) const
 {
     int foundPropertyIndex = findPropertyIndex(propertyID);
@@ -684,6 +728,21 @@ bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, const String&
     return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet) == CSSParser::ParseResult::Changed;
 }
 
+bool MutableStyleProperties::setCustomProperty(const String& propertyName, const String& value, bool important, StyleSheetContents* /*contextStyleSheet*/)
+{
+    // Setting the value to an empty string just removes the property in both IE and Gecko.
+    // Setting it to null seems to produce less consistent results, but we treat it just the same.
+    if (value.isEmpty())
+        return removeCustomProperty(propertyName);
+
+    // When replacing an existing property value, this moves the property to the end of the list.
+    // Firefox preserves the position, and MSIE moves the property to the beginning.
+    RefPtr<CSSCustomPropertyValue> customValue = CSSCustomPropertyValue::create(propertyName, value);
+    addParsedProperty(CSSProperty(CSSPropertyCustom, customValue, important));
+    
+    return true;
+}
+
 void MutableStyleProperties::setProperty(CSSPropertyID propertyID, PassRefPtr<CSSValue> prpValue, bool important)
 {
     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
@@ -702,7 +761,15 @@ void MutableStyleProperties::setProperty(CSSPropertyID propertyID, PassRefPtr<CS
 bool MutableStyleProperties::setProperty(const CSSProperty& property, CSSProperty* slot)
 {
     if (!removeShorthandProperty(property.id())) {
-        CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id());
+        CSSProperty* toReplace = slot;
+        if (!slot) {
+            if (property.id() == CSSPropertyCustom) {
+                if (property.value())
+                    toReplace = findCustomCSSPropertyWithName(downcast<CSSCustomPropertyValue>(*property.value()).name());
+            } else
+                toReplace = findCSSPropertyWithID(property.id());
+        }
+        
         if (toReplace) {
             if (*toReplace == property)
                 return false;
@@ -781,6 +848,12 @@ bool MutableStyleProperties::addParsedProperties(const CSSParser::ParsedProperty
 
 bool MutableStyleProperties::addParsedProperty(const CSSProperty& property)
 {
+    if (property.id() == CSSPropertyCustom) {
+        if ((property.value() && !customPropertyIsImportant(downcast<CSSCustomPropertyValue>(*property.value()).name())) || property.isImportant())
+            return setProperty(property);
+        return false;
+    }
+    
     // Only add properties that have no !important counterpart present
     if (!propertyIsImportant(property.id()) || property.isImportant())
         return setProperty(property);
@@ -973,12 +1046,17 @@ String StyleProperties::asText() const
         } else
             value = property.value()->cssText();
 
-        if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID))
+        if (propertyID != CSSPropertyCustom && value == "initial" && !CSSProperty::isInheritedProperty(propertyID))
             continue;
 
         if (numDecls++)
             result.append(' ');
-        result.append(getPropertyName(propertyID));
+
+        if (propertyID == CSSPropertyCustom)
+            result.append(downcast<CSSCustomPropertyValue>(*property.value()).name());
+        else
+            result.append(getPropertyName(propertyID));
+
         result.appendLiteral(": ");
         result.append(value);
         if (property.isImportant())
@@ -1175,6 +1253,40 @@ int MutableStyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
     return -1;
 }
 
+int ImmutableStyleProperties::findCustomPropertyIndex(const String& propertyName) const
+{
+    // Convert the propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
+    // the compiler converting it to an int multiple times in the loop.
+    for (int n = m_arraySize - 1 ; n >= 0; --n) {
+        if (metadataArray()[n].m_propertyID == CSSPropertyCustom) {
+            // We found a custom property. See if the name matches.
+            if (!valueArray()[n])
+                continue;
+            if (downcast<CSSCustomPropertyValue>(*valueArray()[n]).name() == propertyName)
+                return n;
+        }
+    }
+
+    return -1;
+}
+
+int MutableStyleProperties::findCustomPropertyIndex(const String& propertyName) const
+{
+    // Convert the propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
+    // the compiler converting it to an int multiple times in the loop.
+    for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
+        if (m_propertyVector.at(n).metadata().m_propertyID == CSSPropertyCustom) {
+            // We found a custom property. See if the name matches.
+            if (!m_propertyVector.at(n).value())
+                continue;
+            if (downcast<CSSCustomPropertyValue>(*m_propertyVector.at(n).value()).name() == propertyName)
+                return n;
+        }
+    }
+
+    return -1;
+}
+
 CSSProperty* MutableStyleProperties::findCSSPropertyWithID(CSSPropertyID propertyID)
 {
     int foundPropertyIndex = findPropertyIndex(propertyID);
@@ -1183,6 +1295,14 @@ CSSProperty* MutableStyleProperties::findCSSPropertyWithID(CSSPropertyID propert
     return &m_propertyVector.at(foundPropertyIndex);
 }
 
+CSSProperty* MutableStyleProperties::findCustomCSSPropertyWithName(const String& propertyName)
+{
+    int foundPropertyIndex = findCustomPropertyIndex(propertyName);
+    if (foundPropertyIndex == -1)
+        return 0;
+    return &m_propertyVector.at(foundPropertyIndex);
+}
+
 bool StyleProperties::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
 {
     int foundPropertyIndex = findPropertyIndex(propertyID);
@@ -1265,6 +1385,8 @@ Ref<MutableStyleProperties> MutableStyleProperties::create(const CSSProperty* pr
 
 String StyleProperties::PropertyReference::cssName() const
 {
+    if (id() == CSSPropertyCustom)
+        return downcast<CSSCustomPropertyValue>(*value()).name();
     return getPropertyNameString(id());
 }
 
index 6f3024c..9aa65a8 100644 (file)
@@ -92,6 +92,10 @@ public:
     String getPropertyShorthand(CSSPropertyID) const;
     bool isPropertyImplicit(CSSPropertyID) const;
 
+    RefPtr<CSSValue> getCustomPropertyCSSValue(const String& propertyName) const;
+    String getCustomPropertyValue(const String& propertyName) const;
+    bool customPropertyIsImportant(const String& propertyName) const;
+
     Ref<MutableStyleProperties> copyBlockProperties() const;
 
     CSSParserMode cssParserMode() const { return static_cast<CSSParserMode>(m_cssParserMode); }
@@ -132,7 +136,8 @@ protected:
     { }
 
     int findPropertyIndex(CSSPropertyID) const;
-
+    int findCustomPropertyIndex(const String& propertyName) const;
+    
     unsigned m_cssParserMode : 2;
     mutable unsigned m_isMutable : 1;
     unsigned m_arraySize : 29;
@@ -163,7 +168,8 @@ public:
     const CSSValue** valueArray() const;
     const StylePropertyMetadata* metadataArray() const;
     int findPropertyIndex(CSSPropertyID) const;
-
+    int findCustomPropertyIndex(const String& propertyName) const;
+    
     void* m_storage;
 
 private:
@@ -221,9 +227,14 @@ public:
     CSSStyleDeclaration* ensureInlineCSSStyleDeclaration(StyledElement* parentElement);
 
     int findPropertyIndex(CSSPropertyID) const;
-
+    int findCustomPropertyIndex(const String& propertyName) const;
+    
     Vector<CSSProperty, 4> m_propertyVector;
 
+    // Methods for querying and altering CSS custom properties.
+    bool setCustomProperty(const String& propertyName, const String& value, bool important = false, StyleSheetContents* contextStyleSheet = 0);
+    bool removeCustomProperty(const String& propertyName, String* returnText = nullptr);
+
 private:
     explicit MutableStyleProperties(CSSParserMode);
     explicit MutableStyleProperties(const StyleProperties&);
@@ -231,6 +242,7 @@ private:
 
     bool removeShorthandProperty(CSSPropertyID);
     CSSProperty* findCSSPropertyWithID(CSSPropertyID);
+    CSSProperty* findCustomCSSPropertyWithName(const String&);
     std::unique_ptr<PropertySetCSSStyleDeclaration> m_cssomWrapper;
 
     friend class StyleProperties;
@@ -279,6 +291,13 @@ inline int StyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
     return downcast<ImmutableStyleProperties>(*this).findPropertyIndex(propertyID);
 }
 
+inline int StyleProperties::findCustomPropertyIndex(const String& propertyName) const
+{
+    if (is<MutableStyleProperties>(*this))
+        return downcast<MutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
+    return downcast<ImmutableStyleProperties>(*this).findCustomPropertyIndex(propertyName);
+}
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MutableStyleProperties)
index 95cca34..88b1941 100644 (file)
@@ -33,6 +33,7 @@
 #include "CSSBorderImage.h"
 #include "CSSCalculationValue.h"
 #include "CSSCursorImageValue.h"
+#include "CSSCustomPropertyValue.h"
 #include "CSSDefaultStyleSheets.h"
 #include "CSSFilterImageValue.h"
 #include "CSSFontFaceRule.h"
 #include <wtf/StdLibExtras.h>
 #include <wtf/TemporaryChange.h>
 #include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
 
 #if ENABLE(CSS_GRID_LAYOUT)
 #include "CSSGridLineNamesValue.h"
@@ -189,14 +191,17 @@ public:
 
     void applyDeferredProperties(StyleResolver&);
 
+    HashMap<AtomicString, Property>& customProperties() { return m_customProperties; }
+    
 private:
     void addStyleProperties(const StyleProperties&, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType, unsigned linkMatchType);
     static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType);
 
-    Property m_properties[numCSSProperties + 1];
-    std::bitset<numCSSProperties + 1> m_propertyIsPresent;
+    Property m_properties[numCSSProperties + 2];
+    std::bitset<numCSSProperties + 2> m_propertyIsPresent;
 
     Vector<Property, 8> m_deferredProperties;
+    HashMap<AtomicString, Property> m_customProperties;
 
     TextDirection m_direction;
     WritingMode m_writingMode;
@@ -845,6 +850,9 @@ Ref<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle
     // decl, there's nothing to override. So just add the first properties.
     CascadedProperties cascade(direction, writingMode);
     cascade.addMatches(result, false, 0, result.matchedProperties().size() - 1);
+    
+    // Resolve custom properties first.
+    applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom);
 
     applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty);
 
@@ -1011,6 +1019,9 @@ Ref<RenderStyle> StyleResolver::styleForPage(int pageIndex)
     CascadedProperties cascade(direction, writingMode);
     cascade.addMatches(result, false, 0, result.matchedProperties().size() - 1);
 
+    // Resolve custom properties first.
+    applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom);
+
     applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty);
 
     // If our font got dirtied, update it now.
@@ -1686,6 +1697,9 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
 
         applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition);
         adjustStyleForInterCharacterRuby();
+    
+        // Resolve custom variables first.
+        applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom);
 
         // Start by applying properties that other properties may depend on.
         applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty);
@@ -1701,6 +1715,9 @@ void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const
     cascade.addMatches(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
     cascade.addMatches(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
     cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
+    
+    // Resolve custom properties first.
+    applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom);
 
     applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition);
     
@@ -1881,6 +1898,12 @@ void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
 
     if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id))
         state.parentStyle()->setHasExplicitlyInheritedProperties();
+    
+    if (id == CSSPropertyCustom) {
+        CSSCustomPropertyValue* customProperty = &downcast<CSSCustomPropertyValue>(*value);
+        state.style()->setCustomPropertyValue(customProperty->name(), customProperty->value());
+        return;
+    }
 
     // Use the generated StyleBuilder.
     StyleBuilder::applyProperty(id, *this, *value, isInitial, isInherit);
@@ -2526,6 +2549,24 @@ void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue
 
     auto& property = m_properties[id];
     ASSERT(id < m_propertyIsPresent.size());
+    if (id == CSSPropertyCustom) {
+        m_propertyIsPresent.set(id);
+        const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
+        bool hasValue = customProperties().contains(customValue.name());
+        if (!hasValue) {
+            Property property;
+            property.id = id;
+            memset(property.cssValue, 0, sizeof(property.cssValue));
+            setPropertyInternal(property, id, cssValue, linkMatchType);
+            customProperties().set(customValue.name(), property);
+        } else {
+            Property property = customProperties().get(customValue.name());
+            setPropertyInternal(property, id, cssValue, linkMatchType);
+            customProperties().set(customValue.name(), property);
+        }
+        return;
+    }
+    
     if (!m_propertyIsPresent[id])
         memset(property.cssValue, 0, sizeof(property.cssValue));
     m_propertyIsPresent.set(id);
@@ -2623,6 +2664,12 @@ void StyleResolver::applyCascadedProperties(CascadedProperties& cascade, int fir
         CSSPropertyID propertyID = static_cast<CSSPropertyID>(id);
         if (!cascade.hasProperty(propertyID))
             continue;
+        if (propertyID == CSSPropertyCustom) {
+            HashMap<AtomicString, CascadedProperties::Property>::iterator end = cascade.customProperties().end();
+            for (HashMap<AtomicString, CascadedProperties::Property>::iterator it = cascade.customProperties().begin(); it != end; ++it)
+                it->value.apply(*this);
+            continue;
+        }
         auto& property = cascade.property(propertyID);
         ASSERT(!shouldApplyPropertyInParseOrder(propertyID));
         property.apply(*this);
index 5572fca..533f766 100755 (executable)
@@ -38,7 +38,7 @@ die "We've reached more than 1024 CSS properties, please make sure to update CSS
 my %namesHash;
 my @duplicates = ();
 
-my $numPredefinedProperties = 1;
+my $numPredefinedProperties = 2;
 my @names = ();
 my %nameIsInherited;
 my %propertiesWithStyleBuilderOptions;
@@ -236,6 +236,7 @@ String getJSPropertyName(CSSPropertyID id)
 
 static const bool isInheritedPropertyTable[numCSSProperties + $numPredefinedProperties] = {
     false, // CSSPropertyInvalid
+    false, // CSSPropertyCustom
 EOF
 
 foreach my $name (@names) {
@@ -283,6 +284,7 @@ namespace WebCore {
 
 enum CSSPropertyID : uint16_t {
     CSSPropertyInvalid = 0,
+    CSSPropertyCustom = 1,
 EOF
 
 my $first = $numPredefinedProperties;
@@ -313,7 +315,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);
 }
 
@@ -872,6 +874,7 @@ void StyleBuilder::applyProperty(CSSPropertyID property, StyleResolver& styleRes
 {
     switch (property) {
     case CSSPropertyInvalid:
+    case CSSPropertyCustom:
         break;
 EOF
 
index 9761edf..920c13a 100644 (file)
@@ -348,6 +348,14 @@ bool InspectorStyle::getText(String* result) const
     return true;
 }
 
+static String lowercasePropertyName(const String& name)
+{
+    // Custom properties are case-sensitive.
+    if (name.length() > 2 && name.characterAt(0) == '-' && name.characterAt(1) == '-')
+        return name;
+    return name.lower();
+}
+
 bool InspectorStyle::populateAllProperties(Vector<InspectorStyleProperty>* result) const
 {
     HashSet<String> sourcePropertyNames;
@@ -362,16 +370,16 @@ bool InspectorStyle::populateAllProperties(Vector<InspectorStyleProperty>* resul
             InspectorStyleProperty p(*it, true, false);
             p.setRawTextFromStyleDeclaration(styleDeclaration);
             result->append(p);
-            sourcePropertyNames.add(it->name.lower());
+            sourcePropertyNames.add(lowercasePropertyName(it->name));
         }
     }
 
     for (int i = 0, size = m_style->length(); i < size; ++i) {
         String name = m_style->item(i);
-        if (sourcePropertyNames.contains(name.lower()))
+        String lowerName = lowercasePropertyName(name);
+        if (sourcePropertyNames.contains(lowerName))
             continue;
-
-        sourcePropertyNames.add(name.lower());
+        sourcePropertyNames.add(lowerName);
         result->append(InspectorStyleProperty(CSSPropertySourceData(name, m_style->getPropertyValue(name), !m_style->getPropertyPriority(name).isEmpty(), true, SourceRange()), false, false));
     }
 
index 8d31cdd..68768f8 100644 (file)
@@ -513,6 +513,11 @@ public:
 
     const PseudoStyleCache* cachedPseudoStyles() const { return m_cachedPseudoStyles.get(); }
 
+    void setCustomPropertyValue(const AtomicString& name, const String& value) { rareInheritedData.access()->m_customProperties.access()->setCustomPropertyValue(name, value); }
+    String getCustomPropertyValue(const AtomicString& name) const { return rareInheritedData->m_customProperties->getCustomPropertyValue(name); }
+    bool hasCustomProperty(const AtomicString& name) const { return rareInheritedData->m_customProperties->hasCustomProperty(name); }
+    const HashMap<AtomicString, String>* customProperties() const { return &(rareInheritedData->m_customProperties->m_values); }
+
     void setHasViewportUnits(bool hasViewportUnits = true) { noninherited_flags.setHasViewportUnits(hasViewportUnits); }
     bool hasViewportUnits() const { return noninherited_flags.hasViewportUnits(); }
 
diff --git a/Source/WebCore/rendering/style/StyleCustomPropertyData.h b/Source/WebCore/rendering/style/StyleCustomPropertyData.h
new file mode 100644 (file)
index 0000000..524cc64
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012 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.
+ *
+ */
+
+#ifndef StyleCustomPropertyData_h
+#define StyleCustomPropertyData_h
+
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/text/AtomicStringHash.h>
+
+namespace WebCore {
+
+class StyleCustomPropertyData : public RefCounted<StyleCustomPropertyData> {
+public:
+    static Ref<StyleCustomPropertyData> create() { return adoptRef(*new StyleCustomPropertyData); }
+    Ref<StyleCustomPropertyData> copy() const { return adoptRef(*new StyleCustomPropertyData(*this)); }
+    
+    bool operator==(const StyleCustomPropertyData& o) const { return m_values == o.m_values; }
+    bool operator!=(const StyleCustomPropertyData &o) const { return !(*this == o); }
+    
+    void setCustomPropertyValue(const AtomicString& name, const String& value) { m_values.set(name, value); }
+    String getCustomPropertyValue(const AtomicString& name) const { return m_values.get(name); }
+    bool hasCustomProperty(const AtomicString& name) const { return m_values.contains(name); }
+
+    HashMap<AtomicString, String> m_values;
+    
+private:
+    explicit StyleCustomPropertyData()
+        : RefCounted<StyleCustomPropertyData>()
+    { }
+    StyleCustomPropertyData(const StyleCustomPropertyData& other)
+        : RefCounted<StyleCustomPropertyData>()
+        , m_values(HashMap<AtomicString, String>(other.m_values))
+    { }
+};
+
+} // namespace WebCore
+
+#endif // StyleCustomPropertyData_h
index 6b3924c..c5e87e0 100644 (file)
 #include "StyleRareInheritedData.h"
 
 #include "CursorList.h"
+#include "DataRef.h"
 #include "QuotesData.h"
 #include "RenderStyle.h"
 #include "RenderStyleConstants.h"
 #include "ShadowData.h"
+#include "StyleCustomPropertyData.h"
 #include "StyleImage.h"
 
 namespace WebCore {
@@ -60,6 +62,8 @@ struct GreaterThanOrSameSizeAsStyleRareInheritedData : public RefCounted<Greater
 #if ENABLE(TOUCH_EVENTS)
     Color tapHighlightColor;
 #endif
+
+    void* customPropertyDataRefs[1];
 };
 
 COMPILE_ASSERT(sizeof(StyleRareInheritedData) <= sizeof(GreaterThanOrSameSizeAsStyleRareInheritedData), StyleRareInheritedData_should_bit_pack);
@@ -69,6 +73,7 @@ StyleRareInheritedData::StyleRareInheritedData()
     , textStrokeWidth(RenderStyle::initialTextStrokeWidth())
     , indent(RenderStyle::initialTextIndent())
     , m_effectiveZoom(RenderStyle::initialZoom())
+    , m_customProperties(StyleCustomPropertyData::create())
     , widows(RenderStyle::initialWidows())
     , orphans(RenderStyle::initialOrphans())
     , m_hasAutoWidows(true)
@@ -150,6 +155,7 @@ inline StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedDa
     , cursorData(o.cursorData)
     , indent(o.indent)
     , m_effectiveZoom(o.m_effectiveZoom)
+    , m_customProperties(o.m_customProperties)
     , widows(o.widows)
     , orphans(o.orphans)
     , m_hasAutoWidows(o.m_hasAutoWidows)
@@ -324,6 +330,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
 #if ENABLE(CSS_TRAILING_WORD)
         && trailingWord == o.trailingWord
 #endif
+        && m_customProperties == o.m_customProperties
         && StyleImage::imagesEquivalent(listStyleImage.get(), o.listStyleImage.get());
 }
 
index e85031b..66d56a4 100644 (file)
@@ -26,7 +26,9 @@
 #define StyleRareInheritedData_h
 
 #include "Color.h"
+#include "DataRef.h"
 #include "Length.h"
+#include "StyleCustomPropertyData.h"
 #include <wtf/RefCounted.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/text/AtomicString.h>
@@ -77,6 +79,8 @@ public:
     
     Length wordSpacing;
 
+    DataRef<StyleCustomPropertyData> m_customProperties;
+
     // Paged media properties.
     short widows;
     short orphans;