Title: [213341] trunk
Revision
213341
Author
mmaxfi...@apple.com
Date
2017-03-02 19:17:35 -0800 (Thu, 02 Mar 2017)

Log Message

Migrate font-stretch to use fixed-point values
https://bugs.webkit.org/show_bug.cgi?id=169107

Reviewed by Dean Jackson.

Source/WebCore:

There are a few benefits of using fixed-point values:
- Not all of the entropy of a float is necessary for font selection. In particular, values are
expected to stay between around -1000 to 1000, and only need to have a few fractional bits.
Therefore, the values can be represented by 16-bit fixed point numbers, which includes one sign
bit and two fractional bits. This is smaller than the 32-bit floating point numbers we were
using, which means FontDescription can be slimmed down. This becomes even more important when
the rest of the variation font properties are implemented, since those will use these fixed-
point values too.
- Fixed point values have a larger distance between adjacent representable values, which means
there are more collisions, which means our cache hit rates are higher.

No new tests because there is no behavior change.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::fontStretchFromStyle):
* css/StyleBuilderConverter.h:
(WebCore::StyleBuilderConverter::convertFontStretch):
* platform/graphics/FontCache.h:
(WebCore::FontDescriptionKey::FontDescriptionKey):
* platform/graphics/FontDescription.h:
(WebCore::FontDescription::stretch):
(WebCore::FontDescription::setStretch):
(WebCore::FontCascadeDescription::initialStretch):
* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::defaultFontSelectionValues):
(WebCore::preparePlatformFont):
(WebCore::FontDatabase::InstalledFont::InstalledFont):
(WebCore::FontDatabase::InstalledFontFamily::expand):
(WebCore::FontDatabase::capabilitiesForFontDescriptor):
(WebCore::FontDatabase::stretchThreshold):
(WebCore::FontDatabase::italicThreshold):
(WebCore::FontDatabase::weightThreshold):
(WebCore::findClosestStretch):
(WebCore::filterStretch):
(WebCore::findClosestStyle):
(WebCore::filterStyle):
(WebCore::findClosestWeight):
(WebCore::filterWeight):
(WebCore::computeTargetWeight):
(WebCore::findClosestFont):
(WebCore::platformFontLookupWithFamily):
(WebCore::fontWithFamily):
(WebCore::defaultVariationValues): Deleted.
(WebCore::FontDatabase::Range::Range): Deleted.
(WebCore::FontDatabase::Range::isValid): Deleted.
(WebCore::FontDatabase::Range::expand): Deleted.
(WebCore::FontDatabase::Range::includes): Deleted.
(): Deleted.
* platform/text/TextFlags.h:
(WebCore::FontSelectionValue::FontSelectionValue):
(WebCore::FontSelectionValue::operator float):
(WebCore::FontSelectionValue::operator+):
(WebCore::FontSelectionValue::operator-):
(WebCore::FontSelectionValue::operator*):
(WebCore::FontSelectionValue::operator/):
(WebCore::FontSelectionValue::operator==):
(WebCore::FontSelectionValue::operator!=):
(WebCore::FontSelectionValue::operator<):
(WebCore::FontSelectionValue::operator<=):
(WebCore::FontSelectionValue::operator>):
(WebCore::FontSelectionValue::operator>=):
(WebCore::FontSelectionValue::rawValue):
(WebCore::FontSelectionRange::isValid):
(WebCore::FontSelectionRange::expand):
(WebCore::FontSelectionRange::includes):
(WebCore::FontSelectionCapabilities::expand):

Tools:

Update to new types.

* TestWebKitAPI/Tests/WebCore/FontCache.cpp:
(TestWebKitAPI::createPlatformFont):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (213340 => 213341)


--- trunk/Source/WebCore/ChangeLog	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/ChangeLog	2017-03-03 03:17:35 UTC (rev 213341)
@@ -1,3 +1,77 @@
+2017-03-02  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        Migrate font-stretch to use fixed-point values
+        https://bugs.webkit.org/show_bug.cgi?id=169107
+
+        Reviewed by Dean Jackson.
+
+        There are a few benefits of using fixed-point values:
+        - Not all of the entropy of a float is necessary for font selection. In particular, values are
+        expected to stay between around -1000 to 1000, and only need to have a few fractional bits.
+        Therefore, the values can be represented by 16-bit fixed point numbers, which includes one sign
+        bit and two fractional bits. This is smaller than the 32-bit floating point numbers we were
+        using, which means FontDescription can be slimmed down. This becomes even more important when
+        the rest of the variation font properties are implemented, since those will use these fixed-
+        point values too.
+        - Fixed point values have a larger distance between adjacent representable values, which means
+        there are more collisions, which means our cache hit rates are higher.
+
+        No new tests because there is no behavior change.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::fontStretchFromStyle):
+        * css/StyleBuilderConverter.h:
+        (WebCore::StyleBuilderConverter::convertFontStretch):
+        * platform/graphics/FontCache.h:
+        (WebCore::FontDescriptionKey::FontDescriptionKey):
+        * platform/graphics/FontDescription.h:
+        (WebCore::FontDescription::stretch):
+        (WebCore::FontDescription::setStretch):
+        (WebCore::FontCascadeDescription::initialStretch):
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::defaultFontSelectionValues):
+        (WebCore::preparePlatformFont):
+        (WebCore::FontDatabase::InstalledFont::InstalledFont):
+        (WebCore::FontDatabase::InstalledFontFamily::expand):
+        (WebCore::FontDatabase::capabilitiesForFontDescriptor):
+        (WebCore::FontDatabase::stretchThreshold):
+        (WebCore::FontDatabase::italicThreshold):
+        (WebCore::FontDatabase::weightThreshold):
+        (WebCore::findClosestStretch):
+        (WebCore::filterStretch):
+        (WebCore::findClosestStyle):
+        (WebCore::filterStyle):
+        (WebCore::findClosestWeight):
+        (WebCore::filterWeight):
+        (WebCore::computeTargetWeight):
+        (WebCore::findClosestFont):
+        (WebCore::platformFontLookupWithFamily):
+        (WebCore::fontWithFamily):
+        (WebCore::defaultVariationValues): Deleted.
+        (WebCore::FontDatabase::Range::Range): Deleted.
+        (WebCore::FontDatabase::Range::isValid): Deleted.
+        (WebCore::FontDatabase::Range::expand): Deleted.
+        (WebCore::FontDatabase::Range::includes): Deleted.
+        (): Deleted.
+        * platform/text/TextFlags.h:
+        (WebCore::FontSelectionValue::FontSelectionValue):
+        (WebCore::FontSelectionValue::operator float):
+        (WebCore::FontSelectionValue::operator+):
+        (WebCore::FontSelectionValue::operator-):
+        (WebCore::FontSelectionValue::operator*):
+        (WebCore::FontSelectionValue::operator/):
+        (WebCore::FontSelectionValue::operator==):
+        (WebCore::FontSelectionValue::operator!=):
+        (WebCore::FontSelectionValue::operator<):
+        (WebCore::FontSelectionValue::operator<=):
+        (WebCore::FontSelectionValue::operator>):
+        (WebCore::FontSelectionValue::operator>=):
+        (WebCore::FontSelectionValue::rawValue):
+        (WebCore::FontSelectionRange::isValid):
+        (WebCore::FontSelectionRange::expand):
+        (WebCore::FontSelectionRange::includes):
+        (WebCore::FontSelectionCapabilities::expand):
+
 2017-03-02  Alex Christensen  <achristen...@webkit.org>
 
         Modernize ContentExtensionParser

Modified: trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp (213340 => 213341)


--- trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp	2017-03-03 03:17:35 UTC (rev 213341)
@@ -1921,26 +1921,26 @@
 
 static Ref<CSSPrimitiveValue> fontStretchFromStyle(const RenderStyle& style)
 {
-    float stretch = style.fontDescription().stretch();
-    if (stretch == 50)
+    auto stretch = style.fontDescription().stretch();
+    if (stretch == FontSelectionValue(50))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueUltraCondensed);
-    if (stretch == 62.5)
+    if (stretch == FontSelectionValue(62.5f))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueExtraCondensed);
-    if (stretch == 75)
+    if (stretch == FontSelectionValue(75))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueCondensed);
-    if (stretch == 87.5)
+    if (stretch == FontSelectionValue(87.5f))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueSemiCondensed);
-    if (stretch == 100)
+    if (stretch == FontSelectionValue(100))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
-    if (stretch == 112.5)
+    if (stretch == FontSelectionValue(112.5f))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueSemiExpanded);
-    if (stretch == 125)
+    if (stretch == FontSelectionValue(125))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueExpanded);
-    if (stretch == 150)
+    if (stretch == FontSelectionValue(150))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueExtraExpanded);
-    if (stretch == 200)
+    if (stretch == FontSelectionValue(200))
         return CSSValuePool::singleton().createIdentifierValue(CSSValueUltraExpanded);
-    return CSSValuePool::singleton().createValue(stretch, CSSPrimitiveValue::CSS_PERCENTAGE);
+    return CSSValuePool::singleton().createValue(static_cast<float>(stretch), CSSPrimitiveValue::CSS_PERCENTAGE);
 }
 
 static Ref<CSSValue> fontVariantFromStyle(const RenderStyle& style)

Modified: trunk/Source/WebCore/css/StyleBuilderConverter.h (213340 => 213341)


--- trunk/Source/WebCore/css/StyleBuilderConverter.h	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/css/StyleBuilderConverter.h	2017-03-03 03:17:35 UTC (rev 213341)
@@ -114,7 +114,7 @@
     static bool convertOverflowScrolling(StyleResolver&, const CSSValue&);
 #endif
     static FontFeatureSettings convertFontFeatureSettings(StyleResolver&, const CSSValue&);
-    static float convertFontStretch(StyleResolver&, const CSSValue&);
+    static FontSelectionValue convertFontStretch(StyleResolver&, const CSSValue&);
 #if ENABLE(VARIATION_FONTS)
     static FontVariationSettings convertFontVariationSettings(StyleResolver&, const CSSValue&);
 #endif
@@ -1154,35 +1154,43 @@
     return settings;
 }
 
-inline float StyleBuilderConverter::convertFontStretch(StyleResolver&, const CSSValue& value)
+inline FontSelectionValue StyleBuilderConverter::convertFontStretch(StyleResolver&, const CSSValue& value)
 {
     ASSERT(is<CSSPrimitiveValue>(value));
     const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
-    if (primitiveValue.isPercentage() || primitiveValue.isNumber())
-        return primitiveValue.floatValue();
+    if (primitiveValue.isPercentage() || primitiveValue.isNumber()) {
+        auto value = primitiveValue.floatValue();
+        if (value <= static_cast<float>(FontSelectionValue::maximumValue())
+            && value >= static_cast<float>(FontSelectionValue::minimumValue()))
+            return FontSelectionValue(value);
+        if (value < static_cast<float>(FontSelectionValue::minimumValue()))
+            return FontSelectionValue::minimumValue();
+        ASSERT(value > static_cast<float>(FontSelectionValue::maximumValue()));
+        return FontSelectionValue::maximumValue();
+    }
 
     switch (primitiveValue.valueID()) {
     case CSSValueUltraCondensed:
-        return 50;
+        return FontSelectionValue(50);
     case CSSValueExtraCondensed:
-        return 62.5;
+        return FontSelectionValue(62.5f);
     case CSSValueCondensed:
-        return 75;
+        return FontSelectionValue(75);
     case CSSValueSemiCondensed:
-        return 87.5;
+        return FontSelectionValue(87.5f);
     case CSSValueNormal:
-        return 100;
+        return FontSelectionValue(100);
     case CSSValueSemiExpanded:
-        return 112.5;
+        return FontSelectionValue(112.5f);
     case CSSValueExpanded:
-        return 125;
+        return FontSelectionValue(125);
     case CSSValueExtraExpanded:
-        return 150;
+        return FontSelectionValue(150);
     case CSSValueUltraExpanded:
-        return 200;
+        return FontSelectionValue(200);
     default:
         ASSERT_NOT_REACHED();
-        return 100;
+        return FontSelectionValue(100);
     }
 }
 

Modified: trunk/Source/WebCore/platform/graphics/FontCache.h (213340 => 213341)


--- trunk/Source/WebCore/platform/graphics/FontCache.h	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/platform/graphics/FontCache.h	2017-03-03 03:17:35 UTC (rev 213341)
@@ -73,12 +73,12 @@
     FontDescriptionKey(const FontDescription& description)
         : m_size(description.computedPixelSize())
         , m_weight(description.weight())
-        , m_stretch(description.stretch())
         , m_flags(makeFlagsKey(description))
         , m_featureSettings(description.featureSettings())
 #if ENABLE(VARIATION_FONTS)
         , m_variationSettings(description.variationSettings())
 #endif
+        , m_stretch(description.stretch().rawValue())
     { }
 
     explicit FontDescriptionKey(WTF::HashTableDeletedValueType)
@@ -154,12 +154,12 @@
     // FontCascade::locale() is explicitly not included in this struct.
     unsigned m_size { 0 };
     unsigned m_weight { 0 };
-    float m_stretch { 0 };
     std::array<unsigned, 2> m_flags {{ 0, 0 }};
     FontFeatureSettings m_featureSettings;
 #if ENABLE(VARIATION_FONTS)
     FontVariationSettings m_variationSettings;
 #endif
+    uint16_t m_stretch { 0 };
 };
 
 struct FontDescriptionKeyHash {

Modified: trunk/Source/WebCore/platform/graphics/FontDescription.h (213340 => 213341)


--- trunk/Source/WebCore/platform/graphics/FontDescription.h	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/platform/graphics/FontDescription.h	2017-03-03 03:17:35 UTC (rev 213341)
@@ -46,7 +46,7 @@
 
     float computedSize() const { return m_computedSize; }
     FontItalic italic() const { return static_cast<FontItalic>(m_italic); }
-    float stretch() const { return m_stretch; }
+    FontSelectionValue stretch() const { return m_stretch; }
     int computedPixelSize() const { return int(m_computedSize + 0.5f); }
     FontWeight weight() const { return static_cast<FontWeight>(m_weight); }
     FontWeight lighterWeight() const;
@@ -98,7 +98,7 @@
 
     void setComputedSize(float s) { m_computedSize = clampToFloat(s); }
     void setItalic(FontItalic i) { m_italic = i; }
-    void setStretch(float stretch) { m_stretch = stretch; }
+    void setStretch(FontSelectionValue stretch) { m_stretch = stretch; }
     void setIsItalic(bool i) { setItalic(i ? FontItalicOn : FontItalicOff); }
     void setWeight(FontWeight w) { m_weight = w; }
     void setRenderingMode(FontRenderingMode mode) { m_renderingMode = static_cast<unsigned>(mode); }
@@ -136,8 +136,8 @@
     FontVariationSettings m_variationSettings;
     AtomicString m_locale;
 
-    float m_stretch { 100 }; // Stretch, or "width," of the font
     float m_computedSize { 0 }; // Computed size adjusted for the minimum font size and the zoom factor.
+    FontSelectionValue m_stretch { 100 }; // Stretch, or "width," of the font
     unsigned m_orientation : 1; // FontOrientation - Whether the font is rendering on a horizontal line or a vertical line.
     unsigned m_nonCJKGlyphOrientation : 1; // NonCJKGlyphOrientation - Only used by vertical text. Determines the default orientation for non-ideograph glyphs.
     unsigned m_widthVariant : 2; // FontWidthVariant
@@ -265,7 +265,7 @@
 
     // Initial values for font properties.
     static FontItalic initialItalic() { return FontItalicOff; }
-    static float initialStretch() { return 100; }
+    static FontSelectionValue initialStretch() { return FontSelectionValue(100); }
     static FontSmallCaps initialSmallCaps() { return FontSmallCapsOff; }
     static Kerning initialKerning() { return Kerning::Auto; }
     static FontSmoothingMode initialFontSmoothing() { return AutoSmoothing; }

Modified: trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp (213340 => 213341)


--- trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp	2017-03-03 03:17:35 UTC (rev 213341)
@@ -789,10 +789,6 @@
 
 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
 
-constexpr float stretchThreshold = 100;
-constexpr float italicThreshold = 20;
-constexpr float weightThreshold = 500;
-
 class FontDatabase {
 public:
     static FontDatabase& singleton()
@@ -804,93 +800,17 @@
     FontDatabase(const FontDatabase&) = delete;
     FontDatabase& operator=(const FontDatabase&) = delete;
 
-    // [Inclusive, Inclusive]
-    struct Range {
-        Range()
-        {
-            ASSERT(!isValid());
-        }
-
-        Range(float minimum, float maximum)
-            : minimum(minimum)
-            , maximum(maximum)
-        {
-            ASSERT(isValid());
-        }
-
-        bool isValid() const
-        {
-            return minimum <= maximum;
-        }
-
-        void expand(const Range& other)
-        {
-            ASSERT(other.isValid());
-            if (!isValid())
-                *this = other;
-            else {
-                minimum = std::min(minimum, other.minimum);
-                maximum = std::max(maximum, other.maximum);
-            }
-            ASSERT(isValid());
-        }
-
-        bool includes(float target) const
-        {
-            return target >= minimum && target <= maximum;
-        }
-
-        float minimum { 1 };
-        float maximum { 0 };
-    };
-
     struct InstalledFont {
         InstalledFont() = default;
 
         InstalledFont(CTFontDescriptorRef fontDescriptor)
             : fontDescriptor(fontDescriptor)
+            , capabilities(capabilitiesForFontDescriptor(fontDescriptor))
         {
-            if (!fontDescriptor)
-                return;
-
-            auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
-            float width = 0;
-            float slant = 0;
-            float weight = 0;
-            if (traits) {
-                auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWidthTrait));
-                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, &ctWidth);
-                    ASSERT_UNUSED(success, success);
-                    width = ctWidth < 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50;
-                }
-
-                auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
-                if (symbolicTraitsNumber) {
-                    int32_t symbolicTraits;
-                    auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
-                    ASSERT_UNUSED(success, success);
-                    slant = symbolicTraits & kCTFontTraitItalic ? italicThreshold : 0;
-                }
-            }
-
-            auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute)));
-            if (weightNumber) {
-                auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &weight);
-                ASSERT_UNUSED(success, success);
-            }
-            
-            stretch = Range(width, width);
-            style = Range(slant, slant);
-            this->weight = Range(weight, weight);
         }
 
         RetainPtr<CTFontDescriptorRef> fontDescriptor;
-        Range stretch;
-        Range style;
-        Range weight;
+        FontSelectionCapabilities capabilities;
     };
 
     struct InstalledFontFamily {
@@ -905,9 +825,7 @@
 
         void expand(const InstalledFont& installedFont)
         {
-            stretchBounds.expand(installedFont.stretch);
-            styleBounds.expand(installedFont.style);
-            weightBounds.expand(installedFont.weight);
+            capabilities.expand(installedFont.capabilities);
         }
 
         bool isEmpty() const
@@ -921,9 +839,7 @@
         }
 
         Vector<InstalledFont> installedFonts;
-        Range stretchBounds;
-        Range styleBounds;
-        Range weightBounds;
+        FontSelectionCapabilities capabilities;
     };
 
     const InstalledFontFamily& collectionForFamily(const String& familyName)
@@ -969,6 +885,65 @@
         m_postScriptNameToFontDescriptors.clear();
     }
 
+    static FontSelectionCapabilities capabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor)
+    {
+        if (!fontDescriptor)
+            return { };
+
+        auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));
+        FontSelectionValue width;
+        FontSelectionValue slant;
+        FontSelectionValue weight;
+        if (traits) {
+            auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWidthTrait));
+            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, &ctWidth);
+                ASSERT_UNUSED(success, success);
+                width = FontSelectionValue(ctWidth < 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50);
+            }
+
+            auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));
+            if (symbolicTraitsNumber) {
+                int32_t symbolicTraits;
+                auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);
+                ASSERT_UNUSED(success, success);
+                slant = symbolicTraits & kCTFontTraitItalic ? italicThreshold() : FontSelectionValue();
+            }
+        }
+
+        auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute)));
+        if (weightNumber) {
+            float cssWeight;
+            auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &cssWeight);
+            ASSERT_UNUSED(success, success);
+            weight = FontSelectionValue(cssWeight);
+        }
+
+        // FIXME: Educate this function about font variations.
+
+        return { { weight, weight }, { width, width }, { slant, slant } };
+    }
+
+    static const FontSelectionValue stretchThreshold()
+    {
+        static NeverDestroyed<FontSelectionValue> threshold(100);
+        return threshold.get();
+    }
+
+    static const FontSelectionValue italicThreshold()
+    {
+        static NeverDestroyed<FontSelectionValue> threshold(20);
+        return threshold.get();
+    }
+
+    static const FontSelectionValue weightThreshold()
+    {
+        static NeverDestroyed<FontSelectionValue> threshold(500);
+        return threshold.get();
+    }
+
 private:
     friend class NeverDestroyed<FontDatabase>;
 
@@ -1002,33 +977,35 @@
     });
 }
 
-static inline std::optional<float> findClosestStretch(float targetStretch, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
+static inline std::optional<FontSelectionValue> findClosestStretch(FontSelectionValue targetStretch, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
 {
     std::function<float(const FontDatabase::InstalledFont&)> computeScore;
 
-    if (targetStretch >= stretchThreshold) {
-        float threshold = std::max(targetStretch, installedFonts.stretchBounds.maximum);
+    if (targetStretch >= FontDatabase::stretchThreshold()) {
+        auto threshold = std::max(targetStretch, installedFonts.capabilities.width.maximum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            ASSERT(font.stretch.isValid());
-            if (font.stretch.includes(targetStretch))
+            auto width = font.capabilities.width;
+            ASSERT(width.isValid());
+            if (width.includes(targetStretch))
                 return 0;
-            ASSERT(font.stretch.minimum > targetStretch || font.stretch.maximum < targetStretch);
-            if (font.stretch.minimum > targetStretch)
-                return font.stretch.minimum - targetStretch;
-            ASSERT(font.stretch.maximum < targetStretch);
-            return threshold - font.stretch.maximum;
+            ASSERT(width.minimum > targetStretch || width.maximum < targetStretch);
+            if (width.minimum > targetStretch)
+                return width.minimum - targetStretch;
+            ASSERT(width.maximum < targetStretch);
+            return threshold - width.maximum;
         };
     } else {
-        ASSERT(targetStretch < stretchThreshold);
-        float threshold = std::min(targetStretch, installedFonts.stretchBounds.minimum);
+        ASSERT(targetStretch < FontDatabase::stretchThreshold());
+        auto threshold = std::min(targetStretch, installedFonts.capabilities.width.minimum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            if (font.stretch.includes(targetStretch))
+            auto width = font.capabilities.width;
+            if (width.includes(targetStretch))
                 return 0;
-            ASSERT(font.stretch.minimum > targetStretch || font.stretch.maximum < targetStretch);
-            if (font.stretch.maximum < targetStretch)
-                return targetStretch - font.stretch.maximum;
-            ASSERT(font.stretch.minimum > targetStretch);
-            return font.stretch.minimum - threshold;
+            ASSERT(width.minimum > targetStretch || width.maximum < targetStretch);
+            if (width.maximum < targetStretch)
+                return targetStretch - width.maximum;
+            ASSERT(width.minimum > targetStretch);
+            return width.minimum - threshold;
         };
     }
 
@@ -1045,78 +1022,83 @@
     if (!minimumScore)
         return std::nullopt;
     auto& winner = installedFonts.installedFonts[closestIndex];
-    if (winner.stretch.includes(targetStretch))
+    auto width = winner.capabilities.width;
+    if (width.includes(targetStretch))
         return targetStretch;
-    if (winner.stretch.minimum > targetStretch)
-        return winner.stretch.minimum;
-    ASSERT(winner.stretch.maximum < targetStretch);
-    return winner.stretch.maximum;
+    if (width.minimum > targetStretch)
+        return width.minimum;
+    ASSERT(width.maximum < targetStretch);
+    return width.maximum;
 }
 
-static inline void filterStretch(float target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
+static inline void filterStretch(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
 {
     iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) {
-        if (!installedFont.stretch.includes(target))
+        if (!installedFont.capabilities.width.includes(target))
             filter[i] = false;
     });
 }
 
-static inline std::optional<float> findClosestStyle(float targetStyle, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
+static inline std::optional<FontSelectionValue> findClosestStyle(FontSelectionValue targetStyle, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
 {
     std::function<float(const FontDatabase::InstalledFont&)> computeScore;
 
-    if (targetStyle >= italicThreshold) {
-        float threshold = std::max(targetStyle, installedFonts.styleBounds.maximum);
+    if (targetStyle >= FontDatabase::italicThreshold()) {
+        auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            ASSERT(font.style.isValid());
-            if (font.style.includes(targetStyle))
+            auto slope = font.capabilities.slope;
+            ASSERT(slope.isValid());
+            if (slope.includes(targetStyle))
                 return 0;
-            ASSERT(font.style.minimum > targetStyle || font.style.maximum < targetStyle);
-            if (font.style.minimum > targetStyle)
-                return font.style.minimum - targetStyle;
-            ASSERT(targetStyle > font.style.maximum);
-            return threshold - font.style.maximum;
+            ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle);
+            if (slope.minimum > targetStyle)
+                return slope.minimum - targetStyle;
+            ASSERT(targetStyle > slope.maximum);
+            return threshold - slope.maximum;
         };
-    } else if (targetStyle >= 0) {
-        float threshold = std::max(targetStyle, installedFonts.styleBounds.maximum);
+    } else if (targetStyle >= FontSelectionValue()) {
+        auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            ASSERT(font.style.isValid());
-            if (font.style.includes(targetStyle))
+            auto slope = font.capabilities.slope;
+            ASSERT(slope.isValid());
+            if (slope.includes(targetStyle))
                 return 0;
-            ASSERT(font.style.minimum > targetStyle || font.style.maximum < targetStyle);
-            if (font.style.maximum >= 0 && font.style.maximum < targetStyle)
-                return targetStyle - font.style.maximum;
-            if (font.style.minimum > targetStyle)
-                return font.style.minimum;
-            ASSERT(font.style.maximum < 0);
-            return threshold - font.style.maximum;
+            ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle);
+            if (slope.maximum >= FontSelectionValue() && slope.maximum < targetStyle)
+                return targetStyle - slope.maximum;
+            if (slope.minimum > targetStyle)
+                return slope.minimum;
+            ASSERT(slope.maximum < FontSelectionValue());
+            return threshold - slope.maximum;
         };
-    } else if (targetStyle > -italicThreshold) {
-        float threshold = std::min(targetStyle, installedFonts.styleBounds.minimum);
+    } else if (targetStyle > -FontDatabase::italicThreshold()) {
+        auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            ASSERT(font.style.isValid());
-            if (font.style.includes(targetStyle))
+            auto slope = font.capabilities.slope;
+            ASSERT(slope.isValid());
+            if (slope.includes(targetStyle))
                 return 0;
-            ASSERT(font.style.minimum > targetStyle || font.style.maximum < targetStyle);
-            if (font.style.minimum > targetStyle && font.style.minimum <= 0)
-                return font.style.minimum - targetStyle;
-            if (font.style.maximum < targetStyle)
-                return -font.style.maximum;
-            ASSERT(font.style.minimum > 0);
-            return font.style.minimum - threshold;
+            ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle);
+            if (slope.minimum > targetStyle && slope.minimum <= FontSelectionValue())
+                return slope.minimum - targetStyle;
+            if (slope.maximum < targetStyle)
+                return -slope.maximum;
+            ASSERT(slope.minimum > FontSelectionValue());
+            return slope.minimum - threshold;
         };
     } else {
-        ASSERT(targetStyle <= -italicThreshold);
-        float threshold = std::min(targetStyle, installedFonts.styleBounds.minimum);
+        ASSERT(targetStyle <= -FontDatabase::italicThreshold());
+        auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum);
         computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            ASSERT(font.style.isValid());
-            if (font.style.includes(targetStyle))
+            auto slope = font.capabilities.slope;
+            ASSERT(slope.isValid());
+            if (slope.includes(targetStyle))
                 return 0;
-            ASSERT(font.style.minimum > targetStyle || font.style.maximum < targetStyle);
-            if (font.style.maximum < targetStyle)
-                return targetStyle - font.style.maximum;
-            ASSERT(font.style.minimum > targetStyle);
-            return font.style.minimum - threshold;
+            ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle);
+            if (slope.maximum < targetStyle)
+                return targetStyle - slope.maximum;
+            ASSERT(slope.minimum > targetStyle);
+            return slope.minimum - threshold;
         };
     }
 
@@ -1133,42 +1115,43 @@
     if (!minimumScore)
         return std::nullopt;
     auto& winner = installedFonts.installedFonts[closestIndex];
-    if (winner.style.includes(targetStyle))
+    auto slope = winner.capabilities.slope;
+    if (slope.includes(targetStyle))
         return targetStyle;
-    if (winner.style.minimum > targetStyle)
-        return winner.style.minimum;
-    ASSERT(winner.style.maximum < targetStyle);
-    return winner.style.maximum;
+    if (slope.minimum > targetStyle)
+        return slope.minimum;
+    ASSERT(slope.maximum < targetStyle);
+    return slope.maximum;
 }
 
-static inline void filterStyle(float target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
+static inline void filterStyle(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
 {
     iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) {
-        if (!installedFont.style.includes(target))
+        if (!installedFont.capabilities.slope.includes(target))
             filter[i] = false;
     });
 }
 
-static inline std::optional<float> findClosestWeight(float targetWeight, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
+static inline std::optional<FontSelectionValue> findClosestWeight(FontSelectionValue targetWeight, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)
 {
     {
         // The spec states: "If the desired weight is 400, 500 is checked first ... If the desired weight is 500, 400 is checked first"
-        IterateActiveFontsWithReturnCallback<float> searchFor400 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<float> {
-            if (font.weight.includes(400))
-                return 400;
+        IterateActiveFontsWithReturnCallback<FontSelectionValue> searchFor400 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<FontSelectionValue> {
+            if (font.capabilities.weight.includes(FontSelectionValue(400)))
+                return FontSelectionValue(400);
             return std::nullopt;
         };
-        IterateActiveFontsWithReturnCallback<float> searchFor500 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<float> {
-            if (font.weight.includes(500))
-                return 500;
+        IterateActiveFontsWithReturnCallback<FontSelectionValue> searchFor500 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<FontSelectionValue> {
+            if (font.capabilities.weight.includes(FontSelectionValue(500)))
+                return FontSelectionValue(500);
             return std::nullopt;
         };
-        if (targetWeight == 400) {
+        if (targetWeight == FontSelectionValue(400)) {
             if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor400))
                 return result;
             if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500))
                 return result;
-        } else if (targetWeight == 500) {
+        } else if (targetWeight == FontSelectionValue(500)) {
             if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500))
                 return result;
             if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor400))
@@ -1177,28 +1160,30 @@
     }
 
     std::function<float(const FontDatabase::InstalledFont&)> computeScore;
-    if (targetWeight <= weightThreshold) {
-        float threshold = std::min(targetWeight, installedFonts.weightBounds.minimum);
-        computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            if (font.weight.includes(targetWeight))
-                return 0;
-            ASSERT(font.weight.minimum > targetWeight || font.weight.maximum < targetWeight);
-            if (font.weight.maximum < targetWeight)
-                return targetWeight - font.weight.maximum;
-            ASSERT(font.weight.minimum > targetWeight);
-            return font.weight.minimum - threshold;
+    if (targetWeight <= FontDatabase::weightThreshold()) {
+        auto threshold = std::min(targetWeight, installedFonts.capabilities.weight.minimum);
+        computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> FontSelectionValue {
+            auto weight = font.capabilities.weight;
+            if (weight.includes(targetWeight))
+                return FontSelectionValue();
+            ASSERT(weight.minimum > targetWeight || weight.maximum < targetWeight);
+            if (weight.maximum < targetWeight)
+                return targetWeight - weight.maximum;
+            ASSERT(weight.minimum > targetWeight);
+            return weight.minimum - threshold;
         };
     } else {
-        ASSERT(targetWeight > weightThreshold);
-        float threshold = std::max(targetWeight, installedFonts.weightBounds.maximum);
-        computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float {
-            if (font.weight.includes(targetWeight))
-                return 0;
-            ASSERT(font.weight.minimum > targetWeight || font.weight.maximum < targetWeight);
-            if (font.weight.minimum > targetWeight)
-                return font.weight.minimum - targetWeight;
-            ASSERT(font.weight.maximum < targetWeight);
-            return threshold - font.weight.maximum;
+        ASSERT(targetWeight > FontDatabase::weightThreshold());
+        auto threshold = std::max(targetWeight, installedFonts.capabilities.weight.maximum);
+        computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> FontSelectionValue {
+            auto weight = font.capabilities.weight;
+            if (weight.includes(targetWeight))
+                return FontSelectionValue();
+            ASSERT(weight.minimum > targetWeight || weight.maximum < targetWeight);
+            if (weight.minimum > targetWeight)
+                return weight.minimum - targetWeight;
+            ASSERT(weight.maximum < targetWeight);
+            return threshold - weight.maximum;
         };
     }
 
@@ -1215,50 +1200,51 @@
     if (!minimumScore)
         return std::nullopt;
     auto& winner = installedFonts.installedFonts[closestIndex];
-    if (winner.weight.includes(targetWeight))
+    auto weight = winner.capabilities.weight;
+    if (weight.includes(targetWeight))
         return targetWeight;
-    if (winner.weight.minimum > targetWeight)
-        return winner.weight.minimum;
-    ASSERT(winner.weight.maximum < targetWeight);
-    return winner.weight.maximum;
+    if (weight.minimum > targetWeight)
+        return weight.minimum;
+    ASSERT(weight.maximum < targetWeight);
+    return weight.maximum;
 }
 
-static inline void filterWeight(float target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
+static inline void filterWeight(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)
 {
     iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) {
-        if (!installedFont.weight.includes(target))
+        if (!installedFont.capabilities.weight.includes(target))
             filter[i] = false;
     });
 }
 
-static inline float computeTargetWeight(FontWeight weight)
+static inline FontSelectionValue computeTargetWeight(FontWeight weight)
 {
     switch (weight) {
     case FontWeight100:
-        return 100;
+        return FontSelectionValue(100);
     case FontWeight200:
-        return 200;
+        return FontSelectionValue(200);
     case FontWeight300:
-        return 300;
+        return FontSelectionValue(300);
     case FontWeight400:
-        return 400;
+        return FontSelectionValue(400);
     case FontWeight500:
-        return 500;
+        return FontSelectionValue(500);
     case FontWeight600:
-        return 600;
+        return FontSelectionValue(600);
     case FontWeight700:
-        return 700;
+        return FontSelectionValue(700);
     case FontWeight800:
-        return 800;
+        return FontSelectionValue(800);
     case FontWeight900:
-        return 900;
+        return FontSelectionValue(900);
     default:
         ASSERT_NOT_REACHED();
-        return 400;
+        return FontSelectionValue(400);
     }
 }
 
-static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, CTFontSymbolicTraits requestedTraits, FontWeight weight, float stretch)
+static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch)
 {
     ASSERT(!familyFonts.isEmpty());
 
@@ -1267,20 +1253,18 @@
     for (size_t i = 0; i < familyFonts.size(); ++i)
         filter[i] = true;
 
-    // FIXME: Implement this.
-    float targetStretch = stretch;
-    if (auto closestStretch = findClosestStretch(targetStretch, familyFonts, filter))
+    if (auto closestStretch = findClosestStretch(stretch, familyFonts, filter))
         filterStretch(closestStretch.value(), familyFonts, filter);
     else
         return nullptr;
 
-    float targetStyle = requestedTraits & kCTFontTraitItalic ? italicThreshold : 0;
+    FontSelectionValue targetStyle = requestedTraits & kCTFontTraitItalic ? FontDatabase::italicThreshold() : FontSelectionValue();
     if (auto closestStyle = findClosestStyle(targetStyle, familyFonts, filter))
         filterStyle(closestStyle.value(), familyFonts, filter);
     else
         return nullptr;
 
-    float targetWeight = computeTargetWeight(weight);
+    FontSelectionValue targetWeight = computeTargetWeight(weight);
     if (auto closestWeight = findClosestWeight(targetWeight, familyFonts, filter))
         filterWeight(closestWeight.value(), familyFonts, filter);
     else
@@ -1293,7 +1277,7 @@
 
 #endif // !SHOULD_USE_CORE_TEXT_FONT_LOOKUP
 
-static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, float stretch, float size)
+static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch, float size)
 {
     const auto& whitelist = fontWhitelist();
     if (!isSystemFont(family) && whitelist.size() && !whitelist.contains(family))
@@ -1316,7 +1300,8 @@
         const auto& postScriptFont = FontDatabase::singleton().fontForPostScriptName(family);
         if (!postScriptFont.fontDescriptor)
             return nullptr;
-        if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.style.maximum < italicThreshold) || (weight >= FontWeight600 && postScriptFont.weight.maximum < 600)) {
+        if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.capabilities.slope.maximum < FontDatabase::italicThreshold())
+            || (weight >= FontWeight600 && postScriptFont.capabilities.weight.maximum < FontSelectionValue(600))) {
             auto postScriptFamilyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(postScriptFont.fontDescriptor.get(), kCTFontFamilyNameAttribute)));
             if (!postScriptFamilyName)
                 return nullptr;
@@ -1356,7 +1341,7 @@
     FontCache::singleton().invalidate();
 }
 
-static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, float stretch, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontVariationSettings& variationSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size)
+static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, FontSelectionValue stretch, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontVariationSettings& variationSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size)
 {
     if (family.isEmpty())
         return nullptr;

Modified: trunk/Source/WebCore/platform/text/TextFlags.h (213340 => 213341)


--- trunk/Source/WebCore/platform/text/TextFlags.h	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Source/WebCore/platform/text/TextFlags.h	2017-03-03 03:17:35 UTC (rev 213341)
@@ -23,9 +23,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#ifndef TextFlags_h
-#define TextFlags_h
+#pragma once
 
+#include <wtf/NeverDestroyed.h>
+
 namespace WebCore {
 
 enum TextRenderingMode { AutoTextRendering, OptimizeSpeed, OptimizeLegibility, GeometricPrecision };
@@ -397,6 +398,162 @@
     FontWeightMask = FontWeight100Mask | FontWeight200Mask | FontWeight300Mask | FontWeight400Mask | FontWeight500Mask | FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask
 };
 
+// Unclamped, unchecked, signed fixed-point number representing a value used for font variations.
+// Sixteen bits in total, one sign bit, two fractional bits, means the smallest positive representable value is 0.25,
+// the maximum representable value is 8191.75, and the minimum representable value is -8192.
+class FontSelectionValue {
+public:
+    FontSelectionValue() = default;
+
+    // Explicit because it is lossy.
+    explicit FontSelectionValue(int x)
+        : m_backing(x * fractionalEntropy)
+    {
+    }
+
+    // Explicit because it is lossy.
+    explicit FontSelectionValue(float x)
+        : m_backing(x * fractionalEntropy)
+    {
+    }
+
+    operator float() const
+    {
+        // floats have 23 fractional bits, but only 14 fractional bits are necessary, so every value can be represented losslessly.
+        return m_backing / static_cast<float>(fractionalEntropy);
+    }
+
+    FontSelectionValue operator+(const FontSelectionValue other) const
+    {
+        return FontSelectionValue(m_backing + other.m_backing, RawTag::RawTag);
+    }
+
+    FontSelectionValue operator-(const FontSelectionValue other) const
+    {
+        return FontSelectionValue(m_backing - other.m_backing, RawTag::RawTag);
+    }
+
+    FontSelectionValue operator*(const FontSelectionValue other) const
+    {
+        return FontSelectionValue(static_cast<int32_t>(m_backing) * other.m_backing / fractionalEntropy, RawTag::RawTag);
+    }
+
+    FontSelectionValue operator/(const FontSelectionValue other) const
+    {
+        return FontSelectionValue(static_cast<int32_t>(m_backing) / other.m_backing * fractionalEntropy, RawTag::RawTag);
+    }
+
+    FontSelectionValue operator-() const
+    {
+        return FontSelectionValue(-m_backing, RawTag::RawTag);
+    }
+
+    bool operator==(const FontSelectionValue other) const
+    {
+        return m_backing == other.m_backing;
+    }
+
+    bool operator!=(const FontSelectionValue other) const
+    {
+        return !operator==(other);
+    }
+
+    bool operator<(const FontSelectionValue other) const
+    {
+        return m_backing < other.m_backing;
+    }
+
+    bool operator<=(const FontSelectionValue other) const
+    {
+        return m_backing <= other.m_backing;
+    }
+
+    bool operator>(const FontSelectionValue other) const
+    {
+        return m_backing > other.m_backing;
+    }
+
+    bool operator>=(const FontSelectionValue other) const
+    {
+        return m_backing >= other.m_backing;
+    }
+
+    int16_t rawValue() const
+    {
+        return m_backing;
+    }
+
+    static FontSelectionValue maximumValue()
+    {
+        static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<int16_t>::max(), RawTag::RawTag);
+        return result.get();
+    }
+
+    static FontSelectionValue minimumValue()
+    {
+        static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<int16_t>::min(), RawTag::RawTag);
+        return result.get();
+    }
+
+private:
+    enum class RawTag { RawTag };
+
+    FontSelectionValue(int16_t rawValue, RawTag)
+        : m_backing(rawValue)
+    {
+    }
+
+    static constexpr int fractionalEntropy = 4;
+    int16_t m_backing { 0 };
+};
+
+// [Inclusive, Inclusive]
+struct FontSelectionRange {
+    bool isValid() const
+    {
+        return minimum <= maximum;
+    }
+
+    void expand(const FontSelectionRange& other)
+    {
+        ASSERT(other.isValid());
+        if (!isValid())
+            *this = other;
+        else {
+            minimum = std::min(minimum, other.minimum);
+            maximum = std::max(maximum, other.maximum);
+        }
+        ASSERT(isValid());
+    }
+
+    bool includes(FontSelectionValue target) const
+    {
+        return target >= minimum && target <= maximum;
+    }
+
+    FontSelectionValue minimum { FontSelectionValue(1) };
+    FontSelectionValue maximum { FontSelectionValue(0) };
+};
+
+struct FontSelectionRequest {
+    FontSelectionValue weight;
+    FontSelectionValue width;
+    FontSelectionValue slope;
+};
+
+struct FontSelectionCapabilities {
+    void expand(const FontSelectionCapabilities& capabilities)
+    {
+        weight.expand(capabilities.weight);
+        width.expand(capabilities.width);
+        slope.expand(capabilities.slope);
+    }
+
+    FontSelectionRange weight;
+    FontSelectionRange width;
+    FontSelectionRange slope;
+};
+
 enum class Kerning {
     Auto,
     Normal,
@@ -404,5 +561,3 @@
 };
 
 }
-
-#endif

Modified: trunk/Tools/ChangeLog (213340 => 213341)


--- trunk/Tools/ChangeLog	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Tools/ChangeLog	2017-03-03 03:17:35 UTC (rev 213341)
@@ -1,3 +1,15 @@
+2017-03-02  Myles C. Maxfield  <mmaxfi...@apple.com>
+
+        Migrate font-stretch to use fixed-point values
+        https://bugs.webkit.org/show_bug.cgi?id=169107
+
+        Reviewed by Dean Jackson.
+
+        Update to new types.
+
+        * TestWebKitAPI/Tests/WebCore/FontCache.cpp:
+        (TestWebKitAPI::createPlatformFont):
+
 2017-03-02  Brady Eidson  <beid...@apple.com>
 
         Update WKWebsiteDatastoreConfiguration SPI.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/FontCache.cpp (213340 => 213341)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/FontCache.cpp	2017-03-03 02:45:28 UTC (rev 213340)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/FontCache.cpp	2017-03-03 03:17:35 UTC (rev 213341)
@@ -56,7 +56,7 @@
     description.setOneFamily(familyNameString);
     description.setWeight(weight);
     description.setItalic(italic);
-    description.setStretch(stretch);
+    description.setStretch(FontSelectionValue(stretch));
     description.setComputedSize(size);
 
     auto& fontCache = FontCache::singleton();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to