Implement animation of font-variation-settings
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Sep 2016 23:08:02 +0000 (23:08 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Sep 2016 23:08:02 +0000 (23:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=162783

Reviewed by Simon Fraser.

Source/WebCore:

Modify CSSPropertyAnimation to understand FontVariationSettings objects and how
to interpolate them.

If two FontVariationSettings objects are unlike (meaning they specify different
variation axes), for now the interpolation simply returns an empty object. This
might change in the future, but for now, this is a reasonable place to start.

Because CSSPropertyAnimation interacts with RenderStyles instead of
FontDescriptions, this patch adds a transparent accessor from the RenderStyle
to the inner FontDescription.

Tests: animations/font-variation-settings-order.html
       animations/font-variation-settings-unlike.html
       animations/font-variation-settings.html

* page/animation/CSSPropertyAnimation.cpp:
(WebCore::blendFunc):
(WebCore::PropertyWrapperFontVariationSettings::PropertyWrapperFontVariationSettings):
(WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setFontVariationSettings):
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::fontVariationSettings):

LayoutTests:

Animation tests need a little infrastructure to be able to tell if two computed
values for font-variation-settings are equivalent.

* animations/font-variation-settings-expected.html: Added.
* animations/font-variation-settings-order-expected.html: Added.
* animations/font-variation-settings-order.html: Added.
* animations/font-variation-settings-unlike-expected.html: Added.
* animations/font-variation-settings-unlike.html: Added.
* animations/font-variation-settings.html: Added.
* animations/resources/animation-test-helpers.js:
(compareFontVariationSettings):
(getPropertyValue):
(comparePropertyValue):

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/font-variation-settings-expected.html [new file with mode: 0644]
LayoutTests/animations/font-variation-settings-order-expected.html [new file with mode: 0644]
LayoutTests/animations/font-variation-settings-order.html [new file with mode: 0644]
LayoutTests/animations/font-variation-settings-unlike-expected.html [new file with mode: 0644]
LayoutTests/animations/font-variation-settings-unlike.html [new file with mode: 0644]
LayoutTests/animations/font-variation-settings.html [new file with mode: 0644]
LayoutTests/animations/resources/animation-test-helpers.js
Source/WebCore/ChangeLog
Source/WebCore/page/animation/CSSPropertyAnimation.cpp
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h

index 988c0b3..a2264dd 100644 (file)
@@ -1,3 +1,24 @@
+2016-09-30  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Implement animation of font-variation-settings
+        https://bugs.webkit.org/show_bug.cgi?id=162783
+
+        Reviewed by Simon Fraser.
+
+        Animation tests need a little infrastructure to be able to tell if two computed
+        values for font-variation-settings are equivalent.
+
+        * animations/font-variation-settings-expected.html: Added.
+        * animations/font-variation-settings-order-expected.html: Added.
+        * animations/font-variation-settings-order.html: Added.
+        * animations/font-variation-settings-unlike-expected.html: Added.
+        * animations/font-variation-settings-unlike.html: Added.
+        * animations/font-variation-settings.html: Added.
+        * animations/resources/animation-test-helpers.js:
+        (compareFontVariationSettings):
+        (getPropertyValue):
+        (comparePropertyValue):
+
 2016-09-30  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] layout nodes
diff --git a/LayoutTests/animations/font-variation-settings-expected.html b/LayoutTests/animations/font-variation-settings-expected.html
new file mode 100644 (file)
index 0000000..782e239
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+   window.internals.settings.setVariationFontsEnabled(true);
+</script>
+</head>
+<body>
+<div style="font: 100px 'Skia'; font-variation-settings: 'wght' 2.3">Hello</div>
+<div>PASS - "font-variation-settings" property for "box" element at 0.5s saw something close to: 'wght' 0.95<br>
+PASS - "font-variation-settings" property for "box" element at 1s saw something close to: 'wght' 1.4<br>
+PASS - "font-variation-settings" property for "box" element at 2s saw something close to: 'wght' 2.3</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/animations/font-variation-settings-order-expected.html b/LayoutTests/animations/font-variation-settings-order-expected.html
new file mode 100644 (file)
index 0000000..c2993d1
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+   window.internals.settings.setVariationFontsEnabled(true);
+</script>
+</head>
+<body>
+<div style="font: 100px 'Skia'; font-variation-settings: 'wght' 2.3, 'wdth' 1.1">Hello</div>
+<div>PASS - "font-variation-settings" property for "box" element at 0.5s saw something close to: 'wght' 0.95, 'wdth' 0.95<br>
+PASS - "font-variation-settings" property for "box" element at 1s saw something close to: 'wght' 1.4, 'wdth' 1<br>
+PASS - "font-variation-settings" property for "box" element at 2s saw something close to: 'wght' 2.3, 'wdth' 1.1</div>
+</body>
+</html>
diff --git a/LayoutTests/animations/font-variation-settings-order.html b/LayoutTests/animations/font-variation-settings-order.html
new file mode 100644 (file)
index 0000000..3e3b312
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+    window.internals.settings.setVariationFontsEnabled(true);
+</script>
+<script src="resources/animation-test-helpers.js"></script>
+<style>
+@keyframes "weightAnimation" {
+    from {
+        font-variation-settings: "wght" 0.5, "wdth" 0.9;
+    }
+    to {
+        font-variation-settings: "wdth" 1.2, "wght" 3.2;
+    }
+}
+
+#box {
+    font: 100px "Skia";
+    animation-name: "weightAnimation";
+    animation-duration: 3s;
+    animation-timing-function: linear;
+}
+</style>
+</head>
+<body>
+<div id="box">Hello</div>
+<div id="result"></div>
+<script>
+var expectedValues = [
+    // [animation-name, time, element-id, property, expected-value, tolerance]
+    ["weightAnimation", 0.5, "box", "font-variation-settings", "'wght' 0.95, 'wdth' 0.95", 0.05],
+    ["weightAnimation", 1.0, "box", "font-variation-settings", "'wght' 1.4, 'wdth' 1", 0.05],
+    ["weightAnimation", 2.0, "box", "font-variation-settings", "'wght' 2.3, 'wdth' 1.1", 0.05],
+];
+runAnimationTest(expectedValues, undefined, undefined, undefined, true, undefined);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/animations/font-variation-settings-unlike-expected.html b/LayoutTests/animations/font-variation-settings-unlike-expected.html
new file mode 100644 (file)
index 0000000..c29151a
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+   window.internals.settings.setVariationFontsEnabled(true);
+</script>
+</head>
+<body>
+<div style="font: 100px 'Skia';">Hello</div>
+<div>PASS - "font-variation-settings" property for "box" element at 0.5s saw something close to: normal<br>
+PASS - "font-variation-settings" property for "box" element at 1s saw something close to: normal<br>
+PASS - "font-variation-settings" property for "box" element at 2s saw something close to: normal</div>
+</body>
+</html>
diff --git a/LayoutTests/animations/font-variation-settings-unlike.html b/LayoutTests/animations/font-variation-settings-unlike.html
new file mode 100644 (file)
index 0000000..0c61046
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+    window.internals.settings.setVariationFontsEnabled(true);
+</script>
+<script src="resources/animation-test-helpers.js"></script>
+<style>
+@keyframes "weightAnimation" {
+    from {
+        font-variation-settings: "wght" 0.5, "wdth" 0.9;
+    }
+    to {
+        font-variation-settings: "wght" 3.2;
+    }
+}
+
+#box {
+    font: 100px "Skia";
+    animation-name: "weightAnimation";
+    animation-duration: 3s;
+    animation-timing-function: linear;
+}
+</style>
+</head>
+<body>
+<div id="box">Hello</div>
+<div id="result"></div>
+<script>
+var expectedValues = [
+    // [animation-name, time, element-id, property, expected-value, tolerance]
+    ["weightAnimation", 0.5, "box", "font-variation-settings", "normal", 0.05],
+    ["weightAnimation", 1.0, "box", "font-variation-settings", "normal", 0.05],
+    ["weightAnimation", 2.0, "box", "font-variation-settings", "normal", 0.05],
+];
+runAnimationTest(expectedValues, undefined, undefined, undefined, true, undefined);
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/animations/font-variation-settings.html b/LayoutTests/animations/font-variation-settings.html
new file mode 100644 (file)
index 0000000..0a7a29e
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.internals)
+    window.internals.settings.setVariationFontsEnabled(true);
+</script>
+<script>
+if (window.internals)
+    window.internals.settings.setVariationFontsEnabled(true);
+</script>
+<script src="resources/animation-test-helpers.js"></script>
+<style>
+@keyframes "weightAnimation" {
+    from {
+        font-variation-settings: "wght" 0.5;
+    }
+    to {
+        font-variation-settings: "wght" 3.2;
+    }
+}
+
+#box {
+    font: 100px "Skia";
+    animation-name: "weightAnimation";
+    animation-duration: 3s;
+    animation-timing-function: linear;
+}
+</style>
+</head>
+<body>
+<div id="box">Hello</div>
+<div id="result"></div>
+<script>
+var expectedValues = [
+    // [animation-name, time, element-id, property, expected-value, tolerance]
+    ["weightAnimation", 0.5, "box", "font-variation-settings", "'wght' 0.95", 0.05],
+    ["weightAnimation", 1.0, "box", "font-variation-settings", "'wght' 1.4", 0.05],
+    ["weightAnimation", 2.0, "box", "font-variation-settings", "'wght' 2.3", 0.05],
+];
+runAnimationTest(expectedValues, undefined, undefined, undefined, true, undefined);
+</script>
+</body>
+</html>
\ No newline at end of file
index 2041c70..743127f 100644 (file)
@@ -258,6 +258,29 @@ function compareCSSImages(computedValue, expectedValue, tolerance)
     }
 }
 
+function compareFontVariationSettings(computedValue, expectedValue, tolerance)
+{
+    if (computedValue == "normal" || expectedValue == "normal")
+        return computedValue == expectedValue;
+    var computed = computedValue.split(", ");
+    var expected = expectedValue.split(", ");
+    if (computed.length != expected.length)
+        return false;
+    for (var i = 0; i < computed.length; ++i) {
+        var computedPieces = computed[i].split(" ");
+        var expectedPieces = expected[i].split(" ");
+        if (computedPieces.length != 2 || expectedPieces.length != 2)
+            return false;
+        if (computedPieces[0] != expectedPieces[0])
+            return false;
+        var computedNumber = Number.parseFloat(computedPieces[1]);
+        var expectedNumber = Number.parseFloat(expectedPieces[1]);
+        if (Math.abs(computedNumber - expectedNumber) > tolerance)
+            return false;
+    }
+    return true;
+}
+
 // Called by CSS Image function filter() as well as filter property.
 function compareFilterFunctions(computedValue, expectedValue, tolerance)
 {
@@ -401,6 +424,7 @@ function getPropertyValue(property, elementId, iframeId)
                || property == "webkitClipPath"
                || property == "webkitShapeInside"
                || property == "webkitShapeOutside"
+               || property == "font-variation-settings"
                || !property.indexOf("webkitTransform")
                || !property.indexOf("transform")) {
         computedValue = window.getComputedStyle(element)[property.split(".")[0]];
@@ -446,9 +470,10 @@ function comparePropertyValue(property, computedValue, expectedValue, tolerance)
                || property == "webkitMaskImage"
                || property == "webkitMaskBoxImage")
         result = compareCSSImages(computedValue, expectedValue, tolerance);
-    else {
+    else if (property == "font-variation-settings")
+        result = compareFontVariationSettings(computedValue, expectedValue, tolerance);
+    else
         result = isCloseEnough(computedValue, expectedValue, tolerance);
-    }
     return result;
 }
 
index cd2708b..4a34cea 100644 (file)
@@ -1,3 +1,34 @@
+2016-09-30  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Implement animation of font-variation-settings
+        https://bugs.webkit.org/show_bug.cgi?id=162783
+
+        Reviewed by Simon Fraser.
+
+        Modify CSSPropertyAnimation to understand FontVariationSettings objects and how
+        to interpolate them.
+
+        If two FontVariationSettings objects are unlike (meaning they specify different
+        variation axes), for now the interpolation simply returns an empty object. This
+        might change in the future, but for now, this is a reasonable place to start.
+
+        Because CSSPropertyAnimation interacts with RenderStyles instead of
+        FontDescriptions, this patch adds a transparent accessor from the RenderStyle
+        to the inner FontDescription.
+
+        Tests: animations/font-variation-settings-order.html
+               animations/font-variation-settings-unlike.html
+               animations/font-variation-settings.html
+
+        * page/animation/CSSPropertyAnimation.cpp:
+        (WebCore::blendFunc):
+        (WebCore::PropertyWrapperFontVariationSettings::PropertyWrapperFontVariationSettings):
+        (WebCore::CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setFontVariationSettings):
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::fontVariationSettings):
+
 2016-09-30  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] layout nodes
index 2ff6eaf..0755c0d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2013, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@
 #include "CachedImage.h"
 #include "ClipPathOperation.h"
 #include "FloatConversion.h"
+#include "FontTaggedSettings.h"
 #include "IdentityTransformOperation.h"
 #include "Logging.h"
 #include "Matrix3DTransformOperation.h"
@@ -371,6 +372,23 @@ static inline NinePieceImage blendFunc(const AnimationBase* anim, const NinePiec
     return NinePieceImage(newContentImage, from.imageSlices(), from.fill(), from.borderSlices(), from.outset(), from.horizontalRule(), from.verticalRule());
 }
 
+static inline FontVariationSettings blendFunc(const AnimationBase* anim, const FontVariationSettings& from, const FontVariationSettings& to, double progress)
+{
+    if (from.size() != to.size())
+        return FontVariationSettings();
+    FontVariationSettings result;
+    unsigned size = from.size();
+    for (unsigned i = 0; i < size; ++i) {
+        auto& fromItem = from.at(i);
+        auto& toItem = to.at(i);
+        if (fromItem.tag() != toItem.tag())
+            return FontVariationSettings();
+        float interpolated = blendFunc(anim, fromItem.value(), toItem.value(), progress);
+        result.insert({ fromItem.tag(), interpolated });
+    }
+    return result;
+}
+
 class AnimationPropertyWrapperBase {
     WTF_MAKE_NONCOPYABLE(AnimationPropertyWrapperBase);
     WTF_MAKE_FAST_ALLOCATED;
@@ -517,6 +535,29 @@ public:
     }
 };
 
+class PropertyWrapperFontVariationSettings : public PropertyWrapper<FontVariationSettings> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    PropertyWrapperFontVariationSettings(CSSPropertyID prop, FontVariationSettings (RenderStyle::*getter)() const, void (RenderStyle::*setter)(FontVariationSettings))
+        : PropertyWrapper<FontVariationSettings>(prop, getter, setter)
+    {
+    }
+
+    bool equals(const RenderStyle* a, const RenderStyle* b) const override
+    {
+        // If the style pointers are the same, don't bother doing the test.
+        // If either is null, return false. If both are null, return true.
+        if (a == b)
+            return true;
+        if (!a || !b)
+            return false;
+
+        const FontVariationSettings& variationSettingsA = (a->*m_getter)();
+        const FontVariationSettings& variationSettingsB = (b->*m_getter)();
+        return variationSettingsA == variationSettingsB;
+    }
+};
+
 #if ENABLE(CSS_SHAPES)
 class PropertyWrapperShape : public RefCountedPropertyWrapper<ShapeValue> {
     WTF_MAKE_FAST_ALLOCATED;
@@ -1438,6 +1479,7 @@ CSSPropertyAnimationWrapperMap::CSSPropertyAnimationWrapperMap()
 
         new PropertyWrapper<SVGLength>(CSSPropertyBaselineShift, &RenderStyle::baselineShiftValue, &RenderStyle::setBaselineShiftValue),
         new PropertyWrapper<SVGLength>(CSSPropertyKerning, &RenderStyle::kerning, &RenderStyle::setKerning),
+        new PropertyWrapperFontVariationSettings(CSSPropertyFontVariationSettings, &RenderStyle::fontVariationSettings, &RenderStyle::setFontVariationSettings),
     };
     const unsigned animatableLonghandPropertiesCount = WTF_ARRAY_LENGTH(animatableLonghandPropertyWrappers);
 
index 8f5df60..94ec0ae 100644 (file)
@@ -1550,6 +1550,16 @@ void RenderStyle::setFontSize(float size)
     fontCascade().update(currentFontSelector);
 }
 
+void RenderStyle::setFontVariationSettings(FontVariationSettings settings)
+{
+    FontSelector* currentFontSelector = fontCascade().fontSelector();
+    auto description = fontDescription();
+    description.setVariationSettings(WTFMove(settings));
+
+    setFontDescription(description);
+    fontCascade().update(currentFontSelector);
+}
+
 void RenderStyle::getShadowExtent(const ShadowData* shadow, LayoutUnit &top, LayoutUnit &right, LayoutUnit &bottom, LayoutUnit &left) const
 {
     top = 0;
index 21dd5bb..ab96676 100644 (file)
@@ -719,6 +719,7 @@ public:
     float specifiedFontSize() const;
     float computedFontSize() const;
     int fontSize() const;
+    FontVariationSettings fontVariationSettings() const { return fontDescription().variationSettings(); }
     std::pair<FontOrientation, NonCJKGlyphOrientation> fontAndGlyphOrientation();
 
     const Length& textIndent() const { return rareInheritedData->indent; }
@@ -1367,6 +1368,7 @@ public:
     bool setFontDescription(const FontCascadeDescription&);
     // Only used for blending font sizes when animating, for MathML anonymous blocks, and for text autosizing.
     void setFontSize(float);
+    void setFontVariationSettings(FontVariationSettings);
 
     void setColor(const Color&);
     void setTextIndent(Length length) { SET_VAR(rareInheritedData, indent, WTFMove(length)); }