Changeset 225769 in webkit


Ignore:
Timestamp:
Dec 11, 2017, 7:50:06 PM (7 years ago)
Author:
Darin Adler
Message:

Improve FontSelectionAlgorithm, including moving from IntegerHasher to Hasher
https://bugs.webkit.org/show_bug.cgi?id=180340

Reviewed by Dan Bates.

  • css/CSSFontFaceSet.h: Moved FontSelectionRequestKey and FontSelectionRequestKeyHash

here to be private members, and used a std::optional instead of a class for this.
Also use the new Hasher to compute the hash. Also added FontSelectionRequestKeyHashTraits.

  • platform/graphics/FontDescription.cpp:

(WebCore::FontDescription::FontDescription): Updated since FontSelectionRequest
does not always have a constructor any more.

  • platform/graphics/FontSelectionAlgorithm.h: Tweaked comments. Used "using" instead

of typedef. Formatted some trivial functions as single lines. Stopped using
NeverDestroyed for simple classes like FontSelectionValue; it's not needed unless
there is a destructor. Got rid of some incorrect use of const. Replaced some member
functions with non-member functions. Moved some function bodies out of class definitions.
Used a lot of constexpr functions.
(WebCore::FontSelectionRequest::tied const): Added so we can easily write both == and the
hash function without listing the data members.
(WebCore::add): Added an overload so we can hash things that include FontSelectionRequest.
(WebCore::FontSelectionRequestKey::FontSelectionRequestKey): Changed this class to
use std::optional instead of a separate boolean for deleted values.
(WebCore::FontSelectionRequestKey::isHashTableDeletedValue const): Ditto.
(WebCore::FontSelectionRequestKey::operator== const): Ditto.
(WebCore::FontSelectionRequestKeyHash::hash): Ditto.
(WebCore::FontSelectionRequestKeyHash::equal): Ditto.
(WebCore::FontSelectionCapabilities::tied const): Added so we can easily write both ==
and the hash function without listing the data members.
(WebCore::FontSelectionSpecifiedCapabilities::tied const): Ditto.
(WebCore::FontSelectionAlgorithm::FontSelectionAlgorithm): Use make_unique instead of new.

  • platform/graphics/cocoa/FontCacheCoreText.cpp:

(WebCore::findClosestFont): Move in the vector instead of copying it when creating a
FontSelectionAlgorithm object.

Location:
trunk/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r225766 r225769  
     12017-12-11  Darin Adler  <darin@apple.com>
     2
     3        Improve FontSelectionAlgorithm, including moving from IntegerHasher to Hasher
     4        https://bugs.webkit.org/show_bug.cgi?id=180340
     5
     6        Reviewed by Dan Bates.
     7
     8        * css/CSSFontFaceSet.h: Moved FontSelectionRequestKey and FontSelectionRequestKeyHash
     9        here to be private members, and used a std::optional instead of a class for this.
     10        Also use the new Hasher to compute the hash. Also added FontSelectionRequestKeyHashTraits.
     11
     12        * platform/graphics/FontDescription.cpp:
     13        (WebCore::FontDescription::FontDescription): Updated since FontSelectionRequest
     14        does not always have a constructor any more.
     15
     16        * platform/graphics/FontSelectionAlgorithm.h: Tweaked comments. Used "using" instead
     17        of typedef. Formatted some trivial functions as single lines. Stopped using
     18        NeverDestroyed for simple classes like FontSelectionValue; it's not needed unless
     19        there is a destructor. Got rid of some incorrect use of const. Replaced some member
     20        functions with non-member functions. Moved some function bodies out of class definitions.
     21        Used a lot of constexpr functions.
     22        (WebCore::FontSelectionRequest::tied const): Added so we can easily write both == and the
     23        hash function without listing the data members.
     24        (WebCore::add): Added an overload so we can hash things that include FontSelectionRequest.
     25        (WebCore::FontSelectionRequestKey::FontSelectionRequestKey): Changed this class to
     26        use std::optional instead of a separate boolean for deleted values.
     27        (WebCore::FontSelectionRequestKey::isHashTableDeletedValue const): Ditto.
     28        (WebCore::FontSelectionRequestKey::operator== const): Ditto.
     29        (WebCore::FontSelectionRequestKeyHash::hash): Ditto.
     30        (WebCore::FontSelectionRequestKeyHash::equal): Ditto.
     31        (WebCore::FontSelectionCapabilities::tied const): Added so we can easily write both ==
     32        and the hash function without listing the data members.
     33        (WebCore::FontSelectionSpecifiedCapabilities::tied const): Ditto.
     34        (WebCore::FontSelectionAlgorithm::FontSelectionAlgorithm): Use make_unique instead of new.
     35
     36        * platform/graphics/cocoa/FontCacheCoreText.cpp:
     37        (WebCore::findClosestFont): Move in the vector instead of copying it when creating a
     38        FontSelectionAlgorithm object.
     39
    1402017-12-11  Jer Noble  <jer.noble@apple.com>
    241
  • trunk/Source/WebCore/css/CSSFontFaceSet.h

    r225414 r225769  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9898    static String familyNameFromPrimitive(const CSSPrimitiveValue&);
    9999
     100    using FontSelectionKey = std::optional<FontSelectionRequest>;
     101    struct FontSelectionKeyHash {
     102        static unsigned hash(const FontSelectionKey& key) { return computeHash(key); }
     103        static bool equal(const FontSelectionKey& a, const FontSelectionKey& b) { return a == b; }
     104        static const bool safeToCompareToEmptyOrDeleted = true;
     105    };
     106    struct FontSelectionKeyHashTraits : SimpleClassHashTraits<FontSelectionKey> {
     107        static const bool emptyValueIsZero = false;
     108        static FontSelectionKey emptyValue() { return FontSelectionRequest { }; }
     109        static void constructDeletedValue(FontSelectionKey& slot) { slot = std::nullopt; }
     110        static bool isDeletedValue(const FontSelectionKey& value) { return !value; }
     111    };
     112    using FontSelectionHashMap = HashMap<FontSelectionKey, RefPtr<CSSSegmentedFontFace>, FontSelectionKeyHash, FontSelectionKeyHashTraits>;
     113
    100114    // m_faces should hold all the same fonts as the ones inside inside m_facesLookupTable.
    101115    Vector<Ref<CSSFontFace>> m_faces; // We should investigate moving m_faces to FontFaceSet and making it reference FontFaces. This may clean up the font loading design.
    102116    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_facesLookupTable;
    103117    HashMap<String, Vector<Ref<CSSFontFace>>, ASCIICaseInsensitiveHash> m_locallyInstalledFacesLookupTable;
    104     typedef HashMap<FontSelectionRequestKey, RefPtr<CSSSegmentedFontFace>, FontSelectionRequestKeyHash, WTF::SimpleClassHashTraits<FontSelectionRequestKey>> FontSelectionHashMap;
    105118    HashMap<String, FontSelectionHashMap, ASCIICaseInsensitiveHash> m_cache;
    106119    HashMap<StyleRuleFontFace*, CSSFontFace*> m_constituentCSSConnections;
  • trunk/Source/WebCore/platform/graphics/FontDescription.cpp

    r225641 r225769  
    5656
    5757FontDescription::FontDescription()
    58     : m_fontSelectionRequest(FontCascadeDescription::initialWeight(), FontCascadeDescription::initialStretch(), FontCascadeDescription::initialItalic())
     58    : m_fontSelectionRequest { FontCascadeDescription::initialWeight(), FontCascadeDescription::initialStretch(), FontCascadeDescription::initialItalic() }
    5959    , m_orientation(Horizontal)
    6060    , m_nonCJKGlyphOrientation(static_cast<unsigned>(NonCJKGlyphOrientation::Mixed))
  • trunk/Source/WebCore/platform/graphics/FontSelectionAlgorithm.cpp

    r221630 r225769  
    2929namespace WebCore {
    3030
    31 auto FontSelectionAlgorithm::stretchDistance(FontSelectionCapabilities capabilities) const -> DistanceResult
     31FontSelectionAlgorithm::FontSelectionAlgorithm(FontSelectionRequest request, const Vector<Capabilities>& capabilities, std::optional<Capabilities> bounds)
     32    : m_request(request)
     33    , m_capabilities(capabilities)
     34{
     35    ASSERT(!m_capabilities.isEmpty());
     36    if (bounds)
     37        m_capabilitiesBounds = bounds.value();
     38    else {
     39        for (auto& capabilities : m_capabilities)
     40            m_capabilitiesBounds.expand(capabilities);
     41    }
     42}
     43
     44auto FontSelectionAlgorithm::stretchDistance(Capabilities capabilities) const -> DistanceResult
    3245{
    3346    auto width = capabilities.width;
     
    5164}
    5265
    53 auto FontSelectionAlgorithm::styleDistance(FontSelectionCapabilities capabilities) const -> DistanceResult
     66auto FontSelectionAlgorithm::styleDistance(Capabilities capabilities) const -> DistanceResult
    5467{
    5568    auto slope = capabilities.slope;
     
    93106}
    94107
    95 auto FontSelectionAlgorithm::weightDistance(FontSelectionCapabilities capabilities) const -> DistanceResult
     108auto FontSelectionAlgorithm::weightDistance(Capabilities capabilities) const -> DistanceResult
    96109{
    97110    auto weight = capabilities.weight;
     
    124137}
    125138
    126 void FontSelectionAlgorithm::filterCapability(DistanceResult(FontSelectionAlgorithm::*computeDistance)(FontSelectionCapabilities) const, FontSelectionRange FontSelectionCapabilities::*inclusionRange)
     139FontSelectionValue FontSelectionAlgorithm::bestValue(const bool eliminated[], DistanceFunction computeDistance) const
    127140{
    128     std::optional<FontSelectionValue> smallestDistance;
    129     FontSelectionValue closestValue;
    130     iterateActiveCapabilities([&](FontSelectionCapabilities capabilities, size_t) {
    131         auto distanceResult = (this->*computeDistance)(capabilities);
    132         if (!smallestDistance || distanceResult.distance < smallestDistance.value()) {
    133             smallestDistance = distanceResult.distance;
    134             closestValue = distanceResult.value;
    135         }
    136     });
    137     ASSERT(smallestDistance);
    138     iterateActiveCapabilities([&](auto& capabilities, size_t i) {
    139         if (!(capabilities.*inclusionRange).includes(closestValue))
    140             m_filter[i] = false;
    141     });
     141    std::optional<DistanceResult> smallestDistance;
     142    for (size_t i = 0, size = m_capabilities.size(); i < size; ++i) {
     143        if (eliminated[i])
     144            continue;
     145        auto distanceResult = (this->*computeDistance)(m_capabilities[i]);
     146        if (!smallestDistance || distanceResult.distance < smallestDistance.value().distance)
     147            smallestDistance = distanceResult;
     148    }
     149    return smallestDistance.value().value;
     150}
     151
     152void FontSelectionAlgorithm::filterCapability(bool eliminated[], DistanceFunction computeDistance, CapabilitiesRange inclusionRange)
     153{
     154    auto value = bestValue(eliminated, computeDistance);
     155    for (size_t i = 0, size = m_capabilities.size(); i < size; ++i) {
     156        eliminated[i] = eliminated[i]
     157            || !(m_capabilities[i].*inclusionRange).includes(value);
     158    }
    142159}
    143160
    144161size_t FontSelectionAlgorithm::indexOfBestCapabilities()
    145162{
    146     filterCapability(&FontSelectionAlgorithm::stretchDistance, &FontSelectionCapabilities::width);
    147     filterCapability(&FontSelectionAlgorithm::styleDistance, &FontSelectionCapabilities::slope);
    148     filterCapability(&FontSelectionAlgorithm::weightDistance, &FontSelectionCapabilities::weight);
    149 
    150     auto result = iterateActiveCapabilitiesWithReturn<size_t>([](FontSelectionCapabilities, size_t i) {
    151         return i;
    152     });
    153     ASSERT(result);
    154     return result.value_or(0);
     163    Vector<bool, 256> eliminated(m_capabilities.size(), false);
     164    filterCapability(eliminated.data(), &FontSelectionAlgorithm::stretchDistance, &Capabilities::width);
     165    filterCapability(eliminated.data(), &FontSelectionAlgorithm::styleDistance, &Capabilities::slope);
     166    filterCapability(eliminated.data(), &FontSelectionAlgorithm::weightDistance, &Capabilities::weight);
     167    return eliminated.find(false);
    155168}
    156169
  • trunk/Source/WebCore/platform/graphics/FontSelectionAlgorithm.h

    r221630 r225769  
    2727
    2828#include "TextFlags.h"
    29 #include <wtf/Function.h>
    30 #include <wtf/GetPtr.h>
     29#include <algorithm>
     30#include <tuple>
    3131#include <wtf/Hasher.h>
    32 #include <wtf/NeverDestroyed.h>
    3332#include <wtf/Optional.h>
    34 #include <wtf/Vector.h>
    3533
    3634namespace WebCore {
    3735
    3836// Unclamped, unchecked, signed fixed-point number representing a value used for font variations.
    39 // Sixteen bits in total, one sign bit, two fractional bits, means the smallest positive representable value is 0.25,
    40 // the maximum representable value is 8191.75, and the minimum representable value is -8192.
     37// Sixteen bits in total, one sign bit, two fractional bits, smallest positive value is 0.25,
     38// maximum value is 8191.75, and minimum value is -8192.
    4139class FontSelectionValue {
    4240public:
    43     typedef int16_t BackingType;
     41    using BackingType = int16_t;
    4442
    4543    FontSelectionValue() = default;
    4644
    47     // Explicit because it is lossy.
    48     explicit FontSelectionValue(int x)
    49         : m_backing(x * fractionalEntropy)
    50     {
    51     }
    52 
    53     // Explicit because it is lossy.
    54     explicit FontSelectionValue(float x)
    55         : m_backing(x * fractionalEntropy)
    56     {
    57     }
    58 
    59     operator float() const
    60     {
    61         // floats have 23 fractional bits, but only 14 fractional bits are necessary, so every value can be represented losslessly.
    62         return m_backing / static_cast<float>(fractionalEntropy);
    63     }
    64 
    65     FontSelectionValue operator+(const FontSelectionValue other) const;
    66     FontSelectionValue operator-(const FontSelectionValue other) const;
    67     FontSelectionValue operator*(const FontSelectionValue other) const;
    68     FontSelectionValue operator/(const FontSelectionValue other) const;
    69     FontSelectionValue operator-() const;
    70     bool operator==(const FontSelectionValue other) const;
    71     bool operator!=(const FontSelectionValue other) const;
    72     bool operator<(const FontSelectionValue other) const;
    73     bool operator<=(const FontSelectionValue other) const;
    74     bool operator>(const FontSelectionValue other) const;
    75     bool operator>=(const FontSelectionValue other) const;
    76 
    77     BackingType rawValue() const
    78     {
    79         return m_backing;
    80     }
    81 
    82     static FontSelectionValue maximumValue()
    83     {
    84         static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<BackingType>::max(), RawTag::RawTag);
    85         return result.get();
    86     }
    87 
    88     static FontSelectionValue minimumValue()
    89     {
    90         static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<BackingType>::min(), RawTag::RawTag);
    91         return result.get();
    92     }
    93 
    94     static FontSelectionValue clampFloat(float value)
    95     {
    96         if (value < static_cast<float>(FontSelectionValue::minimumValue()))
    97             return FontSelectionValue::minimumValue();
    98         if (value > static_cast<float>(FontSelectionValue::maximumValue()))
    99             return FontSelectionValue::maximumValue();
    100         return FontSelectionValue(value);
    101     }
     45    // Explicit because it won't work correctly for values outside the representable range.
     46    explicit constexpr FontSelectionValue(int);
     47
     48    // Explicit because it won't work correctly for values outside the representable range and because precision can be lost.
     49    explicit constexpr FontSelectionValue(float);
     50
     51    // Precision can be lost, but value will be clamped to the representable range.
     52    static constexpr FontSelectionValue clampFloat(float);
     53
     54    // Since floats have 23 mantissa bits, every value can be represented losslessly.
     55    constexpr operator float() const;
     56
     57    static constexpr FontSelectionValue maximumValue();
     58    static constexpr FontSelectionValue minimumValue();
     59
     60    friend constexpr FontSelectionValue operator+(FontSelectionValue, FontSelectionValue);
     61    friend constexpr FontSelectionValue operator-(FontSelectionValue, FontSelectionValue);
     62    friend constexpr FontSelectionValue operator*(FontSelectionValue, FontSelectionValue);
     63    friend constexpr FontSelectionValue operator/(FontSelectionValue, FontSelectionValue);
     64    friend constexpr FontSelectionValue operator-(FontSelectionValue);
     65
     66    constexpr BackingType rawValue() const { return m_backing; }
    10267
    10368private:
    10469    enum class RawTag { RawTag };
    105 
    106     FontSelectionValue(BackingType rawValue, RawTag)
    107         : m_backing(rawValue)
    108     {
    109     }
     70    constexpr FontSelectionValue(int, RawTag);
    11071
    11172    static constexpr int fractionalEntropy = 4;
     
    11374};
    11475
    115 inline FontSelectionValue FontSelectionValue::operator+(const FontSelectionValue other) const
    116 {
    117     return FontSelectionValue(m_backing + other.m_backing, RawTag::RawTag);
    118 }
    119 
    120 inline FontSelectionValue FontSelectionValue::operator-(const FontSelectionValue other) const
    121 {
    122     return FontSelectionValue(m_backing - other.m_backing, RawTag::RawTag);
    123 }
    124 
    125 inline FontSelectionValue FontSelectionValue::operator*(const FontSelectionValue other) const
    126 {
    127     return FontSelectionValue(static_cast<int32_t>(m_backing) * other.m_backing / fractionalEntropy, RawTag::RawTag);
    128 }
    129 
    130 inline FontSelectionValue FontSelectionValue::operator/(const FontSelectionValue other) const
    131 {
    132     return FontSelectionValue(static_cast<int32_t>(m_backing) / other.m_backing * fractionalEntropy, RawTag::RawTag);
    133 }
    134 
    135 inline FontSelectionValue FontSelectionValue::operator-() const
    136 {
    137     return FontSelectionValue(-m_backing, RawTag::RawTag);
    138 }
    139 
    140 inline bool FontSelectionValue::operator==(const FontSelectionValue other) const
    141 {
    142     return m_backing == other.m_backing;
    143 }
    144 
    145 inline bool FontSelectionValue::operator!=(const FontSelectionValue other) const
    146 {
    147     return !operator==(other);
    148 }
    149 
    150 inline bool FontSelectionValue::operator<(const FontSelectionValue other) const
    151 {
    152     return m_backing < other.m_backing;
    153 }
    154 
    155 inline bool FontSelectionValue::operator<=(const FontSelectionValue other) const
    156 {
    157     return m_backing <= other.m_backing;
    158 }
    159 
    160 inline bool FontSelectionValue::operator>(const FontSelectionValue other) const
    161 {
    162     return m_backing > other.m_backing;
    163 }
    164 
    165 inline bool FontSelectionValue::operator>=(const FontSelectionValue other) const
    166 {
    167     return m_backing >= other.m_backing;
    168 }
    169 
    170 static inline FontSelectionValue italicThreshold()
    171 {
    172     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(20);
    173     return result.get();
    174 }
    175 
    176 static inline bool isItalic(FontSelectionValue fontWeight)
     76constexpr FontSelectionValue::FontSelectionValue(int x)
     77    : m_backing(x * fractionalEntropy)
     78{
     79    // FIXME: Should we assert the passed in value was in range?
     80}
     81
     82constexpr FontSelectionValue::FontSelectionValue(float x)
     83    : m_backing(x * fractionalEntropy)
     84{
     85    // FIXME: Should we assert the passed in value was in range?
     86}
     87
     88constexpr FontSelectionValue::operator float() const
     89{
     90    return m_backing / static_cast<float>(fractionalEntropy);
     91}
     92
     93constexpr FontSelectionValue FontSelectionValue::maximumValue()
     94{
     95    return { std::numeric_limits<BackingType>::max(), RawTag::RawTag };
     96}
     97
     98constexpr FontSelectionValue FontSelectionValue::minimumValue()
     99{
     100    return { std::numeric_limits<BackingType>::min(), RawTag::RawTag };
     101}
     102
     103constexpr FontSelectionValue FontSelectionValue::clampFloat(float value)
     104{
     105    return FontSelectionValue { std::max<float>(minimumValue(), std::min<float>(value, maximumValue())) };
     106}
     107
     108constexpr FontSelectionValue::FontSelectionValue(int rawValue, RawTag)
     109    : m_backing(rawValue)
     110{
     111}
     112
     113constexpr FontSelectionValue operator+(FontSelectionValue a, FontSelectionValue b)
     114{
     115    return { a.m_backing + b.m_backing, FontSelectionValue::RawTag::RawTag };
     116}
     117
     118constexpr FontSelectionValue operator-(FontSelectionValue a, FontSelectionValue b)
     119{
     120    return { a.m_backing - b.m_backing, FontSelectionValue::RawTag::RawTag };
     121}
     122
     123constexpr FontSelectionValue operator*(FontSelectionValue a, FontSelectionValue b)
     124{
     125    return { a.m_backing * b.m_backing / FontSelectionValue::fractionalEntropy, FontSelectionValue::RawTag::RawTag };
     126}
     127
     128constexpr FontSelectionValue operator/(FontSelectionValue a, FontSelectionValue b)
     129{
     130    return { a.m_backing * FontSelectionValue::fractionalEntropy / b.m_backing, FontSelectionValue::RawTag::RawTag };
     131}
     132
     133constexpr FontSelectionValue operator-(FontSelectionValue value)
     134{
     135    return { -value.m_backing, FontSelectionValue::RawTag::RawTag };
     136}
     137
     138constexpr bool operator==(FontSelectionValue a, FontSelectionValue b)
     139{
     140    return a.rawValue() == b.rawValue();
     141}
     142
     143constexpr bool operator!=(FontSelectionValue a, FontSelectionValue b)
     144{
     145    return a.rawValue() != b.rawValue();
     146}
     147
     148constexpr bool operator<(FontSelectionValue a, FontSelectionValue b)
     149{
     150    return a.rawValue() < b.rawValue();
     151}
     152
     153constexpr bool operator<=(FontSelectionValue a, FontSelectionValue b)
     154{
     155    return a.rawValue() <= b.rawValue();
     156}
     157
     158constexpr bool operator>(FontSelectionValue a, FontSelectionValue b)
     159{
     160    return a.rawValue() > b.rawValue();
     161}
     162
     163constexpr bool operator>=(FontSelectionValue a, FontSelectionValue b)
     164{
     165    return a.rawValue() >= b.rawValue();
     166}
     167
     168constexpr FontSelectionValue italicThreshold()
     169{
     170    return FontSelectionValue { 20 };
     171}
     172
     173constexpr bool isItalic(FontSelectionValue fontWeight)
    177174{
    178175    return fontWeight >= italicThreshold();
    179176}
    180177
    181 static inline FontSelectionValue normalItalicValue()
    182 {
    183     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue();
    184     return result.get();
    185 }
    186 
    187 static inline FontSelectionValue italicValue()
    188 {
    189     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(20);
    190     return result.get();
    191 }
    192 
    193 static inline FontSelectionValue boldThreshold()
    194 {
    195     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(600);
    196     return result.get();
    197 }
    198 
    199 static inline FontSelectionValue boldWeightValue()
    200 {
    201     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(700);
    202     return result.get();
    203 }
    204 
    205 static inline FontSelectionValue normalWeightValue()
    206 {
    207     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(400);
    208     return result.get();
    209 }
    210 
    211 static inline FontSelectionValue lightWeightValue()
    212 {
    213     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(200);
    214     return result.get();
    215 }
    216 
    217 static inline bool isFontWeightBold(FontSelectionValue fontWeight)
     178constexpr FontSelectionValue normalItalicValue()
     179{
     180    return FontSelectionValue { 0 };
     181}
     182
     183constexpr FontSelectionValue italicValue()
     184{
     185    return FontSelectionValue { 20 };
     186}
     187
     188constexpr FontSelectionValue boldThreshold()
     189{
     190    return FontSelectionValue { 600 };
     191}
     192
     193constexpr FontSelectionValue boldWeightValue()
     194{
     195    return FontSelectionValue { 700 };
     196}
     197
     198constexpr FontSelectionValue normalWeightValue()
     199{
     200    return FontSelectionValue { 400 };
     201}
     202
     203constexpr FontSelectionValue lightWeightValue()
     204{
     205    return FontSelectionValue { 200 };
     206}
     207
     208constexpr bool isFontWeightBold(FontSelectionValue fontWeight)
    218209{
    219210    return fontWeight >= boldThreshold();
    220211}
    221212
    222 static inline FontSelectionValue lowerWeightSearchThreshold()
    223 {
    224     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(400);
    225     return result.get();
    226 }
    227 
    228 static inline FontSelectionValue upperWeightSearchThreshold()
    229 {
    230     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(500);
    231     return result.get();
    232 }
    233 
    234 static inline FontSelectionValue ultraCondensedStretchValue()
    235 {
    236     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(50);
    237     return result.get();
    238 }
    239 
    240 static inline FontSelectionValue extraCondensedStretchValue()
    241 {
    242     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(62.5f);
    243     return result.get();
    244 }
    245 
    246 static inline FontSelectionValue condensedStretchValue()
    247 {
    248     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(75);
    249     return result.get();
    250 }
    251 
    252 static inline FontSelectionValue semiCondensedStretchValue()
    253 {
    254     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(87.5f);
    255     return result.get();
    256 }
    257 
    258 static inline FontSelectionValue normalStretchValue()
    259 {
    260     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(100);
    261     return result.get();
    262 }
    263 
    264 static inline FontSelectionValue semiExpandedStretchValue()
    265 {
    266     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(112.5f);
    267     return result.get();
    268 }
    269 
    270 static inline FontSelectionValue expandedStretchValue()
    271 {
    272     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(125);
    273     return result.get();
    274 }
    275 
    276 static inline FontSelectionValue extraExpandedStretchValue()
    277 {
    278     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(150);
    279     return result.get();
    280 }
    281 
    282 static inline FontSelectionValue ultraExpandedStretchValue()
    283 {
    284     static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(200);
    285     return result.get();
     213constexpr FontSelectionValue lowerWeightSearchThreshold()
     214{
     215    return FontSelectionValue { 400 };
     216}
     217
     218constexpr FontSelectionValue upperWeightSearchThreshold()
     219{
     220    return FontSelectionValue { 500 };
     221}
     222
     223constexpr FontSelectionValue ultraCondensedStretchValue()
     224{
     225    return FontSelectionValue { 50 };
     226}
     227
     228constexpr FontSelectionValue extraCondensedStretchValue()
     229{
     230    return FontSelectionValue { 62.5f };
     231}
     232
     233constexpr FontSelectionValue condensedStretchValue()
     234{
     235    return FontSelectionValue { 75 };
     236}
     237
     238constexpr FontSelectionValue semiCondensedStretchValue()
     239{
     240    return FontSelectionValue { 87.5f };
     241}
     242
     243constexpr FontSelectionValue normalStretchValue()
     244{
     245    return FontSelectionValue { 100 };
     246}
     247
     248constexpr FontSelectionValue semiExpandedStretchValue()
     249{
     250    return FontSelectionValue { 112.5f };
     251}
     252
     253constexpr FontSelectionValue expandedStretchValue()
     254{
     255    return FontSelectionValue { 125 };
     256}
     257
     258constexpr FontSelectionValue extraExpandedStretchValue()
     259{
     260    return FontSelectionValue { 150 };
     261}
     262
     263constexpr FontSelectionValue ultraExpandedStretchValue()
     264{
     265    return FontSelectionValue { 200 };
    286266}
    287267
    288268// [Inclusive, Inclusive]
    289269struct FontSelectionRange {
    290     FontSelectionRange(FontSelectionValue minimum, FontSelectionValue maximum)
     270    using Value = FontSelectionValue;
     271
     272    constexpr FontSelectionRange(Value minimum, Value maximum)
    291273        : minimum(minimum)
    292274        , maximum(maximum)
     
    294276    }
    295277
    296     bool operator==(const FontSelectionRange& other) const
    297     {
    298         return minimum == other.minimum
    299             && maximum == other.maximum;
    300     }
    301 
    302     bool isValid() const
     278    explicit constexpr FontSelectionRange(Value value)
     279        : minimum(value)
     280        , maximum(value)
     281    {
     282    }
     283
     284    constexpr bool operator==(const FontSelectionRange& other) const
     285    {
     286        return std::tie(minimum, maximum) == std::tie(other.minimum, other.maximum);
     287    }
     288
     289    constexpr bool isValid() const
    303290    {
    304291        return minimum <= maximum;
     
    317304    }
    318305
    319     bool includes(FontSelectionValue target) const
     306    constexpr bool includes(Value target) const
    320307    {
    321308        return target >= minimum && target <= maximum;
    322309    }
    323310
    324     uint32_t uniqueValue() const
     311    // FIXME: This name is not so great. Move this into the add function below
     312    // once we move FontPlatformDataCacheKeyHash from IntegerHasher to Hasher,
     313    // and then it doesn't need to have a name.
     314    constexpr uint32_t uniqueValue() const
    325315    {
    326316        return minimum.rawValue() << 16 | maximum.rawValue();
    327317    }
    328318
    329     FontSelectionValue minimum { FontSelectionValue(1) };
    330     FontSelectionValue maximum { FontSelectionValue(0) };
    331 };
     319    Value minimum { 1 };
     320    Value maximum { 0 };
     321};
     322
     323inline void add(Hasher& hasher, const FontSelectionRange& range)
     324{
     325    add(hasher, range.uniqueValue());
     326}
    332327
    333328struct FontSelectionRequest {
     329    using Value = FontSelectionValue;
     330
     331    Value weight;
     332    Value width;
     333    Value slope;
     334
     335    constexpr std::tuple<Value, Value, Value> tied() const
     336    {
     337        return std::tie(weight, width, slope);
     338    }
     339
     340#if !COMPILER_SUPPORTS(NSDMI_FOR_AGGREGATES)
    334341    FontSelectionRequest() = default;
    335342
    336     FontSelectionRequest(FontSelectionValue weight, FontSelectionValue width, FontSelectionValue slope)
     343    constexpr FontSelectionRequest(Value weight, Value width, Value slope)
    337344        : weight(weight)
    338345        , width(width)
     
    340347    {
    341348    }
    342 
    343     bool operator==(const FontSelectionRequest& other) const
    344     {
    345         return weight == other.weight
    346             && width == other.width
    347             && slope == other.slope;
    348     }
    349 
    350     bool operator!=(const FontSelectionRequest& other) const
    351     {
    352         return !operator==(other);
    353     }
    354 
    355     FontSelectionValue weight;
    356     FontSelectionValue width;
    357     FontSelectionValue slope;
    358 };
    359 
    360 // Only used for HashMaps. We don't want to put the bool into FontSelectionRequest
    361 // because FontSelectionRequest needs to be as small as possible because it's inside
    362 // every FontDescription.
    363 struct FontSelectionRequestKey {
    364     FontSelectionRequestKey() = default;
    365 
    366     FontSelectionRequestKey(FontSelectionRequest request)
    367         : request(request)
    368     {
    369     }
    370 
    371     explicit FontSelectionRequestKey(WTF::HashTableDeletedValueType)
    372         : isDeletedValue(true)
    373     {
    374     }
    375 
    376     bool isHashTableDeletedValue() const
    377     {
    378         return isDeletedValue;
    379     }
    380 
    381     bool operator==(const FontSelectionRequestKey& other) const
    382     {
    383         return request == other.request
    384             && isDeletedValue == other.isDeletedValue;
    385     }
    386 
    387     FontSelectionRequest request;
    388     bool isDeletedValue { false };
    389 };
    390 
    391 struct FontSelectionRequestKeyHash {
    392     static unsigned hash(const FontSelectionRequestKey& key)
    393     {
    394         IntegerHasher hasher;
    395         hasher.add(key.request.weight.rawValue());
    396         hasher.add(key.request.width.rawValue());
    397         hasher.add(key.request.slope.rawValue());
    398         hasher.add(key.isDeletedValue);
    399         return hasher.hash();
    400     }
    401 
    402     static bool equal(const FontSelectionRequestKey& a, const FontSelectionRequestKey& b)
    403     {
    404         return a == b;
    405     }
    406 
    407     static const bool safeToCompareToEmptyOrDeleted = true;
    408 };
     349#endif
     350};
     351
     352constexpr bool operator==(const FontSelectionRequest& a, const FontSelectionRequest& b)
     353{
     354    return a.tied() == b.tied();
     355}
     356
     357constexpr bool operator!=(const FontSelectionRequest& a, const FontSelectionRequest& b)
     358{
     359    return !(a == b);
     360}
     361
     362inline void add(Hasher& hasher, const FontSelectionRequest& request)
     363{
     364    add(hasher, request.tied());
     365}
    409366
    410367struct FontSelectionCapabilities {
    411     FontSelectionCapabilities()
    412     {
    413     }
    414 
    415     FontSelectionCapabilities(FontSelectionRange weight, FontSelectionRange width, FontSelectionRange slope)
     368    using Range = FontSelectionRange;
     369
     370    FontSelectionCapabilities& operator=(const FontSelectionCapabilities&) = default;
     371
     372    constexpr std::tuple<Range, Range, Range> tied() const
     373    {
     374        return std::tie(weight, width, slope);
     375    }
     376
     377    void expand(const FontSelectionCapabilities& capabilities)
     378    {
     379        weight.expand(capabilities.weight);
     380        width.expand(capabilities.width);
     381        slope.expand(capabilities.slope);
     382    }
     383
     384    Range weight { normalWeightValue() };
     385    Range width { normalStretchValue() };
     386    Range slope { normalItalicValue() };
     387
     388#if !COMPILER_SUPPORTS(NSDMI_FOR_AGGREGATES)
     389    FontSelectionCapabilities() = default;
     390
     391    constexpr FontSelectionCapabilities(Range weight, Range width, Range slope)
    416392        : weight(weight)
    417393        , width(width)
     
    419395    {
    420396    }
    421 
    422     void expand(const FontSelectionCapabilities& capabilities)
    423     {
    424         weight.expand(capabilities.weight);
    425         width.expand(capabilities.width);
    426         slope.expand(capabilities.slope);
    427     }
    428 
    429     bool operator==(const FontSelectionCapabilities& other) const
    430     {
    431         return weight == other.weight
    432             && width == other.width
    433             && slope == other.slope;
    434     }
    435 
    436     bool operator!=(const FontSelectionCapabilities& other) const
    437     {
    438         return !(*this == other);
    439     }
    440 
    441     FontSelectionRange weight { normalWeightValue(), normalWeightValue() };
    442     FontSelectionRange width { normalStretchValue(), normalStretchValue() };
    443     FontSelectionRange slope { normalItalicValue(), normalItalicValue() };
    444 };
     397#endif
     398};
     399
     400constexpr bool operator==(const FontSelectionCapabilities& a, const FontSelectionCapabilities& b)
     401{
     402    return a.tied() == b.tied();
     403}
     404
     405constexpr bool operator!=(const FontSelectionCapabilities& a, const FontSelectionCapabilities& b)
     406{
     407    return !(a == b);
     408}
    445409
    446410struct FontSelectionSpecifiedCapabilities {
    447     FontSelectionCapabilities computeFontSelectionCapabilities() const
    448     {
    449         return FontSelectionCapabilities(computeWeight(), computeWidth(), computeSlope());
    450     }
    451 
    452     bool operator==(const FontSelectionSpecifiedCapabilities& other) const
    453     {
    454         return weight == other.weight
    455             && width == other.width
    456             && slope == other.slope;
    457     }
    458 
    459     bool operator!=(const FontSelectionSpecifiedCapabilities& other) const
    460     {
    461         return !(*this == other);
    462     }
    463 
    464     FontSelectionSpecifiedCapabilities& operator=(const FontSelectionCapabilities& other)
    465     {
    466         weight = other.weight;
    467         width = other.width;
    468         slope = other.slope;
     411    using Capabilities = FontSelectionCapabilities;
     412    using Range = FontSelectionRange;
     413    using OptionalRange = std::optional<Range>;
     414
     415    constexpr Capabilities computeFontSelectionCapabilities() const
     416    {
     417        return { computeWeight(), computeWidth(), computeSlope() };
     418    }
     419
     420    constexpr std::tuple<OptionalRange&, OptionalRange&, OptionalRange&> tied()
     421    {
     422        return std::tie(weight, width, slope);
     423    }
     424
     425    constexpr std::tuple<const OptionalRange&, const OptionalRange&, const OptionalRange&> tied() const
     426    {
     427        return std::tie(weight, width, slope);
     428    }
     429
     430    FontSelectionSpecifiedCapabilities& operator=(const Capabilities& other)
     431    {
     432        tied() = other.tied();
    469433        return *this;
    470434    }
    471435
    472     FontSelectionRange computeWeight() const
    473     {
    474         return weight.value_or(FontSelectionRange({ normalWeightValue(), normalWeightValue() }));
    475     }
    476 
    477     FontSelectionRange computeWidth() const
    478     {
    479         return width.value_or(FontSelectionRange({ normalStretchValue(), normalStretchValue() }));
    480     }
    481 
    482     FontSelectionRange computeSlope() const
    483     {
    484         return slope.value_or(FontSelectionRange({ normalItalicValue(), normalItalicValue() }));
    485     }
    486 
    487     std::optional<FontSelectionRange> weight;
    488     std::optional<FontSelectionRange> width;
    489     std::optional<FontSelectionRange> slope;
    490 };
     436    constexpr Range computeWeight() const
     437    {
     438        return weight.value_or(Range { normalWeightValue() });
     439    }
     440
     441    constexpr Range computeWidth() const
     442    {
     443        return width.value_or(Range { normalStretchValue() });
     444    }
     445
     446    constexpr Range computeSlope() const
     447    {
     448        return slope.value_or(Range { normalItalicValue() });
     449    }
     450
     451    OptionalRange weight;
     452    OptionalRange width;
     453    OptionalRange slope;
     454};
     455
     456constexpr bool operator==(const FontSelectionSpecifiedCapabilities& a, const FontSelectionSpecifiedCapabilities& b)
     457{
     458    return a.tied() == b.tied();
     459}
     460
     461constexpr bool operator!=(const FontSelectionSpecifiedCapabilities& a, const FontSelectionSpecifiedCapabilities& b)
     462{
     463    return !(a == b);
     464}
    491465
    492466class FontSelectionAlgorithm {
    493467public:
     468    using Capabilities = FontSelectionCapabilities;
     469
    494470    FontSelectionAlgorithm() = delete;
    495 
    496     FontSelectionAlgorithm(FontSelectionRequest request, const Vector<FontSelectionCapabilities>& capabilities, std::optional<FontSelectionCapabilities> capabilitiesBounds = std::nullopt)
    497         : m_request(request)
    498         , m_capabilities(capabilities)
    499         , m_filter(new bool[m_capabilities.size()])
    500     {
    501         ASSERT(!m_capabilities.isEmpty());
    502         if (capabilitiesBounds)
    503             m_capabilitiesBounds = capabilitiesBounds.value();
    504         else {
    505             for (auto capabilities : m_capabilities)
    506                 m_capabilitiesBounds.expand(capabilities);
    507         }
    508         for (size_t i = 0; i < m_capabilities.size(); ++i)
    509             m_filter[i] = true;
    510     }
     471    FontSelectionAlgorithm(FontSelectionRequest, const Vector<Capabilities>&, std::optional<Capabilities> capabilitiesBounds = std::nullopt);
    511472
    512473    struct DistanceResult {
     
    514475        FontSelectionValue value;
    515476    };
    516 
    517     DistanceResult stretchDistance(FontSelectionCapabilities) const;
    518     DistanceResult styleDistance(FontSelectionCapabilities) const;
    519     DistanceResult weightDistance(FontSelectionCapabilities) const;
     477    DistanceResult stretchDistance(Capabilities) const;
     478    DistanceResult styleDistance(Capabilities) const;
     479    DistanceResult weightDistance(Capabilities) const;
    520480
    521481    size_t indexOfBestCapabilities();
    522482
    523483private:
    524     template <typename T>
    525     using IterateActiveCapabilitiesWithReturnCallback = WTF::Function<std::optional<T>(FontSelectionCapabilities, size_t)>;
    526 
    527     template <typename T>
    528     inline std::optional<T> iterateActiveCapabilitiesWithReturn(const IterateActiveCapabilitiesWithReturnCallback<T>& callback)
    529     {
    530         for (size_t i = 0; i < m_capabilities.size(); ++i) {
    531             if (!m_filter[i])
    532                 continue;
    533             if (auto result = callback(m_capabilities[i], i))
    534                 return result;
    535         }
    536         return std::nullopt;
    537     }
    538 
    539     template <typename T>
    540     inline void iterateActiveCapabilities(T callback)
    541     {
    542         iterateActiveCapabilitiesWithReturn<int>([&](FontSelectionCapabilities capabilities, size_t i) -> std::optional<int> {
    543             callback(capabilities, i);
    544             return std::nullopt;
    545         });
    546     }
    547 
    548     void filterCapability(DistanceResult(FontSelectionAlgorithm::*computeDistance)(FontSelectionCapabilities) const, FontSelectionRange FontSelectionCapabilities::*inclusionRange);
     484    using DistanceFunction = DistanceResult (FontSelectionAlgorithm::*)(Capabilities) const;
     485    using CapabilitiesRange = FontSelectionRange Capabilities::*;
     486    FontSelectionValue bestValue(const bool eliminated[], DistanceFunction) const;
     487    void filterCapability(bool eliminated[], DistanceFunction, CapabilitiesRange);
    549488
    550489    FontSelectionRequest m_request;
    551     FontSelectionCapabilities m_capabilitiesBounds;
    552     const Vector<FontSelectionCapabilities>& m_capabilities;
    553     std::unique_ptr<bool[]> m_filter;
    554 };
    555 
    556 }
     490    Capabilities m_capabilitiesBounds;
     491    const Vector<Capabilities>& m_capabilities;
     492};
     493
     494}
Note: See TracChangeset for help on using the changeset viewer.