Changeset 213528 in webkit


Ignore:
Timestamp:
Mar 7, 2017 11:26:21 AM (7 years ago)
Author:
mmaxfield@apple.com
Message:

Parsing font descriptors inside @font-face needs to accept ranges
https://bugs.webkit.org/show_bug.cgi?id=168893

Reviewed by Dean Jackson.

Source/WebCore:

Parse font-weight, font-stretch, and font-style ranges according to
https://drafts.csswg.org/css-fonts-4/#font-prop-desc. There is one difference, though:
as documented in https://github.com/w3c/csswg-drafts/issues/783, slashes are a better
delimiters than hyphens, so this patch implements that instead. I'll update the spec to
include slashes as soon as possible.

Because this patch is all about creating FontSelectionValues from fonts, it doesn't
actually modify the font selection algorithm, and therefore only tests the creation of
these new values. The font selection algorithm itself is already tested elsewhere.

This new work is behind the ENABLE(VARIATION_FONTS) flag.

Test: fast/text/font-selection-font-face-parse.html

  • css/CSSFontFace.cpp:

(WebCore::calculateWeightRange):
(WebCore::calculateStretchRange):
(WebCore::calculateItalicRange):

  • css/parser/CSSPropertyParser.cpp:

(WebCore::consumeFontWeightRange):
(WebCore::consumeFontStretchRange):
(WebCore::consumeFontStyleRange):
(WebCore::CSSPropertyParser::parseFontFaceDescriptor):

  • platform/graphics/cocoa/FontCacheCoreText.cpp:

(WebCore::extractVariationBounds):
(WebCore::variationCapabilitiesForFontDescriptor):
(WebCore::capabilitiesForFontDescriptor):

LayoutTests:

  • fast/text/font-selection-font-face-parse-expected.txt:
  • fast/text/font-selection-font-face-parse.html:
  • platform/mac-elcapitan/fast/text/font-selection-font-face-parse-expected.txt:

Variations are off on El Capitan, so this platform needs explicit results.

Location:
trunk
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r213526 r213528  
     12017-03-07  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Parsing font descriptors inside @font-face needs to accept ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=168893
     5
     6        Reviewed by Dean Jackson.
     7
     8        * fast/text/font-selection-font-face-parse-expected.txt:
     9        * fast/text/font-selection-font-face-parse.html:
     10        * platform/mac-elcapitan/fast/text/font-selection-font-face-parse-expected.txt:
     11        Variations are off on El Capitan, so this platform needs explicit results.
     12
    1132017-03-07  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    214
  • trunk/LayoutTests/fast/text/font-selection-font-face-parse-expected.txt

    r213464 r213528  
    1717PASS weightTestSheet.cssRules[16].style.fontWeight is "300"
    1818PASS weightTestSheet.cssRules[17].style.fontWeight is "200"
     19PASS weightTestSheet.cssRules[18].style.fontWeight is "100 / 200"
     20PASS weightTestSheet.cssRules[19].style.fontWeight is "100 / 200"
     21PASS weightTestSheet.cssRules[20].style.fontWeight is ""
     22PASS weightTestSheet.cssRules[21].style.fontWeight is ""
     23PASS weightTestSheet.cssRules[22].style.fontWeight is ""
     24PASS weightTestSheet.cssRules[23].style.fontWeight is ""
     25PASS weightTestSheet.cssRules[24].style.fontWeight is ""
     26PASS weightTestSheet.cssRules[25].style.fontWeight is ""
     27PASS weightTestSheet.cssRules[26].style.fontWeight is "1 / 2"
     28PASS weightTestSheet.cssRules[27].style.fontWeight is "-2 / -1"
     29PASS weightTestSheet.cssRules[28].style.fontWeight is ""
     30PASS weightTestSheet.cssRules[29].style.fontWeight is "7 / 8"
     31PASS weightTestSheet.cssRules[30].style.fontWeight is "2 / 7"
    1932PASS stretchTestSheet.cssRules[0].style.fontStretch is "1%"
    2033PASS stretchTestSheet.cssRules[1].style.fontStretch is "2"
     
    3144PASS stretchTestSheet.cssRules[12].style.fontStretch is ""
    3245PASS stretchTestSheet.cssRules[13].style.fontStretch is "7"
     46PASS stretchTestSheet.cssRules[14].style.fontStretch is "100 / 200"
     47PASS stretchTestSheet.cssRules[15].style.fontStretch is "100 / 200"
     48PASS stretchTestSheet.cssRules[16].style.fontStretch is ""
     49PASS stretchTestSheet.cssRules[17].style.fontStretch is ""
     50PASS stretchTestSheet.cssRules[18].style.fontStretch is ""
     51PASS stretchTestSheet.cssRules[19].style.fontStretch is ""
     52PASS stretchTestSheet.cssRules[20].style.fontStretch is ""
     53PASS stretchTestSheet.cssRules[21].style.fontStretch is ""
     54PASS stretchTestSheet.cssRules[22].style.fontStretch is "1 / 2"
     55PASS stretchTestSheet.cssRules[23].style.fontStretch is "-2 / -1"
     56PASS stretchTestSheet.cssRules[24].style.fontStretch is ""
     57PASS stretchTestSheet.cssRules[25].style.fontStretch is "100% / 200%"
     58PASS stretchTestSheet.cssRules[26].style.fontStretch is "100% / 200%"
     59PASS stretchTestSheet.cssRules[27].style.fontStretch is ""
     60PASS stretchTestSheet.cssRules[28].style.fontStretch is ""
     61PASS stretchTestSheet.cssRules[29].style.fontStretch is ""
     62PASS stretchTestSheet.cssRules[30].style.fontStretch is ""
     63PASS stretchTestSheet.cssRules[31].style.fontStretch is ""
     64PASS stretchTestSheet.cssRules[32].style.fontStretch is ""
     65PASS stretchTestSheet.cssRules[33].style.fontStretch is "1% / 2%"
     66PASS stretchTestSheet.cssRules[34].style.fontStretch is "-2% / -1%"
     67PASS stretchTestSheet.cssRules[35].style.fontStretch is ""
     68PASS stretchTestSheet.cssRules[36].style.fontStretch is ""
     69PASS stretchTestSheet.cssRules[37].style.fontStretch is ""
     70PASS stretchTestSheet.cssRules[38].style.fontStretch is "7 / 8"
     71PASS stretchTestSheet.cssRules[39].style.fontStretch is "2 / 7"
    3372PASS styleTestSheet.cssRules[0].style.fontStyle is "1deg"
    3473PASS styleTestSheet.cssRules[1].style.fontStyle is "200grad"
     
    4483PASS styleTestSheet.cssRules[11].style.fontStyle is "7"
    4584PASS styleTestSheet.cssRules[12].style.fontStyle is "calc(1441deg)"
     85PASS styleTestSheet.cssRules[13].style.fontStyle is "100 / 200"
     86PASS styleTestSheet.cssRules[14].style.fontStyle is "100 / 200"
     87PASS styleTestSheet.cssRules[15].style.fontStyle is ""
     88PASS styleTestSheet.cssRules[16].style.fontStyle is ""
     89PASS styleTestSheet.cssRules[17].style.fontStyle is ""
     90PASS styleTestSheet.cssRules[18].style.fontStyle is ""
     91PASS styleTestSheet.cssRules[19].style.fontStyle is ""
     92PASS styleTestSheet.cssRules[20].style.fontStyle is ""
     93PASS styleTestSheet.cssRules[21].style.fontStyle is "1 / 2"
     94PASS styleTestSheet.cssRules[22].style.fontStyle is "-2 / -1"
     95PASS styleTestSheet.cssRules[23].style.fontStyle is ""
     96PASS styleTestSheet.cssRules[24].style.fontStyle is "100deg / 200deg"
     97PASS styleTestSheet.cssRules[25].style.fontStyle is "100deg / 200deg"
     98PASS styleTestSheet.cssRules[26].style.fontStyle is ""
     99PASS styleTestSheet.cssRules[27].style.fontStyle is ""
     100PASS styleTestSheet.cssRules[28].style.fontStyle is ""
     101PASS styleTestSheet.cssRules[29].style.fontStyle is ""
     102PASS styleTestSheet.cssRules[30].style.fontStyle is ""
     103PASS styleTestSheet.cssRules[31].style.fontStyle is ""
     104PASS styleTestSheet.cssRules[32].style.fontStyle is "1deg / 2deg"
     105PASS styleTestSheet.cssRules[33].style.fontStyle is "-2deg / -1deg"
     106PASS styleTestSheet.cssRules[34].style.fontStyle is ""
     107PASS styleTestSheet.cssRules[35].style.fontStyle is ""
     108PASS styleTestSheet.cssRules[36].style.fontStyle is ""
     109PASS styleTestSheet.cssRules[37].style.fontStyle is "2deg / 1turn"
     110PASS styleTestSheet.cssRules[38].style.fontStyle is "7 / 8"
     111PASS styleTestSheet.cssRules[39].style.fontStyle is "2 / 7"
    46112PASS successfullyParsed is true
    47113
  • trunk/LayoutTests/fast/text/font-selection-font-face-parse.html

    r213464 r213528  
    5757    font-weight: calc(150 + 50);
    5858}
     59@font-face {
     60    font-weight: 100/200;
     61}
     62@font-face {
     63    font-weight: 100 / 200;
     64}
     65@font-face {
     66    font-weight: a 100 / 200;
     67}
     68@font-face {
     69    font-weight: 100 / 200 a;
     70}
     71@font-face {
     72    font-weight: 100 a / 200;
     73}
     74@font-face {
     75    font-weight: 100 a/ 200;
     76}
     77@font-face {
     78    font-weight: 100 /a 200;
     79}
     80@font-face {
     81    font-weight: 100 / a200;
     82}
     83@font-face {
     84    font-weight: 1 / 2;
     85}
     86@font-face {
     87    font-weight: -2 / -1;
     88}
     89@font-face {
     90    font-weight: 2 / 1;
     91}
     92@font-face {
     93    font-weight: calc(3 + 4) / 8;
     94}
     95@font-face {
     96    font-weight: 2 / calc(3 + 4);
     97}
    5998</style>
    6099
     
    102141    font-stretch: calc(3 + 4);
    103142}
     143@font-face {
     144    font-stretch: 100/200;
     145}
     146@font-face {
     147    font-stretch: 100 / 200;
     148}
     149@font-face {
     150    font-stretch: a 100 / 200;
     151}
     152@font-face {
     153    font-stretch: 100 / 200 a;
     154}
     155@font-face {
     156    font-stretch: 100 a / 200;
     157}
     158@font-face {
     159    font-stretch: 100 a/ 200;
     160}
     161@font-face {
     162    font-stretch: 100 /a 200;
     163}
     164@font-face {
     165    font-stretch: 100 / a200;
     166}
     167@font-face {
     168    font-stretch: 1 / 2;
     169}
     170@font-face {
     171    font-stretch: -2 / -1;
     172}
     173@font-face {
     174    font-stretch: 2 / 1;
     175}
     176@font-face {
     177    font-stretch: 100%/200%;
     178}
     179@font-face {
     180    font-stretch: 100% / 200%;
     181}
     182@font-face {
     183    font-stretch: a 100% / 200%;
     184}
     185@font-face {
     186    font-stretch: 100% / 200% a;
     187}
     188@font-face {
     189    font-stretch: 100% a / 200%;
     190}
     191@font-face {
     192    font-stretch: 100% a/ 200%;
     193}
     194@font-face {
     195    font-stretch: 100% /a 200%;
     196}
     197@font-face {
     198    font-stretch: 100% / a200%;
     199}
     200@font-face {
     201    font-stretch: 1% / 2%;
     202}
     203@font-face {
     204    font-stretch: -2% / -1%;
     205}
     206@font-face {
     207    font-stretch: 2% / 1%;
     208}
     209@font-face {
     210    font-stretch: 1 / 2%;
     211}
     212@font-face {
     213    font-stretch: 1% / 2;
     214}
     215@font-face {
     216    font-stretch: calc(3 + 4) / 8;
     217}
     218@font-face {
     219    font-stretch: 2 / calc(3 + 4);
     220}
    104221</style>
    105222
     
    143260@font-face {
    144261    font-style: oblique calc(4turn + 1deg);
     262}
     263@font-face {
     264    font-style: oblique 100/200;
     265}
     266@font-face {
     267    font-style: oblique 100 / 200;
     268}
     269@font-face {
     270    font-style: oblique a 100 / 200;
     271}
     272@font-face {
     273    font-style: oblique 100 / 200 a;
     274}
     275@font-face {
     276    font-style: oblique 100 a / 200;
     277}
     278@font-face {
     279    font-style: oblique 100 a/ 200;
     280}
     281@font-face {
     282    font-style: oblique 100 /a 200;
     283}
     284@font-face {
     285    font-style: oblique 100 / a200;
     286}
     287@font-face {
     288    font-style: oblique 1 / 2;
     289}
     290@font-face {
     291    font-style: oblique -2 / -1;
     292}
     293@font-face {
     294    font-style: oblique 2 / 1;
     295}
     296@font-face {
     297    font-style: oblique 100deg/200deg;
     298}
     299@font-face {
     300    font-style: oblique 100deg / 200deg;
     301}
     302@font-face {
     303    font-style: oblique a 100deg / 200deg;
     304}
     305@font-face {
     306    font-style: oblique 100deg / 200deg a;
     307}
     308@font-face {
     309    font-style: oblique 100deg a / 200deg;
     310}
     311@font-face {
     312    font-style: oblique 100deg a/ 200deg;
     313}
     314@font-face {
     315    font-style: oblique 100deg /a 200deg;
     316}
     317@font-face {
     318    font-style: oblique 100deg / a200deg;
     319}
     320@font-face {
     321    font-style: oblique 1deg / 2deg;
     322}
     323@font-face {
     324    font-style: oblique -2deg / -1deg;
     325}
     326@font-face {
     327    font-style: oblique 2deg / 1deg;
     328}
     329@font-face {
     330    font-style: oblique 1 / 2deg;
     331}
     332@font-face {
     333    font-style: oblique 1deg / 2;
     334}
     335@font-face {
     336    font-style: oblique 2deg / 1turn;
     337}
     338@font-face {
     339    font-style: oblique calc(3 + 4) / 8;
     340}
     341@font-face {
     342    font-style: oblique 2 / calc(3 + 4);
    145343}
    146344</style>
     
    167365shouldBeEqualToString("weightTestSheet.cssRules[16].style.fontWeight", "300");
    168366shouldBeEqualToString("weightTestSheet.cssRules[17].style.fontWeight", "200");
     367shouldBeEqualToString("weightTestSheet.cssRules[18].style.fontWeight", "100 / 200");
     368shouldBeEqualToString("weightTestSheet.cssRules[19].style.fontWeight", "100 / 200");
     369shouldBeEqualToString("weightTestSheet.cssRules[20].style.fontWeight", "");
     370shouldBeEqualToString("weightTestSheet.cssRules[21].style.fontWeight", "");
     371shouldBeEqualToString("weightTestSheet.cssRules[22].style.fontWeight", "");
     372shouldBeEqualToString("weightTestSheet.cssRules[23].style.fontWeight", "");
     373shouldBeEqualToString("weightTestSheet.cssRules[24].style.fontWeight", "");
     374shouldBeEqualToString("weightTestSheet.cssRules[25].style.fontWeight", "");
     375shouldBeEqualToString("weightTestSheet.cssRules[26].style.fontWeight", "1 / 2");
     376shouldBeEqualToString("weightTestSheet.cssRules[27].style.fontWeight", "-2 / -1");
     377shouldBeEqualToString("weightTestSheet.cssRules[28].style.fontWeight", "");
     378shouldBeEqualToString("weightTestSheet.cssRules[29].style.fontWeight", "7 / 8");
     379shouldBeEqualToString("weightTestSheet.cssRules[30].style.fontWeight", "2 / 7");
    169380
    170381var stretchTestSheet = document.getElementById("stretchTest").sheet;
     
    183394shouldBeEqualToString("stretchTestSheet.cssRules[12].style.fontStretch", "");
    184395shouldBeEqualToString("stretchTestSheet.cssRules[13].style.fontStretch", "7");
     396shouldBeEqualToString("stretchTestSheet.cssRules[14].style.fontStretch", "100 / 200");
     397shouldBeEqualToString("stretchTestSheet.cssRules[15].style.fontStretch", "100 / 200");
     398shouldBeEqualToString("stretchTestSheet.cssRules[16].style.fontStretch", "");
     399shouldBeEqualToString("stretchTestSheet.cssRules[17].style.fontStretch", "");
     400shouldBeEqualToString("stretchTestSheet.cssRules[18].style.fontStretch", "");
     401shouldBeEqualToString("stretchTestSheet.cssRules[19].style.fontStretch", "");
     402shouldBeEqualToString("stretchTestSheet.cssRules[20].style.fontStretch", "");
     403shouldBeEqualToString("stretchTestSheet.cssRules[21].style.fontStretch", "");
     404shouldBeEqualToString("stretchTestSheet.cssRules[22].style.fontStretch", "1 / 2");
     405shouldBeEqualToString("stretchTestSheet.cssRules[23].style.fontStretch", "-2 / -1");
     406shouldBeEqualToString("stretchTestSheet.cssRules[24].style.fontStretch", "");
     407shouldBeEqualToString("stretchTestSheet.cssRules[25].style.fontStretch", "100% / 200%");
     408shouldBeEqualToString("stretchTestSheet.cssRules[26].style.fontStretch", "100% / 200%");
     409shouldBeEqualToString("stretchTestSheet.cssRules[27].style.fontStretch", "");
     410shouldBeEqualToString("stretchTestSheet.cssRules[28].style.fontStretch", "");
     411shouldBeEqualToString("stretchTestSheet.cssRules[29].style.fontStretch", "");
     412shouldBeEqualToString("stretchTestSheet.cssRules[30].style.fontStretch", "");
     413shouldBeEqualToString("stretchTestSheet.cssRules[31].style.fontStretch", "");
     414shouldBeEqualToString("stretchTestSheet.cssRules[32].style.fontStretch", "");
     415shouldBeEqualToString("stretchTestSheet.cssRules[33].style.fontStretch", "1% / 2%");
     416shouldBeEqualToString("stretchTestSheet.cssRules[34].style.fontStretch", "-2% / -1%");
     417shouldBeEqualToString("stretchTestSheet.cssRules[35].style.fontStretch", "");
     418shouldBeEqualToString("stretchTestSheet.cssRules[36].style.fontStretch", "");
     419shouldBeEqualToString("stretchTestSheet.cssRules[37].style.fontStretch", "");
     420shouldBeEqualToString("stretchTestSheet.cssRules[38].style.fontStretch", "7 / 8");
     421shouldBeEqualToString("stretchTestSheet.cssRules[39].style.fontStretch", "2 / 7");
    185422
    186423var styleTestSheet = document.getElementById("styleTest").sheet;
     
    198435shouldBeEqualToString("styleTestSheet.cssRules[11].style.fontStyle", "7");
    199436shouldBeEqualToString("styleTestSheet.cssRules[12].style.fontStyle", "calc(1441deg)");
     437
     438shouldBeEqualToString("styleTestSheet.cssRules[13].style.fontStyle", "100 / 200");
     439shouldBeEqualToString("styleTestSheet.cssRules[14].style.fontStyle", "100 / 200");
     440shouldBeEqualToString("styleTestSheet.cssRules[15].style.fontStyle", "");
     441shouldBeEqualToString("styleTestSheet.cssRules[16].style.fontStyle", "");
     442shouldBeEqualToString("styleTestSheet.cssRules[17].style.fontStyle", "");
     443shouldBeEqualToString("styleTestSheet.cssRules[18].style.fontStyle", "");
     444shouldBeEqualToString("styleTestSheet.cssRules[19].style.fontStyle", "");
     445shouldBeEqualToString("styleTestSheet.cssRules[20].style.fontStyle", "");
     446shouldBeEqualToString("styleTestSheet.cssRules[21].style.fontStyle", "1 / 2");
     447shouldBeEqualToString("styleTestSheet.cssRules[22].style.fontStyle", "-2 / -1");
     448shouldBeEqualToString("styleTestSheet.cssRules[23].style.fontStyle", "");
     449shouldBeEqualToString("styleTestSheet.cssRules[24].style.fontStyle", "100deg / 200deg");
     450shouldBeEqualToString("styleTestSheet.cssRules[25].style.fontStyle", "100deg / 200deg");
     451shouldBeEqualToString("styleTestSheet.cssRules[26].style.fontStyle", "");
     452shouldBeEqualToString("styleTestSheet.cssRules[27].style.fontStyle", "");
     453shouldBeEqualToString("styleTestSheet.cssRules[28].style.fontStyle", "");
     454shouldBeEqualToString("styleTestSheet.cssRules[29].style.fontStyle", "");
     455shouldBeEqualToString("styleTestSheet.cssRules[30].style.fontStyle", "");
     456shouldBeEqualToString("styleTestSheet.cssRules[31].style.fontStyle", "");
     457shouldBeEqualToString("styleTestSheet.cssRules[32].style.fontStyle", "1deg / 2deg");
     458shouldBeEqualToString("styleTestSheet.cssRules[33].style.fontStyle", "-2deg / -1deg");
     459shouldBeEqualToString("styleTestSheet.cssRules[34].style.fontStyle", "");
     460shouldBeEqualToString("styleTestSheet.cssRules[35].style.fontStyle", "");
     461shouldBeEqualToString("styleTestSheet.cssRules[36].style.fontStyle", "");
     462shouldBeEqualToString("styleTestSheet.cssRules[37].style.fontStyle", "2deg / 1turn");
     463shouldBeEqualToString("styleTestSheet.cssRules[38].style.fontStyle", "7 / 8");
     464shouldBeEqualToString("styleTestSheet.cssRules[39].style.fontStyle", "2 / 7");
    200465</script>
    201466<script src="../../resources/js-test-post.js"></script>
  • trunk/Source/WebCore/ChangeLog

    r213523 r213528  
     12017-03-07  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Parsing font descriptors inside @font-face needs to accept ranges
     4        https://bugs.webkit.org/show_bug.cgi?id=168893
     5
     6        Reviewed by Dean Jackson.
     7
     8        Parse font-weight, font-stretch, and font-style ranges according to
     9        https://drafts.csswg.org/css-fonts-4/#font-prop-desc. There is one difference, though:
     10        as documented in https://github.com/w3c/csswg-drafts/issues/783, slashes are a better
     11        delimiters than hyphens, so this patch implements that instead. I'll update the spec to
     12        include slashes as soon as possible.
     13
     14        Because this patch is all about creating FontSelectionValues from fonts, it doesn't
     15        actually modify the font selection algorithm, and therefore only tests the creation of
     16        these new values. The font selection algorithm itself is already tested elsewhere.
     17
     18        This new work is behind the ENABLE(VARIATION_FONTS) flag.
     19
     20        Test: fast/text/font-selection-font-face-parse.html
     21
     22        * css/CSSFontFace.cpp:
     23        (WebCore::calculateWeightRange):
     24        (WebCore::calculateStretchRange):
     25        (WebCore::calculateItalicRange):
     26        * css/parser/CSSPropertyParser.cpp:
     27        (WebCore::consumeFontWeightRange):
     28        (WebCore::consumeFontStretchRange):
     29        (WebCore::consumeFontStyleRange):
     30        (WebCore::CSSPropertyParser::parseFontFaceDescriptor):
     31        * platform/graphics/cocoa/FontCacheCoreText.cpp:
     32        (WebCore::extractVariationBounds):
     33        (WebCore::variationCapabilitiesForFontDescriptor):
     34        (WebCore::capabilitiesForFontDescriptor):
     35
    1362017-03-07  Dave Hyatt  <hyatt@apple.com>
    237
  • trunk/Source/WebCore/css/CSSFontFace.cpp

    r213464 r213528  
    127127static FontSelectionRange calculateWeightRange(CSSValue& value)
    128128{
    129     // FIXME: Parse range-based values.
     129    if (value.isValueList()) {
     130        auto& valueList = downcast<CSSValueList>(value);
     131        ASSERT(valueList.length() == 2);
     132        if (valueList.length() != 2)
     133            return { normalWeightValue(), normalWeightValue() };
     134        ASSERT(valueList.item(0)->isPrimitiveValue());
     135        ASSERT(valueList.item(1)->isPrimitiveValue());
     136        auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
     137        auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
     138        ASSERT(value0.isNumber());
     139        ASSERT(value1.isNumber());
     140        return { FontSelectionValue::clampFloat(value0.floatValue()), FontSelectionValue::clampFloat(value1.floatValue()) };
     141    }
     142
    130143    ASSERT(is<CSSPrimitiveValue>(value));
    131144    auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
     
    163176static FontSelectionRange calculateStretchRange(CSSValue& value)
    164177{
    165     // FIXME: Parse range-based values.
     178    if (value.isValueList()) {
     179        auto& valueList = downcast<CSSValueList>(value);
     180        ASSERT(valueList.length() == 2);
     181        if (valueList.length() != 2)
     182            return { normalStretchValue(), normalStretchValue() };
     183        ASSERT(valueList.item(0)->isPrimitiveValue());
     184        ASSERT(valueList.item(1)->isPrimitiveValue());
     185        auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
     186        auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
     187        ASSERT(value0.isPercentage() || value0.isNumber());
     188        ASSERT(value1.isPercentage() || value1.isNumber());
     189        return { FontSelectionValue::clampFloat(value0.floatValue()), FontSelectionValue::clampFloat(value1.floatValue()) };
     190    }
     191
    166192    ASSERT(is<CSSPrimitiveValue>(value));
    167193    const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
     
    199225static FontSelectionRange calculateItalicRange(CSSValue& value)
    200226{
    201     // FIXME: Parse range-based values.
     227    if (value.isValueList()) {
     228        auto& valueList = downcast<CSSValueList>(value);
     229        ASSERT(valueList.length() == 2);
     230        if (valueList.length() != 2)
     231            return { normalItalicValue(), normalItalicValue() };
     232        ASSERT(valueList.item(0)->isPrimitiveValue());
     233        ASSERT(valueList.item(1)->isPrimitiveValue());
     234        auto& value0 = downcast<CSSPrimitiveValue>(*valueList.item(0));
     235        auto& value1 = downcast<CSSPrimitiveValue>(*valueList.item(1));
     236        ASSERT(value0.isAngle() || value0.isNumber() || value0.isCalculated());
     237        ASSERT(value1.isAngle() || value1.isNumber() || value1.isCalculated());
     238        return { FontSelectionValue::clampFloat(value0.floatValue(CSSPrimitiveValue::CSS_DEG)), FontSelectionValue::clampFloat(value1.floatValue(CSSPrimitiveValue::CSS_DEG)) };
     239    }
     240
    202241    ASSERT(is<CSSPrimitiveValue>(value));
    203242    const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
  • trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp

    r213464 r213528  
    889889}
    890890
     891#if ENABLE(VARIATION_FONTS)
     892static RefPtr<CSSValue> consumeFontWeightRange(CSSParserTokenRange& range)
     893{
     894    if (auto result = consumeFontWeightKeywordValue(range))
     895        return result;
     896    auto firstNumber = consumeNumber(range, ValueRangeAll);
     897    if (!firstNumber)
     898        return nullptr;
     899    if (range.atEnd())
     900        return firstNumber;
     901    if (!consumeSlashIncludingWhitespace(range))
     902        return nullptr;
     903    auto secondNumber = consumeNumber(range, ValueRangeAll);
     904    if (!secondNumber)
     905        return nullptr;
     906    if (firstNumber->floatValue() > secondNumber->floatValue())
     907        return nullptr;
     908    auto result = CSSValueList::createSlashSeparated();
     909    result->append(firstNumber.releaseNonNull());
     910    result->append(secondNumber.releaseNonNull());
     911    return RefPtr<CSSValue>(WTFMove(result));
     912}
     913#endif
     914
    891915static RefPtr<CSSPrimitiveValue> consumeFontStretchKeywordValue(CSSParserTokenRange& range)
    892916{
     
    902926    return consumeNumber(range, ValueRangeAll);
    903927}
     928
     929#if ENABLE(VARIATION_FONTS)
     930static RefPtr<CSSValue> consumeFontStretchRange(CSSParserTokenRange& range)
     931{
     932    if (auto result = consumeFontStretchKeywordValue(range))
     933        return result;
     934    if (auto firstPercent = consumePercent(range, ValueRangeAll)) {
     935        if (range.atEnd())
     936            return firstPercent;
     937        if (!consumeSlashIncludingWhitespace(range))
     938            return nullptr;
     939        auto secondPercent = consumePercent(range, ValueRangeAll);
     940        if (!secondPercent)
     941            return nullptr;
     942        if (firstPercent->floatValue() > secondPercent->floatValue())
     943            return nullptr;
     944        auto result = CSSValueList::createSlashSeparated();
     945        result->append(firstPercent.releaseNonNull());
     946        result->append(secondPercent.releaseNonNull());
     947        return RefPtr<CSSValue>(WTFMove(result));
     948    }
     949
     950    if (auto firstNumber = consumeNumber(range, ValueRangeAll)) {
     951        if (range.atEnd())
     952            return firstNumber;
     953        if (!consumeSlashIncludingWhitespace(range))
     954            return nullptr;
     955        auto secondNumber = consumeNumber(range, ValueRangeAll);
     956        if (!secondNumber)
     957            return nullptr;
     958        if (firstNumber->floatValue() > secondNumber->floatValue())
     959            return nullptr;
     960        auto result = CSSValueList::createSlashSeparated();
     961        result->append(firstNumber.releaseNonNull());
     962        result->append(secondNumber.releaseNonNull());
     963        return RefPtr<CSSValue>(WTFMove(result));
     964    }
     965
     966    return nullptr;
     967}
     968#endif
    904969
    905970static RefPtr<CSSPrimitiveValue> consumeFontStyleKeywordValue(CSSParserTokenRange& range)
     
    924989    return nullptr;
    925990}
     991
     992#if ENABLE(VARIATION_FONTS)
     993static RefPtr<CSSValue> consumeFontStyleRange(CSSParserTokenRange& range, CSSParserMode cssParserMode)
     994{
     995    if (auto result = consumeFontStyleKeywordValue(range)) {
     996        if (result->valueID() == CSSValueOblique) {
     997            if (range.atEnd())
     998                return result;
     999
     1000            if (auto firstAngle = consumeAngle(range, cssParserMode)) {
     1001                if (range.atEnd())
     1002                    return firstAngle;
     1003                if (!consumeSlashIncludingWhitespace(range))
     1004                    return nullptr;
     1005                auto secondAngle = consumeAngle(range, cssParserMode);
     1006                if (!secondAngle)
     1007                    return nullptr;
     1008                if (firstAngle->floatValue(CSSPrimitiveValue::CSS_DEG) > secondAngle->floatValue(CSSPrimitiveValue::CSS_DEG))
     1009                    return nullptr;
     1010                auto result = CSSValueList::createSlashSeparated();
     1011                result->append(firstAngle.releaseNonNull());
     1012                result->append(secondAngle.releaseNonNull());
     1013                return RefPtr<CSSValue>(WTFMove(result));
     1014            }
     1015
     1016            if (auto firstNumber = consumeNumber(range, ValueRangeAll)) {
     1017                if (range.atEnd())
     1018                    return firstNumber;
     1019                if (!consumeSlashIncludingWhitespace(range))
     1020                    return nullptr;
     1021                auto secondNumber = consumeNumber(range, ValueRangeAll);
     1022                if (!secondNumber)
     1023                    return nullptr;
     1024                if (firstNumber->floatValue() > secondNumber->floatValue())
     1025                    return nullptr;
     1026                auto result = CSSValueList::createSlashSeparated();
     1027                result->append(firstNumber.releaseNonNull());
     1028                result->append(secondNumber.releaseNonNull());
     1029                return RefPtr<CSSValue>(WTFMove(result));
     1030            }
     1031
     1032            return nullptr;
     1033        }
     1034        return result;
     1035    }
     1036    return nullptr;
     1037}
     1038#endif
    9261039
    9271040static String concatenateFamilyName(CSSParserTokenRange& range)
     
    42214334        break;
    42224335    case CSSPropertyFontWeight:
    4223         // FIXME: Parse range-based values.
     4336#if ENABLE(VARIATION_FONTS)
     4337        parsedValue = consumeFontWeightRange(m_range);
     4338#else
    42244339        parsedValue = consumeFontWeight(m_range);
     4340#endif
    42254341        break;
    42264342    case CSSPropertyFontStretch:
    4227         // FIXME: Parse range-based values.
     4343#if ENABLE(VARIATION_FONTS)
     4344        parsedValue = consumeFontStretchRange(m_range);
     4345#else
    42284346        parsedValue = consumeFontStretch(m_range);
     4347#endif
    42294348        break;
    42304349    case CSSPropertyFontStyle:
    4231         // FIXME: Parse range-based values.
     4350#if ENABLE(VARIATION_FONTS)
     4351        parsedValue = consumeFontStyleRange(m_range, m_context.mode);
     4352#else
    42324353        parsedValue = consumeFontStyle(m_range, m_context.mode);
     4354#endif
    42334355        break;
    42344356    case CSSPropertyFontVariantCaps:
  • trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp

    r213507 r213528  
    829829};
    830830
     831struct VariationCapabilities {
     832    std::optional<FontSelectionRange> weight;
     833    std::optional<FontSelectionRange> width;
     834    std::optional<FontSelectionRange> slope;
     835};
     836
     837#if ENABLE(VARIATION_FONTS)
     838static std::optional<FontSelectionRange> extractVariationBounds(CFDictionaryRef axis)
     839{
     840    CFNumberRef minimumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey));
     841    CFNumberRef maximumValue = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey));
     842    float rawMinimumValue = 0;
     843    float rawMaximumValue = 0;
     844    CFNumberGetValue(minimumValue, kCFNumberFloatType, &rawMinimumValue);
     845    CFNumberGetValue(maximumValue, kCFNumberFloatType, &rawMaximumValue);
     846    if (rawMinimumValue < rawMaximumValue)
     847        return {{ FontSelectionValue(rawMinimumValue), FontSelectionValue(rawMaximumValue) }};
     848    return std::nullopt;
     849}
     850#endif
     851
     852static VariationCapabilities variationCapabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
     853{
     854    VariationCapabilities result;
     855
     856#if ENABLE(VARIATION_FONTS)
     857    if (!adoptCF(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontVariationAttribute)))
     858        return result;
     859
     860    auto variations = adoptCF(CTFontCopyVariationAxes(adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, 0, nullptr)).get()));
     861    if (!variations)
     862        return result;
     863
     864    auto axisCount = CFArrayGetCount(variations.get());
     865    if (!axisCount)
     866        return result;
     867
     868    for (CFIndex i = 0; i < axisCount; ++i) {
     869        CFDictionaryRef axis = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(variations.get(), i));
     870        CFNumberRef axisIdentifier = static_cast<CFNumberRef>(CFDictionaryGetValue(axis, kCTFontVariationAxisIdentifierKey));
     871        uint32_t rawAxisIdentifier = 0;
     872        Boolean success = CFNumberGetValue(axisIdentifier, kCFNumberSInt32Type, &rawAxisIdentifier);
     873        ASSERT_UNUSED(success, success);
     874        if (rawAxisIdentifier == 0x77676874) // 'wght'
     875            result.weight = extractVariationBounds(axis);
     876        else if (rawAxisIdentifier == 0x77647468) // 'wdth'
     877            result.width = extractVariationBounds(axis);
     878        else if (rawAxisIdentifier == 0x736C6E74) // 'slnt'
     879            result.slope = extractVariationBounds(axis);
     880    }
     881#else
     882    UNUSED_PARAM(fontDescriptor);
     883#endif
     884
     885    return result;
     886}
     887
    831888FontSelectionCapabilities capabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
    832889{
     
    834891        return { };
    835892
    836     auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
    837     FontSelectionValue width;
    838     FontSelectionValue slant;
    839     FontSelectionValue weight;
    840     if (traits) {
    841         width = stretchFromCoreTextTraits(traits.get());
    842 
    843         auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
    844         if (symbolicTraitsNumber) {
    845             int32_t symbolicTraits;
    846             auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
     893    VariationCapabilities variationCapabilities = variationCapabilitiesForFontDescriptor(fontDescriptor);
     894
     895#if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
     896    bool weightComesFromTraits = !variationCapabilities.weight;
     897#else
     898    bool weightComesFromTraits = false;
     899#endif
     900
     901    if (!variationCapabilities.slope || !variationCapabilities.width || weightComesFromTraits) {
     902        auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
     903        if (traits) {
     904            if (!variationCapabilities.width) {
     905                auto widthValue = stretchFromCoreTextTraits(traits.get());
     906                variationCapabilities.width = {{ widthValue, widthValue }};
     907            }
     908
     909            if (!variationCapabilities.slope) {
     910                auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
     911                if (symbolicTraitsNumber) {
     912                    int32_t symbolicTraits;
     913                    auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
     914                    ASSERT_UNUSED(success, success);
     915                    auto slopeValue = symbolicTraits & kCTFontTraitItalic ? italicValue() : normalItalicValue();
     916                    variationCapabilities.slope = {{ slopeValue, slopeValue }};
     917                } else
     918                    variationCapabilities.slope = {{ normalItalicValue(), normalItalicValue() }};
     919            }
     920
     921#if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
     922            if (!variationCapabilities.weight) {
     923                auto weightNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWeightTrait));
     924                if (weightNumber) {
     925                    CGFloat ctWeight;
     926                    auto success = CFNumberGetValue(weightNumber, kCFNumberCGFloatType, &ctWeight);
     927                    ASSERT_UNUSED(success, success);
     928                    auto weightValue = fontWeightFromCoreText(ctWeight);
     929                    variationCapabilities.weight = {{ weightValue, weightValue }};
     930                } else
     931                    variationCapabilities.weight = {{ normalWeightValue(), normalWeightValue() }};
     932            }
     933#endif
     934        }
     935    }
     936
     937#if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
     938    if (!variationCapabilities.weight) {
     939        auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute)));
     940        if (weightNumber) {
     941            float cssWeight;
     942            auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &cssWeight);
    847943            ASSERT_UNUSED(success, success);
    848             slant = symbolicTraits & kCTFontTraitItalic ? italicValue() : normalItalicValue();
    849         }
    850 
    851 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
    852         auto weightNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWeightTrait));
    853         if (weightNumber) {
    854             CGFloat ctWeight;
    855             auto success = CFNumberGetValue(weightNumber, kCFNumberCGFloatType, &ctWeight);
    856             ASSERT_UNUSED(success, success);
    857             weight = fontWeightFromCoreText(ctWeight);
    858         }
    859 #endif
    860     }
    861 
    862 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
    863     auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute)));
    864     if (weightNumber) {
    865         float cssWeight;
    866         auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &cssWeight);
    867         ASSERT_UNUSED(success, success);
    868         weight = FontSelectionValue(cssWeight);
    869     }
    870 #endif
    871 
    872     // FIXME: Educate this function about font variations.
    873 
    874     return { { weight, weight }, { width, width }, { slant, slant } };
     944            auto weightValue = FontSelectionValue(cssWeight);
     945            variationCapabilities.weight = {{ weightValue, weightValue }};
     946        } else
     947            variationCapabilities.weight = {{ normalWeightValue(), normalWeightValue() }};
     948    }
     949#endif
     950
     951    return { variationCapabilities.weight.value(), variationCapabilities.width.value(), variationCapabilities.slope.value() };
    875952}
    876953
Note: See TracChangeset for help on using the changeset viewer.