Implement parsing for CSS will-change
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Aug 2015 17:59:05 +0000 (17:59 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Aug 2015 17:59:05 +0000 (17:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148052

Reviewed by Dean Jackson.

Source/WebCore:

Syntax is
    will-change: auto | <animateable-feature>#
where
    <animateable-feature> = scroll-position | contents | <custom-ident>

To support this, add WillChangeData which stores a vector of "feature"
and CSS property squished into 16 bits. This is stored in rareNonInheritedData.
If null or an empty list, the property value is 'auto'. The list preserves
unknown properties.

Test: fast/css/will-change-parsing.html

* CMakeLists.txt:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.vcxproj/WebCore.vcxproj.filters:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::getWillChangePropertyValue):
(WebCore::ComputedStyleExtractor::propertyValue):
* css/CSSParser.cpp:
(WebCore::CSSParser::parseValue):
(WebCore::isValidGridPositionCustomIdent): Renamed from isValidCustomIdent(),
since it's grid-specific.
(WebCore::CSSParser::parseIntegerOrCustomIdentFromGridPosition):
(WebCore::valueIsCSSKeyword): Returns true for the "CSS-wide" keywords like
"initial", "inherit" and "default".
(WebCore::CSSParser::parseFontFamily):
(WebCore::isValidWillChangeAnimatableFeature):
(WebCore::CSSParser::parseWillChange):
(WebCore::isValidCustomIdent): Deleted.
* css/CSSParser.h:
* css/CSSPrimitiveValue.h:
(WebCore::CSSPrimitiveValue::isPropertyID): New utility function.
* css/CSSPropertyNames.in:
* css/CSSValueKeywords.in:
* css/StyleBuilderCustom.h:
(WebCore::StyleBuilderCustom::applyValueWillChange):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setWillChange):
* rendering/style/RenderStyle.h:
* rendering/style/StyleAllInOne.cpp:
* rendering/style/StyleRareNonInheritedData.cpp:
(WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
(WebCore::StyleRareNonInheritedData::operator==):
(WebCore::StyleRareNonInheritedData::willChangeDataEquivalent):
* rendering/style/StyleRareNonInheritedData.h:
* rendering/style/WillChangeData.cpp: Added.
(WebCore::WillChangeData::operator==):
(WebCore::WillChangeData::containsScrollPosition):
(WebCore::WillChangeData::containsContents):
(WebCore::WillChangeData::containsProperty):
(WebCore::WillChangeData::addFeature):
(WebCore::WillChangeData::featureAt):
* rendering/style/WillChangeData.h: Added.
(WebCore::WillChangeData::create):
(WebCore::WillChangeData::operator!=):
(WebCore::WillChangeData::isAuto):
(WebCore::WillChangeData::numFeatures):
(WebCore::WillChangeData::WillChangeData):
(WebCore::WillChangeData::AnimatableFeature::feature):
(WebCore::WillChangeData::AnimatableFeature::property):
(WebCore::WillChangeData::AnimatableFeature::featurePropertyPair):
(WebCore::WillChangeData::AnimatableFeature::AnimatableFeature):
(WebCore::WillChangeData::AnimatableFeature::operator==):

LayoutTests:

will-change parsing test.

* fast/css/will-change-parsing-expected.txt: Added.
* fast/css/will-change-parsing.html: Added.

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

22 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css/will-change-parsing-expected.txt [new file with mode: 0644]
LayoutTests/fast/css/will-change-parsing.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj.filters
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSParser.h
Source/WebCore/css/CSSPrimitiveValue.h
Source/WebCore/css/CSSPropertyNames.in
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/StyleBuilderCustom.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/StyleAllInOne.cpp
Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
Source/WebCore/rendering/style/StyleRareNonInheritedData.h
Source/WebCore/rendering/style/WillChangeData.cpp [new file with mode: 0644]
Source/WebCore/rendering/style/WillChangeData.h [new file with mode: 0644]

index e1b9fc1..2d362d1 100644 (file)
@@ -1,3 +1,15 @@
+2015-08-14  Simon Fraser  <simon.fraser@apple.com>
+
+        Implement parsing for CSS will-change
+        https://bugs.webkit.org/show_bug.cgi?id=148052
+
+        Reviewed by Dean Jackson.
+        
+        will-change parsing test.
+
+        * fast/css/will-change-parsing-expected.txt: Added.
+        * fast/css/will-change-parsing.html: Added.
+
 2015-08-14  Alexey Proskuryakov  <ap@apple.com>
 
         Clean up js-test use in scroll-snap tests
diff --git a/LayoutTests/fast/css/will-change-parsing-expected.txt b/LayoutTests/fast/css/will-change-parsing-expected.txt
new file mode 100644 (file)
index 0000000..1a36207
--- /dev/null
@@ -0,0 +1,33 @@
+This tests checks that will-change parses correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS testComputedStyle("will-change:;") is "auto"
+PASS testComputedStyle("will-change: contents, all;") is "auto"
+PASS testComputedStyle("will-change: contents;") is "contents"
+PASS test("will-change: inherit;") is "inherit"
+PASS test("will-change: initial;") is "initial"
+PASS test("will-change: all;") is ""
+PASS test("will-change: none;") is ""
+PASS test("will-change: default;") is ""
+PASS test("will-change: will-change;") is ""
+PASS test("will-change: auto;") is "auto"
+PASS test("will-change: auto, contents;") is ""
+PASS test("will-change: scroll-position;") is "scroll-position"
+PASS test("will-change: contents;") is "contents"
+PASS test("will-change: scroll-position, scroll-position;") is "scroll-position, scroll-position"
+PASS test("will-change: contents, scroll-position, transform;") is "contents, scroll-position, transform"
+PASS test("will-change: contents, transform, scroll-position, transform;") is "contents, transform, scroll-position, transform"
+PASS test("will-change: , background;") is ""
+PASS test("will-change: background, transform;") is "background, transform"
+PASS test("will-change: background transform;") is ""
+PASS test("will-change: background, all;") is ""
+PASS test("will-change: background, will-change;") is ""
+PASS test("will-change: unknown-property;") is "unknown-property"
+PASS test("will-change: transform, initial;") is ""
+PASS test("will-change: default;") is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/css/will-change-parsing.html b/LayoutTests/fast/css/will-change-parsing.html
new file mode 100644 (file)
index 0000000..d05a6d6
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="../../resources/js-test-pre.js"></script>
+    </head>
+    <body>
+        <script>
+            description("This tests checks that will-change parses correctly.");
+
+            function test(value)
+            {
+                var div = document.createElement("div");
+                div.setAttribute("style", value);
+                document.body.appendChild(div);
+
+                var result = div.style.getPropertyValue("will-change");
+                document.body.removeChild(div);
+                return result;
+            }
+
+            function testComputedStyle(value)
+            {
+                var div = document.createElement("div");
+                div.setAttribute("style", value);
+                document.body.appendChild(div);
+
+                var result = window.getComputedStyle(div).willChange;
+                document.body.removeChild(div);
+                return result;
+            }
+
+            shouldBe('testComputedStyle("will-change:;")', '"auto"');
+            shouldBe('testComputedStyle("will-change: contents, all;")', '"auto"');
+            shouldBe('testComputedStyle("will-change: contents;")', '"contents"');
+            
+            shouldBe('test("will-change: inherit;")', '"inherit"');
+            shouldBe('test("will-change: initial;")', '"initial"');
+            shouldBe('test("will-change: all;")', '""');
+            shouldBe('test("will-change: none;")', '""');
+            shouldBe('test("will-change: default;")', '""');
+            shouldBe('test("will-change: will-change;")', '""');
+
+            shouldBe('test("will-change: auto;")', '"auto"');
+            shouldBe('test("will-change: auto, contents;")', '""');
+            shouldBe('test("will-change: scroll-position;")', '"scroll-position"');
+            shouldBe('test("will-change: contents;")', '"contents"');
+            
+            shouldBe('test("will-change: scroll-position, scroll-position;")', '"scroll-position, scroll-position"');
+
+            shouldBe('test("will-change: contents, scroll-position, transform;")', '"contents, scroll-position, transform"');
+            shouldBe('test("will-change: contents, transform, scroll-position, transform;")', '"contents, transform, scroll-position, transform"');
+
+            shouldBe('test("will-change: , background;")', '""');
+            shouldBe('test("will-change: background, transform;")', '"background, transform"');
+            shouldBe('test("will-change: background transform;")', '""');
+            shouldBe('test("will-change: background, all;")', '""');
+            shouldBe('test("will-change: background, will-change;")', '""');
+
+            shouldBe('test("will-change: unknown-property;")', '"unknown-property"');
+            
+            shouldBe('test("will-change: transform, initial;")', '""');
+            shouldBe('test("will-change: default;")', '""');
+        </script>
+        <script src="../../resources/js-test-post.js"></script>
+    </body>
+</html>
index a3a506f..4916c3d 100644 (file)
@@ -2506,6 +2506,7 @@ set(WebCore_SOURCES
     rendering/style/StyleSurroundData.cpp
     rendering/style/StyleTransformData.cpp
     rendering/style/StyleVisualData.cpp
+    rendering/style/WillChangeData.cpp
 
     rendering/svg/RenderSVGBlock.cpp
     rendering/svg/RenderSVGContainer.cpp
index 7bbf85b..1398ca3 100644 (file)
@@ -1,3 +1,75 @@
+2015-08-14  Simon Fraser  <simon.fraser@apple.com>
+
+        Implement parsing for CSS will-change
+        https://bugs.webkit.org/show_bug.cgi?id=148052
+
+        Reviewed by Dean Jackson.
+        
+        Syntax is
+            will-change: auto | <animateable-feature>#
+        where
+            <animateable-feature> = scroll-position | contents | <custom-ident>
+            
+        To support this, add WillChangeData which stores a vector of "feature"
+        and CSS property squished into 16 bits. This is stored in rareNonInheritedData.
+        If null or an empty list, the property value is 'auto'. The list preserves
+        unknown properties.
+
+        Test: fast/css/will-change-parsing.html
+
+        * CMakeLists.txt:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.vcxproj/WebCore.vcxproj.filters:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::getWillChangePropertyValue):
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseValue):
+        (WebCore::isValidGridPositionCustomIdent): Renamed from isValidCustomIdent(),
+        since it's grid-specific.
+        (WebCore::CSSParser::parseIntegerOrCustomIdentFromGridPosition):
+        (WebCore::valueIsCSSKeyword): Returns true for the "CSS-wide" keywords like
+        "initial", "inherit" and "default".
+        (WebCore::CSSParser::parseFontFamily):
+        (WebCore::isValidWillChangeAnimatableFeature):
+        (WebCore::CSSParser::parseWillChange):
+        (WebCore::isValidCustomIdent): Deleted.
+        * css/CSSParser.h:
+        * css/CSSPrimitiveValue.h:
+        (WebCore::CSSPrimitiveValue::isPropertyID): New utility function.
+        * css/CSSPropertyNames.in:
+        * css/CSSValueKeywords.in:
+        * css/StyleBuilderCustom.h:
+        (WebCore::StyleBuilderCustom::applyValueWillChange):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setWillChange):
+        * rendering/style/RenderStyle.h:
+        * rendering/style/StyleAllInOne.cpp:
+        * rendering/style/StyleRareNonInheritedData.cpp:
+        (WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
+        (WebCore::StyleRareNonInheritedData::operator==):
+        (WebCore::StyleRareNonInheritedData::willChangeDataEquivalent):
+        * rendering/style/StyleRareNonInheritedData.h:
+        * rendering/style/WillChangeData.cpp: Added.
+        (WebCore::WillChangeData::operator==):
+        (WebCore::WillChangeData::containsScrollPosition):
+        (WebCore::WillChangeData::containsContents):
+        (WebCore::WillChangeData::containsProperty):
+        (WebCore::WillChangeData::addFeature):
+        (WebCore::WillChangeData::featureAt):
+        * rendering/style/WillChangeData.h: Added.
+        (WebCore::WillChangeData::create):
+        (WebCore::WillChangeData::operator!=):
+        (WebCore::WillChangeData::isAuto):
+        (WebCore::WillChangeData::numFeatures):
+        (WebCore::WillChangeData::WillChangeData):
+        (WebCore::WillChangeData::AnimatableFeature::feature):
+        (WebCore::WillChangeData::AnimatableFeature::property):
+        (WebCore::WillChangeData::AnimatableFeature::featurePropertyPair):
+        (WebCore::WillChangeData::AnimatableFeature::AnimatableFeature):
+        (WebCore::WillChangeData::AnimatableFeature::operator==):
+
 2015-08-15  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Build fix after r188510
index d17e362..da12073 100644 (file)
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\rendering\style\WillChangeData.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\rendering\style\SVGRenderStyle.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
     <ClInclude Include="..\rendering\style\StyleTransformData.h" />
     <ClInclude Include="..\rendering\style\StyleVariableData.h" />
     <ClInclude Include="..\rendering\style\StyleVisualData.h" />
+    <ClInclude Include="..\rendering\style\WillChangeData.h" />
     <ClInclude Include="..\rendering\style\SVGRenderStyle.h" />
     <ClInclude Include="..\rendering\style\SVGRenderStyleDefs.h" />
     <ClInclude Include="..\rendering\svg\RenderSVGEllipse.h" />
index 770b4f0..e1ae88e 100644 (file)
     <ClCompile Include="..\rendering\style\StyleVisualData.cpp">
       <Filter>rendering\style</Filter>
     </ClCompile>
+    <ClCompile Include="..\rendering\style\WillChangeData.cpp">
+      <Filter>rendering\style</Filter>
+    </ClCompile>
     <ClCompile Include="..\rendering\style\SVGRenderStyle.cpp">
       <Filter>rendering\style</Filter>
     </ClCompile>
     <ClInclude Include="..\rendering\style\StyleVisualData.h">
       <Filter>rendering\style</Filter>
     </ClInclude>
+    <ClInclude Include="..\rendering\style\WillChangeData.h">
+      <Filter>rendering\style</Filter>
+    </ClInclude>
     <ClInclude Include="..\rendering\style\SVGRenderStyle.h">
       <Filter>rendering\style</Filter>
     </ClInclude>
index 3a4a128..e7188f8 100644 (file)
                0F13163E16ED0CC80035CC04 /* PlatformCAFilters.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F13163D16ED0CC80035CC04 /* PlatformCAFilters.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F13164016ED0CDE0035CC04 /* PlatformCAFiltersCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F13163F16ED0CDE0035CC04 /* PlatformCAFiltersCocoa.mm */; };
                0F15DA8A0F3AAEE70000CE47 /* AnimationControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15DA890F3AAEE70000CE47 /* AnimationControllerPrivate.h */; };
+               0F15ED5B1B7EC7C500EDDFEB /* WillChangeData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F15ED591B7EC7C500EDDFEB /* WillChangeData.cpp */; };
+               0F15ED5C1B7EC7C500EDDFEB /* WillChangeData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15ED5A1B7EC7C500EDDFEB /* WillChangeData.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F1774801378B772009DA76A /* ScrollAnimatorIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F17747E1378B771009DA76A /* ScrollAnimatorIOS.h */; };
                0F1774811378B772009DA76A /* ScrollAnimatorIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */; };
                0F3C725E1974874B00AEDD0C /* ImageSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3C725D1974874B00AEDD0C /* ImageSource.cpp */; };
                0F13163D16ED0CC80035CC04 /* PlatformCAFilters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformCAFilters.h; sourceTree = "<group>"; };
                0F13163F16ED0CDE0035CC04 /* PlatformCAFiltersCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformCAFiltersCocoa.mm; sourceTree = "<group>"; };
                0F15DA890F3AAEE70000CE47 /* AnimationControllerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimationControllerPrivate.h; sourceTree = "<group>"; };
+               0F15ED591B7EC7C500EDDFEB /* WillChangeData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WillChangeData.cpp; sourceTree = "<group>"; };
+               0F15ED5A1B7EC7C500EDDFEB /* WillChangeData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WillChangeData.h; sourceTree = "<group>"; };
                0F17747E1378B771009DA76A /* ScrollAnimatorIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollAnimatorIOS.h; sourceTree = "<group>"; };
                0F17747F1378B772009DA76A /* ScrollAnimatorIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollAnimatorIOS.mm; sourceTree = "<group>"; };
                0F3C725D1974874B00AEDD0C /* ImageSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageSource.cpp; sourceTree = "<group>"; };
                                BC2274760E8366E200E7F975 /* SVGRenderStyleDefs.cpp */,
                                BC2274770E8366E200E7F975 /* SVGRenderStyleDefs.h */,
                                448B1B780F3A2F9B0047A9E2 /* TextSizeAdjustment.h */,
+                               0F15ED591B7EC7C500EDDFEB /* WillChangeData.cpp */,
+                               0F15ED5A1B7EC7C500EDDFEB /* WillChangeData.h */,
                        );
                        path = style;
                        sourceTree = "<group>";
                                A31C4E5416E02B40002F7957 /* JSOESTextureHalfFloat.h in Headers */,
                                31078CCA1880AACE008099DC /* JSOESTextureHalfFloatLinear.h in Headers */,
                                77A17AA712F28B2A004E02F6 /* JSOESVertexArrayObject.h in Headers */,
+                               0F15ED5C1B7EC7C500EDDFEB /* WillChangeData.h in Headers */,
                                FDF6BAF9134A4C9800822920 /* JSOfflineAudioCompletionEvent.h in Headers */,
                                FDA9326716703BA9008982DC /* JSOfflineAudioContext.h in Headers */,
                                FDEA6243152102E200479DF0 /* JSOscillatorNode.h in Headers */,
                                B2FA3DAC0AB75A6F000E5AC4 /* JSSVGMatrix.cpp in Sources */,
                                B2FA3DAE0AB75A6F000E5AC4 /* JSSVGMetadataElement.cpp in Sources */,
                                B27B28290CEF0C0700D39D54 /* JSSVGMissingGlyphElement.cpp in Sources */,
+                               0F15ED5B1B7EC7C500EDDFEB /* WillChangeData.cpp in Sources */,
                                4496E3A2139813CB003EE32A /* JSSVGMPathElement.cpp in Sources */,
                                8542A7980AE5C94300DF58DF /* JSSVGNumber.cpp in Sources */,
                                B2FA3DB00AB75A6F000E5AC4 /* JSSVGNumberList.cpp in Sources */,
index 039b818..f521644 100644 (file)
@@ -67,6 +67,7 @@
 #include "WebKitCSSFilterValue.h"
 #include "WebKitCSSTransformValue.h"
 #include "WebKitFontFamilyNames.h"
+#include "WillChangeData.h"
 #include <wtf/NeverDestroyed.h>
 #include <wtf/text/StringBuilder.h>
 
@@ -1161,6 +1162,33 @@ static Ref<CSSValue> scrollSnapCoordinates(RenderStyle& style, const Vector<Leng
 }
 #endif
 
+static Ref<CSSValue> getWillChangePropertyValue(const WillChangeData* willChangeData)
+{
+    if (!willChangeData || !willChangeData->numFeatures())
+        return cssValuePool().createIdentifierValue(CSSValueAuto);
+
+    auto list = CSSValueList::createCommaSeparated();
+    for (size_t i = 0; i < willChangeData->numFeatures(); ++i) {
+        WillChangeData::FeaturePropertyPair feature = willChangeData->featureAt(i);
+        switch (feature.first) {
+        case WillChangeData::ScrollPosition:
+            list.get().append(cssValuePool().createIdentifierValue(CSSValueScrollPosition));
+            break;
+        case WillChangeData::Contents:
+            list.get().append(cssValuePool().createIdentifierValue(CSSValueContents));
+            break;
+        case WillChangeData::Property:
+            list.get().append(cssValuePool().createIdentifierValue(feature.second));
+            break;
+        case WillChangeData::Invalid:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    return WTF::move(list);
+}
+
 static Ref<CSSValueList> getDelayValue(const AnimationList* animList)
 {
     auto list = CSSValueList::createCommaSeparated();
@@ -2650,6 +2678,9 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
                 return zoomAdjustedPixelValue(sizingBox(*renderer).width(), *style);
             }
             return zoomAdjustedPixelValueForLength(style->width(), *style);
+        case CSSPropertyWillChange:
+            return getWillChangePropertyValue(style->willChange());
+            break;
         case CSSPropertyWordBreak:
             return cssValuePool().createValue(style->wordBreak());
         case CSSPropertyWordSpacing:
index 4b1e48e..fbe3475 100644 (file)
@@ -2797,6 +2797,13 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important)
         break;
     // End of CSS3 properties
 
+    case CSSPropertyWillChange: // auto | [scroll-position | contents | <custom-ident>]#
+        if (id == CSSValueAuto)
+            validPrimitive = true;
+        else
+            return parseWillChange(important);
+        break;
+
     // Apple specific properties.  These will never be standardized and are purely to
     // support custom WebKit-based Apple applications.
     case CSSPropertyWebkitLineClamp:
@@ -5229,7 +5236,7 @@ bool CSSParser::parseAnimationProperty(CSSPropertyID propId, RefPtr<CSSValue>& r
 }
 
 #if ENABLE(CSS_GRID_LAYOUT)
-static inline bool isValidCustomIdent(const CSSParserValue& value)
+static inline bool isValidGridPositionCustomIdent(const CSSParserValue& value)
 {
     return value.unit == CSSPrimitiveValue::CSS_IDENT && value.id != CSSValueSpan && value.id != CSSValueAuto;
 }
@@ -5241,14 +5248,14 @@ bool CSSParser::parseIntegerOrCustomIdentFromGridPosition(RefPtr<CSSPrimitiveVal
     if (validateUnit(valueWithCalculation, FInteger) && valueWithCalculation.value().fValue) {
         numericValue = createPrimitiveNumericValue(valueWithCalculation);
         CSSParserValue* nextValue = m_valueList->next();
-        if (nextValue && isValidCustomIdent(*nextValue)) {
+        if (nextValue && isValidGridPositionCustomIdent(*nextValue)) {
             gridLineName = createPrimitiveStringValue(*nextValue);
             m_valueList->next();
         }
         return true;
     }
 
-    if (isValidCustomIdent(valueWithCalculation)) {
+    if (isValidGridPositionCustomIdent(valueWithCalculation)) {
         gridLineName = createPrimitiveStringValue(valueWithCalculation);
         if (CSSParserValue* nextValue = m_valueList->next()) {
             ValueWithCalculation nextValueWithCalculation(*nextValue);
@@ -6685,6 +6692,12 @@ private:
     CSSValueList& m_list;
 };
 
+static bool valueIsCSSKeyword(const CSSParserValue& value)
+{
+    // FIXME: when we add "unset", we should handle it here.
+    return value.id == CSSValueInitial || value.id == CSSValueInherit || value.id == CSSValueDefault;
+}
+
 RefPtr<CSSValueList> CSSParser::parseFontFamily()
 {
     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
@@ -6701,7 +6714,7 @@ RefPtr<CSSValueList> CSSParser::parseFontFamily()
             ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitBody) ||
             (nextValue->unit == CSSPrimitiveValue::CSS_STRING || nextValue->unit == CSSPrimitiveValue::CSS_IDENT));
 
-        bool valueIsKeyword = value->id == CSSValueInitial || value->id == CSSValueInherit || value->id == CSSValueDefault;
+        bool valueIsKeyword = valueIsCSSKeyword(*value);
         if (valueIsKeyword && !inFamily) {
             if (nextValBreaksFont)
                 value = m_valueList->next();
@@ -10462,6 +10475,59 @@ bool CSSParser::parseFontVariantLigatures(bool important)
     return true;
 }
 
+static inline bool isValidWillChangeAnimatableFeature(const CSSParserValue& value)
+{
+    if (value.id == CSSValueNone || value.id == CSSValueAuto || value.id == CSSValueAll)
+        return false;
+
+    if (valueIsCSSKeyword(value))
+        return false;
+
+    if (cssPropertyID(value.string) == CSSPropertyWillChange)
+        return false;
+
+    return true;
+}
+
+bool CSSParser::parseWillChange(bool important)
+{
+    RefPtr<CSSValueList> willChangePropertyValues = CSSValueList::createCommaSeparated();
+
+    bool expectComma = false;
+    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
+        if (expectComma) {
+            if (!isComma(value))
+                return false;
+            
+            expectComma = false;
+            continue;
+        }
+
+        if (value->unit != CSSPrimitiveValue::CSS_IDENT)
+            return false;
+
+        if (!isValidWillChangeAnimatableFeature(*value))
+            return false;
+
+        RefPtr<CSSValue> cssValue;
+        if (value->id == CSSValueScrollPosition || value->id == CSSValueContents)
+            cssValue = cssValuePool().createIdentifierValue(value->id);
+        else {
+            CSSPropertyID propertyID = cssPropertyID(value->string);
+            if (propertyID != CSSPropertyInvalid)
+                cssValue = cssValuePool().createIdentifierValue(propertyID);
+            else // This might be a property we don't support.
+                cssValue = createPrimitiveStringValue(*value);
+        }
+
+        willChangePropertyValues->append(cssValue.releaseNonNull());
+        expectComma = true;
+    }
+
+    addProperty(CSSPropertyWillChange, willChangePropertyValues.release(), important);
+    return true;
+}
+
 RefPtr<CSSCalcValue> CSSParser::parseCalculation(CSSParserValue& value, CalculationPermittedValueRange range)
 {
     ASSERT(isCalculation(value));
index c918ef9..92c1b3e 100644 (file)
@@ -345,6 +345,8 @@ public:
 
     bool parseFontVariantLigatures(bool important);
 
+    bool parseWillChange(bool important);
+
     // Faster than doing a new/delete each time since it keeps one vector.
     std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>> createSelectorVector();
     void recycleSelectorVector(std::unique_ptr<Vector<std::unique_ptr<CSSParserSelector>>>);
index a174316..6c63f18 100644 (file)
@@ -206,6 +206,7 @@ public:
 #if ENABLE(CSS_SCROLL_SNAP)
     bool isLengthRepeat() const { return m_primitiveUnitType == CSS_LENGTH_REPEAT; }
 #endif
+    bool isPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID; }
     bool isRGBColor() const { return m_primitiveUnitType == CSS_RGBCOLOR; }
     bool isShape() const { return m_primitiveUnitType == CSS_SHAPE; }
     bool isString() const { return m_primitiveUnitType == CSS_STRING; }
index fd6369f..3a6b678 100644 (file)
@@ -350,6 +350,7 @@ visibility [Inherited]
 white-space [Inherited]
 widows [Inherited, AutoFunctions]
 width [Initial=initialSize, Converter=LengthSizing]
+will-change [Custom=Value]
 word-break [Inherited]
 -epub-word-break = word-break
 word-spacing [Inherited, ConditionalConverter=WordSpacing]
index fd80919..b17d9e1 100644 (file)
@@ -1126,4 +1126,8 @@ from-intrinsic
 
 // font-synthesis
 weight
-style
\ No newline at end of file
+style
+
+// will-change
+scroll-position
+contents
index 2eb1aa0..1cf5a82 100644 (file)
@@ -48,6 +48,7 @@
 #include "StyleFontSizeFunctions.h"
 #include "StyleGeneratedImage.h"
 #include "StyleResolver.h"
+#include "WillChangeData.h"
 
 namespace WebCore {
 
@@ -133,6 +134,7 @@ public:
     static void applyInitialWebkitScrollSnapPointsY(StyleResolver&);
     static void applyInheritWebkitScrollSnapPointsY(StyleResolver&);
 #endif
+    static void applyValueWillChange(StyleResolver&, CSSValue&);
 
 private:
     static void resetEffectiveZoom(StyleResolver&);
@@ -1717,6 +1719,37 @@ inline void StyleBuilderCustom::applyInheritWebkitScrollSnapPointsY(StyleResolve
 }
 #endif
 
+inline void StyleBuilderCustom::applyValueWillChange(StyleResolver& styleResolver, CSSValue& value)
+{
+    if (is<CSSPrimitiveValue>(value)) {
+        ASSERT(downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueAuto);
+        styleResolver.style()->setWillChange(nullptr);
+        return;
+    }
+
+    Ref<WillChangeData> willChange = WillChangeData::create();
+    for (auto& item : downcast<CSSValueList>(value)) {
+        if (!is<CSSPrimitiveValue>(item.get()))
+            continue;
+
+        const auto& primitiveValue = downcast<CSSPrimitiveValue>(item.get());
+        switch (primitiveValue.getValueID()) {
+        case CSSValueScrollPosition:
+            willChange->addFeature(WillChangeData::Feature::ScrollPosition);
+            break;
+        case CSSValueContents:
+            willChange->addFeature(WillChangeData::Feature::Contents);
+            break;
+        default:
+            if (primitiveValue.isPropertyID())
+                willChange->addFeature(WillChangeData::Feature::Property, primitiveValue.getPropertyID());
+            break;
+        }
+    }
+
+    styleResolver.style()->setWillChange(WTF::move(willChange));
+}
+
 } // namespace WebCore
 
 #endif // StyleBuilderCustom_h
index ddf0198..d1326a9 100644 (file)
@@ -40,6 +40,7 @@
 #include "StyleResolver.h"
 #include "StyleScrollSnapPoints.h"
 #include "StyleSelfAlignmentData.h"
+#include "WillChangeData.h"
 #include <wtf/MathExtras.h>
 #include <wtf/StdLibExtras.h>
 #include <algorithm>
@@ -925,6 +926,15 @@ void RenderStyle::setQuotes(PassRefPtr<QuotesData> q)
     rareInheritedData.access()->quotes = q;
 }
 
+void RenderStyle::setWillChange(PassRefPtr<WillChangeData> willChangeData)
+{
+    if (rareNonInheritedData->m_willChange == willChangeData
+        || (rareNonInheritedData->m_willChange && willChangeData && *rareNonInheritedData->m_willChange == *willChangeData))
+        return;
+
+    rareNonInheritedData.access()->m_willChange = WTF::move(willChangeData);
+}
+
 void RenderStyle::clearCursorList()
 {
     if (rareInheritedData->cursorData)
index cccc93d..4db6a34 100644 (file)
@@ -113,6 +113,7 @@ class StyleImage;
 class StyleInheritedData;
 class StyleResolver;
 class TransformationMatrix;
+class WillChangeData;
 
 struct ScrollSnapPoints;
 
@@ -1778,7 +1779,7 @@ public:
     }
     ClipPathOperation* clipPath() const { return rareNonInheritedData->m_clipPath.get(); }
 
-    static ClipPathOperation* initialClipPath() { return 0; }
+    static ClipPathOperation* initialClipPath() { return nullptr; }
 
     bool hasContent() const { return contentData(); }
     const ContentData* contentData() const { return rareNonInheritedData->m_content.get(); }
@@ -1798,6 +1799,9 @@ public:
     QuotesData* quotes() const { return rareInheritedData->quotes.get(); }
     void setQuotes(PassRefPtr<QuotesData>);
 
+    WillChangeData* willChange() const { return rareNonInheritedData->m_willChange.get(); }
+    void setWillChange(PassRefPtr<WillChangeData>);
+
     const AtomicString& hyphenString() const;
 
     bool inheritedNotEqual(const RenderStyle*) const;
@@ -2003,6 +2007,8 @@ public:
     static QuotesData* initialQuotes() { return nullptr; }
     static const AtomicString& initialContentAltText() { return emptyAtom; }
 
+    static WillChangeData* initialWillChange() { return nullptr; }
+
 #if ENABLE(CSS_SCROLL_SNAP)
     static ScrollSnapType initialScrollSnapType() { return ScrollSnapType::None; }
     static ScrollSnapPoints* initialScrollSnapPointsX() { return nullptr; }
index 0470dce..7c6c079 100644 (file)
@@ -57,3 +57,4 @@
 #include "StyleSurroundData.cpp"
 #include "StyleTransformData.cpp"
 #include "StyleVisualData.cpp"
+#include "WillChangeData.cpp"
index 16dd8b6..0d4d8b5 100644 (file)
@@ -59,8 +59,8 @@ StyleRareNonInheritedData::StyleRareNonInheritedData()
 #if ENABLE(CSS_SCROLL_SNAP)
     , m_scrollSnapPoints(StyleScrollSnapPoints::create())
 #endif
+    , m_willChange(RenderStyle::initialWillChange())
     , m_mask(FillLayer(MaskFillLayer))
-    , m_pageSize()
 #if ENABLE(CSS_SHAPES)
     , m_shapeOutside(RenderStyle::initialShapeOutside())
     , m_shapeMargin(RenderStyle::initialShapeMargin())
@@ -136,6 +136,7 @@ inline StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonIn
     , m_counterDirectives(o.m_counterDirectives ? clone(*o.m_counterDirectives) : nullptr)
     , m_altText(o.m_altText)
     , m_boxShadow(o.m_boxShadow ? std::make_unique<ShadowData>(*o.m_boxShadow) : nullptr)
+    , m_willChange(o.m_willChange)
     , m_boxReflect(o.m_boxReflect)
     , m_animations(o.m_animations ? std::make_unique<AnimationList>(*o.m_animations) : nullptr)
     , m_transitions(o.m_transitions ? std::make_unique<AnimationList>(*o.m_transitions) : nullptr)
@@ -234,6 +235,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
         && contentDataEquivalent(o)
         && counterDataEquivalent(o)
         && shadowDataEquivalent(o)
+        && willChangeDataEquivalent(o)
         && reflectionDataEquivalent(o)
         && animationDataEquivalent(o)
         && transitionDataEquivalent(o)
@@ -245,7 +247,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
         && m_shapeMargin == o.m_shapeMargin
         && m_shapeImageThreshold == o.m_shapeImageThreshold
 #endif
-        && m_clipPath == o.m_clipPath
+        && m_clipPath == o.m_clipPath // FIXME: This needs to compare values.
         && m_textDecorationColor == o.m_textDecorationColor
         && m_visitedLinkTextDecorationColor == o.m_visitedLinkTextDecorationColor
         && m_visitedLinkBackgroundColor == o.m_visitedLinkBackgroundColor
@@ -323,6 +325,16 @@ bool StyleRareNonInheritedData::shadowDataEquivalent(const StyleRareNonInherited
     return true;
 }
 
+bool StyleRareNonInheritedData::willChangeDataEquivalent(const StyleRareNonInheritedData& o) const
+{
+    if (m_willChange != o.m_willChange) {
+        if (!m_willChange || !o.m_willChange)
+            return false;
+        return *m_willChange == *o.m_willChange;
+    }
+    return true;
+}
+
 bool StyleRareNonInheritedData::reflectionDataEquivalent(const StyleRareNonInheritedData& o) const
 {
     if (m_boxReflect != o.m_boxReflect) {
index dc97e15..f61752d 100644 (file)
@@ -26,6 +26,7 @@
 #define StyleRareNonInheritedData_h
 
 #include "BasicShapes.h"
+#include "CSSPropertyNames.h"
 #include "ClipPathOperation.h"
 #include "CounterDirectives.h"
 #include "CursorData.h"
@@ -36,6 +37,7 @@
 #include "ShapeValue.h"
 #include "StyleContentAlignmentData.h"
 #include "StyleSelfAlignmentData.h"
+#include "WillChangeData.h"
 #include <memory>
 #include <wtf/PassRefPtr.h>
 #include <wtf/Vector.h>
@@ -92,6 +94,7 @@ public:
     bool contentDataEquivalent(const StyleRareNonInheritedData&) const;
     bool counterDataEquivalent(const StyleRareNonInheritedData&) const;
     bool shadowDataEquivalent(const StyleRareNonInheritedData&) const;
+    bool willChangeDataEquivalent(const StyleRareNonInheritedData&) const;
     bool reflectionDataEquivalent(const StyleRareNonInheritedData&) const;
     bool animationDataEquivalent(const StyleRareNonInheritedData&) const;
     bool transitionDataEquivalent(const StyleRareNonInheritedData&) const;
@@ -144,6 +147,8 @@ public:
     String m_altText;
 
     std::unique_ptr<ShadowData> m_boxShadow; // For box-shadow decorations.
+
+    RefPtr<WillChangeData> m_willChange; // Null indicates 'auto'.
     
     RefPtr<StyleReflection> m_boxReflect;
 
diff --git a/Source/WebCore/rendering/style/WillChangeData.cpp b/Source/WebCore/rendering/style/WillChangeData.cpp
new file mode 100644 (file)
index 0000000..e631ccf
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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.
+ */
+
+#include "config.h"
+#include "WillChangeData.h"
+
+namespace WebCore {
+
+bool WillChangeData::operator==(const WillChangeData& other) const
+{
+    return m_animatableFeatures == other.m_animatableFeatures;
+}
+
+bool WillChangeData::containsScrollPosition() const
+{
+    for (const auto& feature : m_animatableFeatures) {
+        if (feature.feature() == ScrollPosition)
+            return true;
+    }
+    return false;
+}
+
+bool WillChangeData::containsContents() const
+{
+    for (const auto& feature : m_animatableFeatures) {
+        if (feature.feature() == Contents)
+            return true;
+    }
+    return false;
+}
+
+bool WillChangeData::containsProperty(CSSPropertyID property) const
+{
+    for (const auto& feature : m_animatableFeatures) {
+        if (feature.property() == property)
+            return true;
+    }
+    return false;
+}
+
+void WillChangeData::addFeature(Feature feature, CSSPropertyID propertyID)
+{
+    ASSERT(feature == Property || propertyID == CSSPropertyInvalid);
+    m_animatableFeatures.append(AnimatableFeature(feature, propertyID));
+}
+
+WillChangeData::FeaturePropertyPair WillChangeData::featureAt(size_t index) const
+{
+    if (index >= m_animatableFeatures.size())
+        return FeaturePropertyPair(Invalid, CSSPropertyInvalid);
+
+    return m_animatableFeatures[index].featurePropertyPair();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/style/WillChangeData.h b/Source/WebCore/rendering/style/WillChangeData.h
new file mode 100644 (file)
index 0000000..16d9887
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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. AND ITS CONTRIBUTORS ``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 ITS 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 WillChangeData_h
+#define WillChangeData_h
+
+#include "CSSPropertyNames.h"
+#include "RenderStyleConstants.h"
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class WillChangeData : public RefCounted<WillChangeData> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static Ref<WillChangeData> create()
+    {
+        return adoptRef(*new WillChangeData);
+    }
+    
+    bool operator==(const WillChangeData&) const;
+    bool operator!=(const WillChangeData& o) const
+    {
+        return !(*this == o);
+    }
+
+    bool isAuto() const { return m_animatableFeatures.isEmpty(); }
+    size_t numFeatures() const { return m_animatableFeatures.size(); }
+
+    bool containsScrollPosition() const;
+    bool containsContents() const;
+    bool containsProperty(CSSPropertyID) const;
+
+    enum Feature {
+        ScrollPosition,
+        Contents,
+        Property,
+        Invalid
+    };
+
+    void addFeature(Feature, CSSPropertyID = CSSPropertyInvalid);
+    
+    typedef std::pair<Feature, CSSPropertyID> FeaturePropertyPair;
+    FeaturePropertyPair featureAt(size_t) const;
+
+private:
+    WillChangeData()
+    {
+    }
+
+    struct AnimatableFeature {
+        static const int numCSSPropertyIDBits = 14;
+        COMPILE_ASSERT(numCSSProperties < (1 << numCSSPropertyIDBits), CSSPropertyID_should_fit_in_14_bits);
+
+        unsigned m_feature : 2;
+        unsigned m_cssPropertyID : numCSSPropertyIDBits;
+
+        Feature feature() const
+        {
+            return static_cast<Feature>(m_feature);
+        }
+
+        CSSPropertyID property() const
+        {
+            return feature() == Property ? static_cast<CSSPropertyID>(m_cssPropertyID) : CSSPropertyInvalid;
+        }
+        
+        FeaturePropertyPair featurePropertyPair() const
+        {
+            return FeaturePropertyPair(feature(), property());
+        }
+
+        AnimatableFeature(Feature willChange, CSSPropertyID willChangeProperty = CSSPropertyInvalid)
+        {
+            switch (willChange) {
+            case Property:
+                ASSERT(willChangeProperty != CSSPropertyInvalid);
+                m_cssPropertyID = willChangeProperty;
+                FALLTHROUGH;
+            case ScrollPosition:
+            case Contents:
+                m_feature = static_cast<unsigned>(willChange);
+                break;
+            case Invalid:
+                ASSERT_NOT_REACHED();
+                break;
+            }
+        }
+        
+        bool operator==(const AnimatableFeature& other) const
+        {
+            return m_feature == other.m_feature && m_cssPropertyID == other.m_cssPropertyID;
+        }
+    };
+
+    Vector<AnimatableFeature, 1> m_animatableFeatures;
+};
+
+
+} // namespace WebCore
+
+#endif // WillChangeData_h