Parse font-display
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Aug 2017 00:03:56 +0000 (00:03 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 15 Aug 2017 00:03:56 +0000 (00:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175382

Reviewed by Simon Fraser.

Source/WebCore:

The syntax is very simple: font-display: auto | block | swap | fallback | optional.
So, parsing support is quite straightfoward.

Test: fast/text/font-display/parse.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::propertyValue):
* css/CSSFontFace.cpp:
(WebCore::CSSFontFace::setLoadingBehavior):
* css/CSSFontFace.h:
* css/CSSFontSelector.cpp:
(WebCore::CSSFontSelector::addFontFaceRule):
* css/CSSPrimitiveValueMappings.h:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
(WebCore::CSSPrimitiveValue::operator FontLoadingBehavior const):
* css/CSSProperties.json:
* css/CSSProperty.cpp:
(WebCore::CSSProperty::isDescriptorOnly):
* css/CSSValueKeywords.in:
* css/parser/CSSPropertyParser.cpp:
(WebCore::consumeFontFaceFontDisplay):
(WebCore::CSSPropertyParser::parseFontFaceDescriptor):
* rendering/style/RenderStyleConstants.h:

LayoutTests:

* fast/text/font-display/parse-expected.txt: Added.
* fast/text/font-display/parse.html: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/font-display/parse-expected.txt [new file with mode: 0644]
LayoutTests/fast/text/font-display/parse.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSFontFace.cpp
Source/WebCore/css/CSSFontFace.h
Source/WebCore/css/CSSFontSelector.cpp
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSProperties.json
Source/WebCore/css/CSSProperty.cpp
Source/WebCore/css/CSSValueKeywords.in
Source/WebCore/css/parser/CSSPropertyParser.cpp
Source/WebCore/rendering/style/RenderStyleConstants.h

index 27fe800..d4f35db 100644 (file)
@@ -1,3 +1,13 @@
+2017-08-14  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Parse font-display
+        https://bugs.webkit.org/show_bug.cgi?id=175382
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/font-display/parse-expected.txt: Added.
+        * fast/text/font-display/parse.html: Added.
+
 2017-08-14  Andy Estes  <aestes@apple.com>
 
         [Apple Pay] Add support for phonetic contact names
diff --git a/LayoutTests/fast/text/font-display/parse-expected.txt b/LayoutTests/fast/text/font-display/parse-expected.txt
new file mode 100644 (file)
index 0000000..3cdac8f
--- /dev/null
@@ -0,0 +1,19 @@
+This test makes sure that the font-display descriptor in @font-face is appropriately parsed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS sheet.rules[0].style.getPropertyValue('font-display') is ""
+PASS sheet.rules[1].style.getPropertyValue('font-display') is ""
+PASS sheet.rules[2].style.getPropertyValue('font-display') is ""
+PASS sheet.rules[3].style.getPropertyValue('font-display') is "auto"
+PASS sheet.rules[4].style.getPropertyValue('font-display') is "block"
+PASS sheet.rules[5].style.getPropertyValue('font-display') is "swap"
+PASS sheet.rules[6].style.getPropertyValue('font-display') is "fallback"
+PASS sheet.rules[7].style.getPropertyValue('font-display') is "optional"
+PASS sheet.rules[8].style.getPropertyValue('font-display') is ""
+PASS window.getComputedStyle(document.getElementById('test9')).getPropertyValue('font-display') is ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/text/font-display/parse.html b/LayoutTests/fast/text/font-display/parse.html
new file mode 100644 (file)
index 0000000..f658b96
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test-pre.js"></script>
+<style id="style">
+@font-face {
+    font-family: "Test0";
+    src: local("Times");
+    font-display: garbage;
+}
+@font-face {
+    font-family: "Test1";
+    src: local("Times");
+}
+@font-face {
+    font-family: "Test2";
+    src: local("Times");
+    font-display: block swap;
+}
+@font-face {
+    font-family: "Test3";
+    src: local("Times");
+    font-display: auto;
+}
+@font-face {
+    font-family: "Test4";
+    src: local("Times");
+    font-display: block;
+}
+@font-face {
+    font-family: "Test5";
+    src: local("Times");
+    font-display: swap;
+}
+@font-face {
+    font-family: "Test6";
+    src: local("Times");
+    font-display: fallback;
+}
+@font-face {
+    font-family: "Test7";
+    src: local("Times");
+    font-display: optional;
+}
+@font-face {
+    font-family: "Test8";
+    src: local("Times");
+    font-display: ;
+}
+</style>
+</head>
+<body>
+<div id="test9" style="font-display: block"></div>
+<script>
+description("This test makes sure that the font-display descriptor in @font-face is appropriately parsed.");
+
+var sheet = document.getElementById("style").sheet;
+shouldBeEqualToString("sheet.rules[0].style.getPropertyValue('font-display')", "");
+shouldBeEqualToString("sheet.rules[1].style.getPropertyValue('font-display')", "");
+shouldBeEqualToString("sheet.rules[2].style.getPropertyValue('font-display')", "");
+shouldBeEqualToString("sheet.rules[3].style.getPropertyValue('font-display')", "auto");
+shouldBeEqualToString("sheet.rules[4].style.getPropertyValue('font-display')", "block");
+shouldBeEqualToString("sheet.rules[5].style.getPropertyValue('font-display')", "swap");
+shouldBeEqualToString("sheet.rules[6].style.getPropertyValue('font-display')", "fallback");
+shouldBeEqualToString("sheet.rules[7].style.getPropertyValue('font-display')", "optional");
+shouldBeEqualToString("sheet.rules[8].style.getPropertyValue('font-display')", "");
+shouldBeEqualToString("window.getComputedStyle(document.getElementById('test9')).getPropertyValue('font-display')", "");
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
+</html>
index e4e19aa..31f907b 100644 (file)
@@ -1,3 +1,34 @@
+2017-08-14  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Parse font-display
+        https://bugs.webkit.org/show_bug.cgi?id=175382
+
+        Reviewed by Simon Fraser.
+
+        The syntax is very simple: font-display: auto | block | swap | fallback | optional.
+        So, parsing support is quite straightfoward.
+
+        Test: fast/text/font-display/parse.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::propertyValue):
+        * css/CSSFontFace.cpp:
+        (WebCore::CSSFontFace::setLoadingBehavior):
+        * css/CSSFontFace.h:
+        * css/CSSFontSelector.cpp:
+        (WebCore::CSSFontSelector::addFontFaceRule):
+        * css/CSSPrimitiveValueMappings.h:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        (WebCore::CSSPrimitiveValue::operator FontLoadingBehavior const):
+        * css/CSSProperties.json:
+        * css/CSSProperty.cpp:
+        (WebCore::CSSProperty::isDescriptorOnly):
+        * css/CSSValueKeywords.in:
+        * css/parser/CSSPropertyParser.cpp:
+        (WebCore::consumeFontFaceFontDisplay):
+        (WebCore::CSSPropertyParser::parseFontFaceDescriptor):
+        * rendering/style/RenderStyleConstants.h:
+
 2017-08-14  Jer Noble  <jer.noble@apple.com>
 
         Obj-C exception crash in AVStreamSession when using EME in Private Browsing mode
index 7104dbe..f34c5f7 100644 (file)
@@ -4018,6 +4018,7 @@ RefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propertyID,
         /* Unimplemented @font-face properties */
         case CSSPropertySrc:
         case CSSPropertyUnicodeRange:
+        case CSSPropertyFontDisplay:
             break;
 
         /* Other unimplemented properties */
index 4788fbb..50e94e8 100644 (file)
@@ -149,6 +149,9 @@ static FontSelectionRange calculateWeightRange(CSSValue& value)
 void CSSFontFace::setWeight(CSSValue& weight)
 {
     auto range = calculateWeightRange(weight);
+    if (m_fontSelectionCapabilities.weight == range)
+        return;
+
     setWeight(range);
 
     if (m_cssConnection)
@@ -184,6 +187,9 @@ static FontSelectionRange calculateStretchRange(CSSValue& value)
 void CSSFontFace::setStretch(CSSValue& style)
 {
     auto range = calculateStretchRange(style);
+    if (m_fontSelectionCapabilities.width == range)
+        return;
+
     setStretch(range);
 
     if (m_cssConnection)
@@ -229,6 +235,9 @@ static FontSelectionRange calculateItalicRange(CSSValue& value)
 void CSSFontFace::setStyle(CSSValue& style)
 {
     auto range = calculateItalicRange(style);
+    if (m_fontSelectionCapabilities.slope == range)
+        return;
+
     setStyle(range);
 
     if (m_cssConnection)
@@ -244,13 +253,27 @@ bool CSSFontFace::setUnicodeRange(CSSValue& unicodeRange)
     if (!is<CSSValueList>(unicodeRange))
         return false;
 
-    m_ranges.clear();
+    Vector<UnicodeRange> ranges;
     auto& list = downcast<CSSValueList>(unicodeRange);
     for (auto& rangeValue : list) {
         auto& range = downcast<CSSUnicodeRangeValue>(rangeValue.get());
-        m_ranges.append({ range.from(), range.to() });
+        ranges.append({ range.from(), range.to() });
+    }
+
+    if (ranges.size() == m_ranges.size()) {
+        bool same = true;
+        for (size_t i = 0; i < ranges.size(); ++i) {
+            if (ranges[i] != m_ranges[i]) {
+                same = false;
+                break;
+            }
+        }
+        if (same)
+            return true;
     }
 
+    m_ranges = WTFMove(ranges);
+
     if (m_cssConnection)
         m_cssConnection->mutableProperties().setProperty(CSSPropertyUnicodeRange, &unicodeRange);
 
@@ -265,6 +288,12 @@ bool CSSFontFace::setVariantLigatures(CSSValue& variantLigatures)
 {
     auto ligatures = extractFontVariantLigatures(variantLigatures);
 
+    if (m_variantSettings.commonLigatures == ligatures.commonLigatures
+        && m_variantSettings.discretionaryLigatures == ligatures.discretionaryLigatures
+        && m_variantSettings.historicalLigatures == ligatures.historicalLigatures
+        && m_variantSettings.contextualAlternates == ligatures.contextualAlternates)
+        return true;
+
     m_variantSettings.commonLigatures = ligatures.commonLigatures;
     m_variantSettings.discretionaryLigatures = ligatures.discretionaryLigatures;
     m_variantSettings.historicalLigatures = ligatures.historicalLigatures;
@@ -285,7 +314,12 @@ bool CSSFontFace::setVariantPosition(CSSValue& variantPosition)
     if (!is<CSSPrimitiveValue>(variantPosition))
         return false;
 
-    m_variantSettings.position = downcast<CSSPrimitiveValue>(variantPosition);
+    FontVariantPosition position = downcast<CSSPrimitiveValue>(variantPosition);
+
+    if (m_variantSettings.position == position)
+        return true;
+
+    m_variantSettings.position = position;
 
     if (m_cssConnection)
         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantPosition, &variantPosition);
@@ -302,7 +336,12 @@ bool CSSFontFace::setVariantCaps(CSSValue& variantCaps)
     if (!is<CSSPrimitiveValue>(variantCaps))
         return false;
 
-    m_variantSettings.caps = downcast<CSSPrimitiveValue>(variantCaps);
+    FontVariantCaps caps = downcast<CSSPrimitiveValue>(variantCaps);
+
+    if (m_variantSettings.caps == caps)
+        return true;
+
+    m_variantSettings.caps = caps;
 
     if (m_cssConnection)
         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantCaps, &variantCaps);
@@ -318,6 +357,13 @@ bool CSSFontFace::setVariantNumeric(CSSValue& variantNumeric)
 {
     auto numeric = extractFontVariantNumeric(variantNumeric);
 
+    if (m_variantSettings.numericFigure == numeric.figure
+        && m_variantSettings.numericSpacing == numeric.spacing
+        && m_variantSettings.numericFraction == numeric.fraction
+        && m_variantSettings.numericOrdinal == numeric.ordinal
+        && m_variantSettings.numericSlashedZero == numeric.slashedZero)
+        return true;
+
     m_variantSettings.numericFigure = numeric.figure;
     m_variantSettings.numericSpacing = numeric.spacing;
     m_variantSettings.numericFraction = numeric.fraction;
@@ -339,7 +385,12 @@ bool CSSFontFace::setVariantAlternates(CSSValue& variantAlternates)
     if (!is<CSSPrimitiveValue>(variantAlternates))
         return false;
 
-    m_variantSettings.alternates = downcast<CSSPrimitiveValue>(variantAlternates);
+    FontVariantAlternates alternates = downcast<CSSPrimitiveValue>(variantAlternates);
+
+    if (m_variantSettings.alternates == alternates)
+        return true;
+
+    m_variantSettings.alternates = alternates;
 
     if (m_cssConnection)
         m_cssConnection->mutableProperties().setProperty(CSSPropertyFontVariantAlternates, &variantAlternates);
@@ -355,6 +406,11 @@ bool CSSFontFace::setVariantEastAsian(CSSValue& variantEastAsian)
 {
     auto eastAsian = extractFontVariantEastAsian(variantEastAsian);
 
+    if (m_variantSettings.eastAsianVariant == eastAsian.variant
+        && m_variantSettings.eastAsianWidth == eastAsian.width
+        && m_variantSettings.eastAsianRuby == eastAsian.ruby)
+        return true;
+
     m_variantSettings.eastAsianVariant = eastAsian.variant;
     m_variantSettings.eastAsianWidth = eastAsian.width;
     m_variantSettings.eastAsianRuby = eastAsian.ruby;
@@ -397,6 +453,23 @@ void CSSFontFace::setFeatureSettings(CSSValue& featureSettings)
     });
 }
 
+void CSSFontFace::setLoadingBehavior(CSSValue& loadingBehaviorValue)
+{
+    auto loadingBehavior = static_cast<FontLoadingBehavior>(downcast<CSSPrimitiveValue>(loadingBehaviorValue).valueID());
+
+    if (m_loadingBehavior == loadingBehavior)
+        return;
+
+    m_loadingBehavior = loadingBehavior;
+
+    if (m_cssConnection)
+        m_cssConnection->mutableProperties().setProperty(CSSPropertyFontDisplay, &loadingBehaviorValue);
+
+    iterateClients(m_clients, [&](Client& client) {
+        client.fontPropertyChanged(*this);
+    });
+}
+
 bool CSSFontFace::rangesMatchCodePoint(UChar32 character) const
 {
     if (m_ranges.isEmpty())
index 3b42b10..d927949 100644 (file)
@@ -76,6 +76,7 @@ public:
     bool setVariantAlternates(CSSValue&);
     bool setVariantEastAsian(CSSValue&);
     void setFeatureSettings(CSSValue&);
+    void setLoadingBehavior(CSSValue&);
 
     enum class Status;
     struct UnicodeRange;
@@ -137,6 +138,8 @@ public:
     struct UnicodeRange {
         UChar32 from;
         UChar32 to;
+        bool operator==(const UnicodeRange& other) const { return from == other.from && to == other.to; }
+        bool operator!=(const UnicodeRange& other) const { return !(*this == other); }
     };
 
     bool rangesMatchCodePoint(UChar32) const;
@@ -179,6 +182,7 @@ private:
     HashSet<Client*> m_clients;
     WeakPtr<FontFace> m_wrapper;
     FontSelectionSpecifiedCapabilities m_fontSelectionCapabilities;
+    FontLoadingBehavior m_loadingBehavior { FontLoadingBehavior::Auto };
     Status m_status { Status::Pending };
     bool m_isLocalFallback { false };
     bool m_sourcesPopulated { false };
index 0b2e6ff..4a05e18 100644 (file)
@@ -157,6 +157,7 @@ void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isIn
     RefPtr<CSSValue> variantNumeric = style.getPropertyCSSValue(CSSPropertyFontVariantNumeric);
     RefPtr<CSSValue> variantAlternates = style.getPropertyCSSValue(CSSPropertyFontVariantAlternates);
     RefPtr<CSSValue> variantEastAsian = style.getPropertyCSSValue(CSSPropertyFontVariantEastAsian);
+    RefPtr<CSSValue> loadingBehavior = style.getPropertyCSSValue(CSSPropertyFontDisplay);
     if (!is<CSSValueList>(fontFamily.get()) || !is<CSSValueList>(src.get()) || (unicodeRange && !is<CSSValueList>(*unicodeRange)))
         return;
 
@@ -197,6 +198,8 @@ void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isIn
         return;
     if (featureSettings)
         fontFace->setFeatureSettings(*featureSettings);
+    if (loadingBehavior)
+        fontFace->setLoadingBehavior(*loadingBehavior);
 
     CSSFontFace::appendSources(fontFace, srcList, m_document, isInitiatingElementInUserAgentShadowTree);
     if (fontFace->allSourcesFailed())
index 647b855..a9d30e3 100644 (file)
@@ -5697,4 +5697,57 @@ template<> inline CSSPrimitiveValue::operator FontOpticalSizing() const
     return FontOpticalSizing::Enabled;
 }
 
+template<> inline CSSPrimitiveValue::CSSPrimitiveValue(FontLoadingBehavior behavior)
+    : CSSValue(PrimitiveClass)
+{
+    m_primitiveUnitType = CSS_VALUE_ID;
+    switch (behavior) {
+    case FontLoadingBehavior::Auto:
+        m_value.valueID = CSSValueAuto;
+        break;
+    case FontLoadingBehavior::Block:
+        m_value.valueID = CSSValueBlock;
+        break;
+    case FontLoadingBehavior::Swap:
+        m_value.valueID = CSSValueSwap;
+        break;
+    case FontLoadingBehavior::Fallback:
+        m_value.valueID = CSSValueFallback;
+        break;
+    case FontLoadingBehavior::Optional:
+        m_value.valueID = CSSValueOptional;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+template<> inline CSSPrimitiveValue::operator FontLoadingBehavior() const
+{
+    ASSERT(isValueID());
+    switch (m_value.valueID) {
+    case CSSValueAuto:
+        return FontLoadingBehavior::Auto;
+    case CSSValueBlock:
+        return FontLoadingBehavior::Block;
+    case CSSValueSwap:
+        return FontLoadingBehavior::Swap;
+    case CSSValueFallback:
+        return FontLoadingBehavior::Fallback;
+    case CSSValueOptional:
+        return FontLoadingBehavior::Optional;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return FontLoadingBehavior::Auto;
+}
+
+/*
+enum class FontLoadingBehavior {
+    Auto, Block, Swap, Fallback, Optional
+};
+*/
+
 }
index 717f265..d579452 100644 (file)
                 "enable-if": "ENABLE_VARIATION_FONTS"
             },
             "specification": {
-                "category": "css-fonts",
-                "url": "https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property"
+                "category": "css-fonts-4",
+                "url": "https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def"
             }
         },
         "-webkit-font-kerning": {
                 "enable-if": "ENABLE_VARIATION_FONTS"
             },
             "specification": {
-                "category": "css-fonts",
-                "url": "https://drafts.csswg.org/css-fonts-4/#optical-sizing-control-the-font-optical-sizing-property"
+                "category": "css-fonts-4",
+                "url": "https://drafts.csswg.org/css-fonts-4/#font-optical-sizing-def"
             }
         },
         "font": {
                 "url": "https://www.w3.org/TR/css-fonts-3/#descdef-unicode-range"
             }
         },
+        "font-display": {
+            "codegen-properties": {
+                "skip-builder": true
+            },
+            "specification": {
+                "category": "css-fonts-4",
+                "url": "https://drafts.csswg.org/css-fonts-4/#font-display-desc"
+            },
+            "values": [
+                "auto",
+                "block",
+                "swap",
+                "fallback",
+                "optional"
+            ]
+        },
         "vector-effect": {
             "values": [
                 "none",
             "longname": "CSS Fonts Module",
             "url": "https://www.w3.org/TR/css-fonts-3/"
         },
+        "css-fonts-4": {
+            "shortname": "CSS Fonts Level 4",
+            "longname": "CSS Fonts Module Level 4",
+            "url": "https://drafts.csswg.org/css-fonts-4"
+        },
         "css-grid": {
             "shortname": "CSS Grid Layout",
             "longname": "CSS Grid Layout Module",
index 8a91a39..322f754 100644 (file)
@@ -164,6 +164,7 @@ bool CSSProperty::isDescriptorOnly(CSSPropertyID propertyID)
 #endif
     case CSSPropertySrc:
     case CSSPropertyUnicodeRange:
+    case CSSPropertyFontDisplay:
         return true;
     default:
         return false;
index 15cfb0f..cff8609 100644 (file)
@@ -1347,3 +1347,10 @@ no-preference
 // auto-repeat
 auto-fill
 auto-fit
+
+// font-display
+// auto
+// block
+swap
+fallback
+optional
index 7df81a2..40267b0 100644 (file)
@@ -4304,6 +4304,11 @@ static RefPtr<CSSValueList> consumeFontFaceUnicodeRange(CSSParserTokenRange& ran
     return values;
 }
 
+static RefPtr<CSSPrimitiveValue> consumeFontFaceFontDisplay(CSSParserTokenRange& range)
+{
+    return consumeIdent<CSSValueAuto, CSSValueBlock, CSSValueSwap, CSSValueFallback, CSSValueOptional>(range);
+}
+
 static RefPtr<CSSValue> consumeFontFaceSrcURI(CSSParserTokenRange& range, const CSSParserContext& context)
 {
     String url = consumeUrlAsStringView(range).toString();
@@ -4377,6 +4382,9 @@ bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
     case CSSPropertyUnicodeRange:
         parsedValue = consumeFontFaceUnicodeRange(m_range);
         break;
+    case CSSPropertyFontDisplay:
+        parsedValue = consumeFontFaceFontDisplay(m_range);
+        break;
     case CSSPropertyFontWeight:
 #if ENABLE(VARIATION_FONTS)
         parsedValue = consumeFontWeightRange(m_range);
index 237a2d8..d21b80c 100644 (file)
@@ -753,6 +753,10 @@ enum class PaintType {
     Markers
 };
 
+enum class FontLoadingBehavior {
+    Auto, Block, Swap, Fallback, Optional
+};
+
 extern const float defaultMiterLimit;
 
 } // namespace WebCore