<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[214572] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/214572">214572</a></dd>
<dt>Author</dt> <dd>mmaxfield@apple.com</dd>
<dt>Date</dt> <dd>2017-03-29 16:12:08 -0700 (Wed, 29 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Try to normalize variation ranges
https://bugs.webkit.org/show_bug.cgi?id=170119

Reviewed by Simon Fraser.

Source/WebCore:

TrueType GX-style variation fonts use one particular scale for values on their
weight/width/slope axes - usually the values lie between -1 and 1 on that scale.
However, OpenType 1.8-style fonts use the CSS scale for values on these axes.
For the purposes of font selection, these values need to lie on the same scale.
However, when font selection is completed and the variation values are actually
being applied to the fonts, values which lie on the font's actual scale need to
be applied. This patch adds normalize*() and denormalize*() functions to perform
both of these operations.

The conversion itself between the two scales isn't an exact mapping. Mapping
slope is just a linear relationship with 0deg &lt;=&gt; 0 and 20deg &lt;=&gt; 1 (as per the
CSS Fonts spec). Mapping widths is similar, it uses a 2-component piecewise
linear relationship which includes the values given in the Microsoft OpenType
spec for the OS/2 table's usWidthClass field. Weights are more difficult, so I
plotted the CSS weights and the GX-style weights for every style of San
Francisco, saw that the relationship appears to be linear, and ran a linear
regression to compute the line equation.

As for the actual discrimination of determining whether a font is a GX-style
font or not, we can use the presence of the 'STAT' table. This table didn't
exist when GX fonts were being created, and OpenType 1.8 variable fonts are
required to have this table.

Facebook uses the string &quot;.SFNSText&quot; in their @font-face blocks. This font is
a variation font, but uses the GX-style values. Facebook asks us to create
this font with a weight of 700, and because the values in the font are around
1.0, we were erroneously thinking that the font wasn't bold, so we were then
applying synthetic bold. This was causing text on facebook to look fuzzy and
ugly.

Test: fast/text/variations/font-selection-properties-expected.html

* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::isGXVariableFont):
(WebCore::normalizeWeight):
(WebCore::normalizeSlope):
(WebCore::denormalizeWeight):
(WebCore::denormalizeWidth):
(WebCore::denormalizeSlope):
(WebCore::normalizeWidth):
(WebCore::preparePlatformFont): Instead of using FontSelectionValues for the
intermediate values, we should use floats instead. This is because
FontSelectionValues are fixed-point numbers with the denominator having 2 bits.
When using this data type to represent values on the GX scale, which are usually
between 0 and 1, you lose a lot of fidelity. Instead, our intermediate
calculations should be done with floats, and converted to FontSelectionValues at
the end when they are representative of values on the CSS scale.
(WebCore::stretchFromCoreTextTraits):
(WebCore::fontWeightFromCoreText):
(WebCore::extractVariationBounds):
(WebCore::variationCapabilitiesForFontDescriptor):
(WebCore::capabilitiesForFontDescriptor):

LayoutTests:

* fast/text/variations/font-selection-properties-expected.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfasttextvariationsfontselectionpropertiesexpectedhtml">trunk/LayoutTests/fast/text/variations/font-selection-properties-expected.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscocoaFontCacheCoreTextcpp">trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (214571 => 214572)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-03-29 22:55:53 UTC (rev 214571)
+++ trunk/LayoutTests/ChangeLog        2017-03-29 23:12:08 UTC (rev 214572)
</span><span class="lines">@@ -1,3 +1,12 @@
</span><ins>+2017-03-29  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Try to normalize variation ranges
+        https://bugs.webkit.org/show_bug.cgi?id=170119
+
+        Reviewed by Simon Fraser.
+
+        * fast/text/variations/font-selection-properties-expected.html:
+
</ins><span class="cx"> 2017-03-29  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Mark http/tests/media/modern-media-controls/time-labels-support/long-time.html as flaky on macOS.
</span></span></pre></div>
<a id="trunkLayoutTestsfasttextvariationsfontselectionpropertiesexpectedhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/text/variations/font-selection-properties-expected.html (214571 => 214572)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/text/variations/font-selection-properties-expected.html        2017-03-29 22:55:53 UTC (rev 214571)
+++ trunk/LayoutTests/fast/text/variations/font-selection-properties-expected.html        2017-03-29 23:12:08 UTC (rev 214572)
</span><span class="lines">@@ -10,7 +10,7 @@
</span><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> This test makes sure that the font selection properties affect font variations.
</span><del>-&lt;div style=&quot;font-family: Boxis; font-variation-settings: 'wdth' 900;&quot;&gt;Hello&lt;/div&gt;
</del><ins>+&lt;div style=&quot;font-family: Boxis; font-variation-settings: 'wdth' 5.6666;&quot;&gt;Hello&lt;/div&gt;
</ins><span class="cx"> &lt;div style=&quot;font-family: Boxis; font-variation-settings: 'wdth' 100;&quot;&gt;Hello&lt;/div&gt;
</span><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (214571 => 214572)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-29 22:55:53 UTC (rev 214571)
+++ trunk/Source/WebCore/ChangeLog        2017-03-29 23:12:08 UTC (rev 214572)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2017-03-29  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
+
+        Try to normalize variation ranges
+        https://bugs.webkit.org/show_bug.cgi?id=170119
+
+        Reviewed by Simon Fraser.
+
+        TrueType GX-style variation fonts use one particular scale for values on their
+        weight/width/slope axes - usually the values lie between -1 and 1 on that scale.
+        However, OpenType 1.8-style fonts use the CSS scale for values on these axes.
+        For the purposes of font selection, these values need to lie on the same scale.
+        However, when font selection is completed and the variation values are actually
+        being applied to the fonts, values which lie on the font's actual scale need to
+        be applied. This patch adds normalize*() and denormalize*() functions to perform
+        both of these operations. 
+
+        The conversion itself between the two scales isn't an exact mapping. Mapping
+        slope is just a linear relationship with 0deg &lt;=&gt; 0 and 20deg &lt;=&gt; 1 (as per the
+        CSS Fonts spec). Mapping widths is similar, it uses a 2-component piecewise
+        linear relationship which includes the values given in the Microsoft OpenType
+        spec for the OS/2 table's usWidthClass field. Weights are more difficult, so I
+        plotted the CSS weights and the GX-style weights for every style of San
+        Francisco, saw that the relationship appears to be linear, and ran a linear
+        regression to compute the line equation.
+
+        As for the actual discrimination of determining whether a font is a GX-style
+        font or not, we can use the presence of the 'STAT' table. This table didn't
+        exist when GX fonts were being created, and OpenType 1.8 variable fonts are
+        required to have this table.
+
+        Facebook uses the string &quot;.SFNSText&quot; in their @font-face blocks. This font is
+        a variation font, but uses the GX-style values. Facebook asks us to create
+        this font with a weight of 700, and because the values in the font are around
+        1.0, we were erroneously thinking that the font wasn't bold, so we were then
+        applying synthetic bold. This was causing text on facebook to look fuzzy and
+        ugly.
+
+        Test: fast/text/variations/font-selection-properties-expected.html
+
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::isGXVariableFont):
+        (WebCore::normalizeWeight):
+        (WebCore::normalizeSlope):
+        (WebCore::denormalizeWeight):
+        (WebCore::denormalizeWidth):
+        (WebCore::denormalizeSlope):
+        (WebCore::normalizeWidth):
+        (WebCore::preparePlatformFont): Instead of using FontSelectionValues for the
+        intermediate values, we should use floats instead. This is because
+        FontSelectionValues are fixed-point numbers with the denominator having 2 bits.
+        When using this data type to represent values on the GX scale, which are usually
+        between 0 and 1, you lose a lot of fidelity. Instead, our intermediate
+        calculations should be done with floats, and converted to FontSelectionValues at
+        the end when they are representative of values on the CSS scale.
+        (WebCore::stretchFromCoreTextTraits):
+        (WebCore::fontWeightFromCoreText):
+        (WebCore::extractVariationBounds):
+        (WebCore::variationCapabilitiesForFontDescriptor):
+        (WebCore::capabilitiesForFontDescriptor):
+
</ins><span class="cx"> 2017-03-29  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         LinkBuffer and ExecutableAllocator shouldn't have anything to do with VM
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscocoaFontCacheCoreTextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp (214571 => 214572)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp        2017-03-29 22:55:53 UTC (rev 214571)
+++ trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp        2017-03-29 23:12:08 UTC (rev 214572)
</span><span class="lines">@@ -428,8 +428,62 @@
</span><span class="cx">     auto name = adoptCF(CTFontCopyPostScriptName(font));
</span><span class="cx">     return CFStringGetLength(name.get()) &gt; 0 &amp;&amp; CFStringGetCharacterAtIndex(name.get(), 0) == '.';
</span><span class="cx"> }
</span><ins>+
+static inline bool isGXVariableFont(CTFontRef font)
+{
+    auto tables = adoptCF(CTFontCopyAvailableTables(font, kCTFontTableOptionNoOptions));
+    if (!tables)
+        return false;
+    auto size = CFArrayGetCount(tables.get());
+    for (CFIndex i = 0; i &lt; size; ++i) {
+        // This is so yucky.
+        // https://developer.apple.com/reference/coretext/1510774-ctfontcopyavailabletables
+        // &quot;The returned set will contain unboxed values, which can be extracted like so:&quot;
+        // &quot;CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tags, index);&quot;
+        CTFontTableTag tableTag = static_cast&lt;CTFontTableTag&gt;(reinterpret_cast&lt;uintptr_t&gt;(CFArrayGetValueAtIndex(tables.get(), i)));
+        if (tableTag == 'stat')
+            return false;
+    }
+    return true;
+}
+
+// These values were calculated by performing a linear regression on the CSS weights/widths/slopes and Core Text weights/widths/slopes of San Francisco.
+// FIXME: &lt;rdar://problem/31312602&gt; Get the real values from Core Text.
+static inline float normalizeWeight(float value)
+{
+    return 523.7 * value - 109.3;
+}
+
+static inline float normalizeSlope(float value)
+{
+    return value * 300;
+}
+
+static inline float denormalizeWeight(float value)
+{
+    return (value + 109.3) / 523.7;
+}
+
+static inline float denormalizeWidth(float value)
+{
+    if (value &lt; 125)
+        return (value - 100) / 50;
+    return (value - 50) / 150;
+}
+
+static inline float denormalizeSlope(float value)
+{
+    return value / 300;
+}
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+static inline float normalizeWidth(float value)
+{
+    if (value &lt; 0.5)
+        return value * 50 + 100;
+    return value * 150 + 50;
+}
+
</ins><span class="cx"> RetainPtr&lt;CTFontRef&gt; preparePlatformFont(CTFontRef originalFont, TextRenderingMode textRenderingMode, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const FontFeatureSettings&amp; features, const FontVariantSettings&amp; variantSettings, FontSelectionRequest fontSelectionRequest, const FontVariationSettings&amp; variations, FontOpticalSizing fontOpticalSizing, float size)
</span><span class="cx"> {
</span><span class="cx">     bool alwaysAddVariations = false;
</span><span class="lines">@@ -483,6 +537,7 @@
</span><span class="cx"> #if ENABLE(VARIATION_FONTS)
</span><span class="cx">     VariationsMap variationsToBeApplied;
</span><span class="cx"> 
</span><ins>+    bool needsConversion = isGXVariableFont(originalFont);
</ins><span class="cx">     auto applyVariationValue = [&amp;](const FontTag&amp; tag, float value, bool isDefaultValue) {
</span><span class="cx">         // FIXME: Remove when &lt;rdar://problem/28707822&gt; is fixed
</span><span class="cx"> #define WORKAROUND_CORETEXT_VARIATIONS_DEFAULT_VALUE_BUG ((PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &lt; 101300) || (PLATFORM(IOS) &amp;&amp; __IPHONE_OS_VERSION_MIN_REQUIRED &lt; 110000))
</span><span class="lines">@@ -507,9 +562,17 @@
</span><span class="cx"> 
</span><span class="cx">     // The system font is somewhat magical. Don't mess with its variations.
</span><span class="cx">     if (!fontIsSystemFont(originalFont)) {
</span><del>-        applyVariation({{'w', 'g', 'h', 't'}}, static_cast&lt;float&gt;(fontSelectionRequest.weight));
-        applyVariation({{'w', 'd', 't', 'h'}}, static_cast&lt;float&gt;(fontSelectionRequest.width));
-        applyVariation({{'s', 'l', 'n', 't'}}, static_cast&lt;float&gt;(fontSelectionRequest.slope));
</del><ins>+        float weight = fontSelectionRequest.weight;
+        float width = fontSelectionRequest.width;
+        float slope = fontSelectionRequest.slope;
+        if (needsConversion) {
+            weight = denormalizeWeight(weight);
+            width = denormalizeWidth(width);
+            slope = denormalizeSlope(slope);
+        }
+        applyVariation({{'w', 'g', 'h', 't'}}, weight);
+        applyVariation({{'w', 'd', 't', 'h'}}, width);
+        applyVariation({{'s', 'l', 'n', 't'}}, slope);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (fontOpticalSizing == FontOpticalSizing::Enabled) {
</span><span class="lines">@@ -601,17 +664,16 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static FontSelectionValue stretchFromCoreTextTraits(CFDictionaryRef traits)
</del><ins>+static float stretchFromCoreTextTraits(CFDictionaryRef traits)
</ins><span class="cx"> {
</span><span class="cx">     auto widthNumber = static_cast&lt;CFNumberRef&gt;(CFDictionaryGetValue(traits, kCTFontWidthTrait));
</span><del>-    if (widthNumber) {
-        // FIXME: The normalization from Core Text's [-1, 1] range to CSS's [50%, 200%] range isn't perfect.
-        float ctWidth;
-        auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &amp;ctWidth);
-        ASSERT_UNUSED(success, success);
-        return FontSelectionValue(ctWidth &lt; 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50);
-    }
-    return normalStretchValue();
</del><ins>+    if (!widthNumber)
+        return normalStretchValue();
+
+    float ctWidth;
+    auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &amp;ctWidth);
+    ASSERT_UNUSED(success, success);
+    return normalizeWidth(ctWidth);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void invalidateFontCache();
</span><span class="lines">@@ -708,25 +770,25 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
</span><del>-static FontSelectionValue fontWeightFromCoreText(CGFloat weight)
</del><ins>+static float fontWeightFromCoreText(CGFloat weight)
</ins><span class="cx"> {
</span><span class="cx">     if (weight &lt; -0.6)
</span><del>-        return FontSelectionValue(100);
</del><ins>+        return 100;
</ins><span class="cx">     if (weight &lt; -0.365)
</span><del>-        return FontSelectionValue(200);
</del><ins>+        return 200;
</ins><span class="cx">     if (weight &lt; -0.115)
</span><del>-        return FontSelectionValue(300);
</del><ins>+        return 300;
</ins><span class="cx">     if (weight &lt;  0.130)
</span><del>-        return FontSelectionValue(400);
</del><ins>+        return 400;
</ins><span class="cx">     if (weight &lt;  0.235)
</span><del>-        return FontSelectionValue(500);
</del><ins>+        return 500;
</ins><span class="cx">     if (weight &lt;  0.350)
</span><del>-        return FontSelectionValue(600);
</del><ins>+        return 600;
</ins><span class="cx">     if (weight &lt;  0.500)
</span><del>-        return FontSelectionValue(700);
</del><ins>+        return 700;
</ins><span class="cx">     if (weight &lt;  0.700)
</span><del>-        return FontSelectionValue(800);
-    return FontSelectionValue(900);
</del><ins>+        return 800;
+    return 900;
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -835,14 +897,21 @@
</span><span class="cx">     HashMap&lt;String, InstalledFont&gt; m_postScriptNameToFontDescriptors;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+// Because this struct holds intermediate values which may be in the compressed -1 - 1 GX range, we don't want to use the relatively large
+// quantization of FontSelectionValue. Instead, do this logic with floats.
+struct MinMax {
+    float minimum;
+    float maximum;
+};
+
</ins><span class="cx"> struct VariationCapabilities {
</span><del>-    std::optional&lt;FontSelectionRange&gt; weight;
-    std::optional&lt;FontSelectionRange&gt; width;
-    std::optional&lt;FontSelectionRange&gt; slope;
</del><ins>+    std::optional&lt;MinMax&gt; weight;
+    std::optional&lt;MinMax&gt; width;
+    std::optional&lt;MinMax&gt; slope;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(VARIATION_FONTS)
</span><del>-static std::optional&lt;FontSelectionRange&gt; extractVariationBounds(CFDictionaryRef axis)
</del><ins>+static std::optional&lt;MinMax&gt; extractVariationBounds(CFDictionaryRef axis)
</ins><span class="cx"> {
</span><span class="cx">     CFNumberRef minimumValue = static_cast&lt;CFNumberRef&gt;(CFDictionaryGetValue(axis, kCTFontVariationAxisMinimumValueKey));
</span><span class="cx">     CFNumberRef maximumValue = static_cast&lt;CFNumberRef&gt;(CFDictionaryGetValue(axis, kCTFontVariationAxisMaximumValueKey));
</span><span class="lines">@@ -851,7 +920,7 @@
</span><span class="cx">     CFNumberGetValue(minimumValue, kCFNumberFloatType, &amp;rawMinimumValue);
</span><span class="cx">     CFNumberGetValue(maximumValue, kCFNumberFloatType, &amp;rawMaximumValue);
</span><span class="cx">     if (rawMinimumValue &lt; rawMaximumValue)
</span><del>-        return {{ FontSelectionValue(rawMinimumValue), FontSelectionValue(rawMaximumValue) }};
</del><ins>+        return {{ rawMinimumValue, rawMaximumValue }};
</ins><span class="cx">     return std::nullopt;
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="lines">@@ -864,7 +933,8 @@
</span><span class="cx">     if (!adoptCF(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontVariationAttribute)))
</span><span class="cx">         return result;
</span><span class="cx"> 
</span><del>-    auto variations = adoptCF(CTFontCopyVariationAxes(adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, 0, nullptr)).get()));
</del><ins>+    auto font = adoptCF(CTFontCreateWithFontDescriptor(fontDescriptor, 0, nullptr));
+    auto variations = adoptCF(CTFontCopyVariationAxes(font.get()));
</ins><span class="cx">     if (!variations)
</span><span class="cx">         return result;
</span><span class="cx"> 
</span><span class="lines">@@ -885,6 +955,15 @@
</span><span class="cx">         else if (rawAxisIdentifier == 0x736C6E74) // 'slnt'
</span><span class="cx">             result.slope = extractVariationBounds(axis);
</span><span class="cx">     }
</span><ins>+
+    if (isGXVariableFont(font.get())) {
+        if (result.weight)
+            result.weight = {{ normalizeWeight(result.weight.value().minimum), normalizeWeight(result.weight.value().maximum) }};
+        if (result.width)
+            result.width = {{ normalizeWidth(result.width.value().minimum), normalizeWidth(result.width.value().maximum) }};
+        if (result.slope)
+            result.slope = {{ normalizeSlope(result.slope.value().minimum), normalizeSlope(result.slope.value().maximum) }};
+    }
</ins><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(fontDescriptor);
</span><span class="cx"> #endif
</span><span class="lines">@@ -919,10 +998,10 @@
</span><span class="cx">                     int32_t symbolicTraits;
</span><span class="cx">                     auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &amp;symbolicTraits);
</span><span class="cx">                     ASSERT_UNUSED(success, success);
</span><del>-                    auto slopeValue = symbolicTraits &amp; kCTFontTraitItalic ? italicValue() : normalItalicValue();
</del><ins>+                    auto slopeValue = static_cast&lt;float&gt;(symbolicTraits &amp; kCTFontTraitItalic ? italicValue() : normalItalicValue());
</ins><span class="cx">                     variationCapabilities.slope = {{ slopeValue, slopeValue }};
</span><span class="cx">                 } else
</span><del>-                    variationCapabilities.slope = {{ normalItalicValue(), normalItalicValue() }};
</del><ins>+                    variationCapabilities.slope = {{ static_cast&lt;float&gt;(normalItalicValue()), static_cast&lt;float&gt;(normalItalicValue()) }};
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx"> #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP
</span><span class="lines">@@ -935,7 +1014,7 @@
</span><span class="cx">                     auto weightValue = fontWeightFromCoreText(ctWeight);
</span><span class="cx">                     variationCapabilities.weight = {{ weightValue, weightValue }};
</span><span class="cx">                 } else
</span><del>-                    variationCapabilities.weight = {{ normalWeightValue(), normalWeightValue() }};
</del><ins>+                    variationCapabilities.weight = {{ static_cast&lt;float&gt;(normalWeightValue()), static_cast&lt;float&gt;(normalWeightValue()) }};
</ins><span class="cx">             }
</span><span class="cx"> #endif
</span><span class="cx">         }
</span><span class="lines">@@ -948,14 +1027,15 @@
</span><span class="cx">             float cssWeight;
</span><span class="cx">             auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &amp;cssWeight);
</span><span class="cx">             ASSERT_UNUSED(success, success);
</span><del>-            auto weightValue = FontSelectionValue(cssWeight);
-            variationCapabilities.weight = {{ weightValue, weightValue }};
</del><ins>+            variationCapabilities.weight = {{ cssWeight, cssWeight }};
</ins><span class="cx">         } else
</span><del>-            variationCapabilities.weight = {{ normalWeightValue(), normalWeightValue() }};
</del><ins>+            variationCapabilities.weight = {{ static_cast&lt;float&gt;(normalWeightValue()), static_cast&lt;float&gt;(normalWeightValue()) }};
</ins><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    return { variationCapabilities.weight.value(), variationCapabilities.width.value(), variationCapabilities.slope.value() };
</del><ins>+    return {{ FontSelectionValue(variationCapabilities.weight.value().minimum), FontSelectionValue(variationCapabilities.weight.value().maximum) },
+        { FontSelectionValue(variationCapabilities.width.value().minimum), FontSelectionValue(variationCapabilities.width.value().maximum) },
+        { FontSelectionValue(variationCapabilities.slope.value().minimum), FontSelectionValue(variationCapabilities.slope.value().maximum) }};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
</span></span></pre>
</div>
</div>

</body>
</html>