Changeset 213341 in webkit
- Timestamp:
- Mar 2, 2017 7:17:35 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r213322 r213341 1 2017-03-02 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Migrate font-stretch to use fixed-point values 4 https://bugs.webkit.org/show_bug.cgi?id=169107 5 6 Reviewed by Dean Jackson. 7 8 There are a few benefits of using fixed-point values: 9 - Not all of the entropy of a float is necessary for font selection. In particular, values are 10 expected to stay between around -1000 to 1000, and only need to have a few fractional bits. 11 Therefore, the values can be represented by 16-bit fixed point numbers, which includes one sign 12 bit and two fractional bits. This is smaller than the 32-bit floating point numbers we were 13 using, which means FontDescription can be slimmed down. This becomes even more important when 14 the rest of the variation font properties are implemented, since those will use these fixed- 15 point values too. 16 - Fixed point values have a larger distance between adjacent representable values, which means 17 there are more collisions, which means our cache hit rates are higher. 18 19 No new tests because there is no behavior change. 20 21 * css/CSSComputedStyleDeclaration.cpp: 22 (WebCore::fontStretchFromStyle): 23 * css/StyleBuilderConverter.h: 24 (WebCore::StyleBuilderConverter::convertFontStretch): 25 * platform/graphics/FontCache.h: 26 (WebCore::FontDescriptionKey::FontDescriptionKey): 27 * platform/graphics/FontDescription.h: 28 (WebCore::FontDescription::stretch): 29 (WebCore::FontDescription::setStretch): 30 (WebCore::FontCascadeDescription::initialStretch): 31 * platform/graphics/cocoa/FontCacheCoreText.cpp: 32 (WebCore::defaultFontSelectionValues): 33 (WebCore::preparePlatformFont): 34 (WebCore::FontDatabase::InstalledFont::InstalledFont): 35 (WebCore::FontDatabase::InstalledFontFamily::expand): 36 (WebCore::FontDatabase::capabilitiesForFontDescriptor): 37 (WebCore::FontDatabase::stretchThreshold): 38 (WebCore::FontDatabase::italicThreshold): 39 (WebCore::FontDatabase::weightThreshold): 40 (WebCore::findClosestStretch): 41 (WebCore::filterStretch): 42 (WebCore::findClosestStyle): 43 (WebCore::filterStyle): 44 (WebCore::findClosestWeight): 45 (WebCore::filterWeight): 46 (WebCore::computeTargetWeight): 47 (WebCore::findClosestFont): 48 (WebCore::platformFontLookupWithFamily): 49 (WebCore::fontWithFamily): 50 (WebCore::defaultVariationValues): Deleted. 51 (WebCore::FontDatabase::Range::Range): Deleted. 52 (WebCore::FontDatabase::Range::isValid): Deleted. 53 (WebCore::FontDatabase::Range::expand): Deleted. 54 (WebCore::FontDatabase::Range::includes): Deleted. 55 (): Deleted. 56 * platform/text/TextFlags.h: 57 (WebCore::FontSelectionValue::FontSelectionValue): 58 (WebCore::FontSelectionValue::operator float): 59 (WebCore::FontSelectionValue::operator+): 60 (WebCore::FontSelectionValue::operator-): 61 (WebCore::FontSelectionValue::operator*): 62 (WebCore::FontSelectionValue::operator/): 63 (WebCore::FontSelectionValue::operator==): 64 (WebCore::FontSelectionValue::operator!=): 65 (WebCore::FontSelectionValue::operator<): 66 (WebCore::FontSelectionValue::operator<=): 67 (WebCore::FontSelectionValue::operator>): 68 (WebCore::FontSelectionValue::operator>=): 69 (WebCore::FontSelectionValue::rawValue): 70 (WebCore::FontSelectionRange::isValid): 71 (WebCore::FontSelectionRange::expand): 72 (WebCore::FontSelectionRange::includes): 73 (WebCore::FontSelectionCapabilities::expand): 74 1 75 2017-03-02 Alex Christensen <achristensen@webkit.org> 2 76 -
trunk/Source/WebCore/css/CSSComputedStyleDeclaration.cpp
r213267 r213341 1922 1922 static Ref<CSSPrimitiveValue> fontStretchFromStyle(const RenderStyle& style) 1923 1923 { 1924 floatstretch = style.fontDescription().stretch();1925 if (stretch == 50)1924 auto stretch = style.fontDescription().stretch(); 1925 if (stretch == FontSelectionValue(50)) 1926 1926 return CSSValuePool::singleton().createIdentifierValue(CSSValueUltraCondensed); 1927 if (stretch == 62.5)1927 if (stretch == FontSelectionValue(62.5f)) 1928 1928 return CSSValuePool::singleton().createIdentifierValue(CSSValueExtraCondensed); 1929 if (stretch == 75)1929 if (stretch == FontSelectionValue(75)) 1930 1930 return CSSValuePool::singleton().createIdentifierValue(CSSValueCondensed); 1931 if (stretch == 87.5)1931 if (stretch == FontSelectionValue(87.5f)) 1932 1932 return CSSValuePool::singleton().createIdentifierValue(CSSValueSemiCondensed); 1933 if (stretch == 100)1933 if (stretch == FontSelectionValue(100)) 1934 1934 return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); 1935 if (stretch == 112.5)1935 if (stretch == FontSelectionValue(112.5f)) 1936 1936 return CSSValuePool::singleton().createIdentifierValue(CSSValueSemiExpanded); 1937 if (stretch == 125)1937 if (stretch == FontSelectionValue(125)) 1938 1938 return CSSValuePool::singleton().createIdentifierValue(CSSValueExpanded); 1939 if (stretch == 150)1939 if (stretch == FontSelectionValue(150)) 1940 1940 return CSSValuePool::singleton().createIdentifierValue(CSSValueExtraExpanded); 1941 if (stretch == 200)1941 if (stretch == FontSelectionValue(200)) 1942 1942 return CSSValuePool::singleton().createIdentifierValue(CSSValueUltraExpanded); 1943 return CSSValuePool::singleton().createValue(st retch, CSSPrimitiveValue::CSS_PERCENTAGE);1943 return CSSValuePool::singleton().createValue(static_cast<float>(stretch), CSSPrimitiveValue::CSS_PERCENTAGE); 1944 1944 } 1945 1945 -
trunk/Source/WebCore/css/StyleBuilderConverter.h
r213267 r213341 115 115 #endif 116 116 static FontFeatureSettings convertFontFeatureSettings(StyleResolver&, const CSSValue&); 117 static floatconvertFontStretch(StyleResolver&, const CSSValue&);117 static FontSelectionValue convertFontStretch(StyleResolver&, const CSSValue&); 118 118 #if ENABLE(VARIATION_FONTS) 119 119 static FontVariationSettings convertFontVariationSettings(StyleResolver&, const CSSValue&); … … 1155 1155 } 1156 1156 1157 inline floatStyleBuilderConverter::convertFontStretch(StyleResolver&, const CSSValue& value)1157 inline FontSelectionValue StyleBuilderConverter::convertFontStretch(StyleResolver&, const CSSValue& value) 1158 1158 { 1159 1159 ASSERT(is<CSSPrimitiveValue>(value)); 1160 1160 const auto& primitiveValue = downcast<CSSPrimitiveValue>(value); 1161 if (primitiveValue.isPercentage() || primitiveValue.isNumber()) 1162 return primitiveValue.floatValue(); 1161 if (primitiveValue.isPercentage() || primitiveValue.isNumber()) { 1162 auto value = primitiveValue.floatValue(); 1163 if (value <= static_cast<float>(FontSelectionValue::maximumValue()) 1164 && value >= static_cast<float>(FontSelectionValue::minimumValue())) 1165 return FontSelectionValue(value); 1166 if (value < static_cast<float>(FontSelectionValue::minimumValue())) 1167 return FontSelectionValue::minimumValue(); 1168 ASSERT(value > static_cast<float>(FontSelectionValue::maximumValue())); 1169 return FontSelectionValue::maximumValue(); 1170 } 1163 1171 1164 1172 switch (primitiveValue.valueID()) { 1165 1173 case CSSValueUltraCondensed: 1166 return 50;1174 return FontSelectionValue(50); 1167 1175 case CSSValueExtraCondensed: 1168 return 62.5;1176 return FontSelectionValue(62.5f); 1169 1177 case CSSValueCondensed: 1170 return 75;1178 return FontSelectionValue(75); 1171 1179 case CSSValueSemiCondensed: 1172 return 87.5;1180 return FontSelectionValue(87.5f); 1173 1181 case CSSValueNormal: 1174 return 100;1182 return FontSelectionValue(100); 1175 1183 case CSSValueSemiExpanded: 1176 return 112.5;1184 return FontSelectionValue(112.5f); 1177 1185 case CSSValueExpanded: 1178 return 125;1186 return FontSelectionValue(125); 1179 1187 case CSSValueExtraExpanded: 1180 return 150;1188 return FontSelectionValue(150); 1181 1189 case CSSValueUltraExpanded: 1182 return 200;1190 return FontSelectionValue(200); 1183 1191 default: 1184 1192 ASSERT_NOT_REACHED(); 1185 return 100;1193 return FontSelectionValue(100); 1186 1194 } 1187 1195 } -
trunk/Source/WebCore/platform/graphics/FontCache.h
r213267 r213341 74 74 : m_size(description.computedPixelSize()) 75 75 , m_weight(description.weight()) 76 , m_stretch(description.stretch())77 76 , m_flags(makeFlagsKey(description)) 78 77 , m_featureSettings(description.featureSettings()) … … 80 79 , m_variationSettings(description.variationSettings()) 81 80 #endif 81 , m_stretch(description.stretch().rawValue()) 82 82 { } 83 83 … … 155 155 unsigned m_size { 0 }; 156 156 unsigned m_weight { 0 }; 157 float m_stretch { 0 };158 157 std::array<unsigned, 2> m_flags {{ 0, 0 }}; 159 158 FontFeatureSettings m_featureSettings; … … 161 160 FontVariationSettings m_variationSettings; 162 161 #endif 162 uint16_t m_stretch { 0 }; 163 163 }; 164 164 -
trunk/Source/WebCore/platform/graphics/FontDescription.h
r213267 r213341 47 47 float computedSize() const { return m_computedSize; } 48 48 FontItalic italic() const { return static_cast<FontItalic>(m_italic); } 49 floatstretch() const { return m_stretch; }49 FontSelectionValue stretch() const { return m_stretch; } 50 50 int computedPixelSize() const { return int(m_computedSize + 0.5f); } 51 51 FontWeight weight() const { return static_cast<FontWeight>(m_weight); } … … 99 99 void setComputedSize(float s) { m_computedSize = clampToFloat(s); } 100 100 void setItalic(FontItalic i) { m_italic = i; } 101 void setStretch( floatstretch) { m_stretch = stretch; }101 void setStretch(FontSelectionValue stretch) { m_stretch = stretch; } 102 102 void setIsItalic(bool i) { setItalic(i ? FontItalicOn : FontItalicOff); } 103 103 void setWeight(FontWeight w) { m_weight = w; } … … 137 137 AtomicString m_locale; 138 138 139 float m_stretch { 100 }; // Stretch, or "width," of the font140 139 float m_computedSize { 0 }; // Computed size adjusted for the minimum font size and the zoom factor. 140 FontSelectionValue m_stretch { 100 }; // Stretch, or "width," of the font 141 141 unsigned m_orientation : 1; // FontOrientation - Whether the font is rendering on a horizontal line or a vertical line. 142 142 unsigned m_nonCJKGlyphOrientation : 1; // NonCJKGlyphOrientation - Only used by vertical text. Determines the default orientation for non-ideograph glyphs. … … 266 266 // Initial values for font properties. 267 267 static FontItalic initialItalic() { return FontItalicOff; } 268 static float initialStretch() { return 100; }268 static FontSelectionValue initialStretch() { return FontSelectionValue(100); } 269 269 static FontSmallCaps initialSmallCaps() { return FontSmallCapsOff; } 270 270 static Kerning initialKerning() { return Kerning::Auto; } -
trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
r213267 r213341 790 790 #if !SHOULD_USE_CORE_TEXT_FONT_LOOKUP 791 791 792 constexpr float stretchThreshold = 100;793 constexpr float italicThreshold = 20;794 constexpr float weightThreshold = 500;795 796 792 class FontDatabase { 797 793 public: … … 805 801 FontDatabase& operator=(const FontDatabase&) = delete; 806 802 807 // [Inclusive, Inclusive]808 struct Range {809 Range()810 {811 ASSERT(!isValid());812 }813 814 Range(float minimum, float maximum)815 : minimum(minimum)816 , maximum(maximum)817 {818 ASSERT(isValid());819 }820 821 bool isValid() const822 {823 return minimum <= maximum;824 }825 826 void expand(const Range& other)827 {828 ASSERT(other.isValid());829 if (!isValid())830 *this = other;831 else {832 minimum = std::min(minimum, other.minimum);833 maximum = std::max(maximum, other.maximum);834 }835 ASSERT(isValid());836 }837 838 bool includes(float target) const839 {840 return target >= minimum && target <= maximum;841 }842 843 float minimum { 1 };844 float maximum { 0 };845 };846 847 803 struct InstalledFont { 848 804 InstalledFont() = default; … … 850 806 InstalledFont(CTFontDescriptorRef fontDescriptor) 851 807 : fontDescriptor(fontDescriptor) 808 , capabilities(capabilitiesForFontDescriptor(fontDescriptor)) 852 809 { 853 if (!fontDescriptor)854 return;855 856 auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute)));857 float width = 0;858 float slant = 0;859 float weight = 0;860 if (traits) {861 auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWidthTrait));862 if (widthNumber) {863 // FIXME: The normalization from Core Text's [-1, 1] range to CSS's [50%, 200%] range isn't perfect.864 float ctWidth;865 auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &ctWidth);866 ASSERT_UNUSED(success, success);867 width = ctWidth < 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50;868 }869 870 auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait));871 if (symbolicTraitsNumber) {872 int32_t symbolicTraits;873 auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits);874 ASSERT_UNUSED(success, success);875 slant = symbolicTraits & kCTFontTraitItalic ? italicThreshold : 0;876 }877 }878 879 auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute)));880 if (weightNumber) {881 auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &weight);882 ASSERT_UNUSED(success, success);883 }884 885 stretch = Range(width, width);886 style = Range(slant, slant);887 this->weight = Range(weight, weight);888 810 } 889 811 890 812 RetainPtr<CTFontDescriptorRef> fontDescriptor; 891 Range stretch; 892 Range style; 893 Range weight; 813 FontSelectionCapabilities capabilities; 894 814 }; 895 815 … … 906 826 void expand(const InstalledFont& installedFont) 907 827 { 908 stretchBounds.expand(installedFont.stretch); 909 styleBounds.expand(installedFont.style); 910 weightBounds.expand(installedFont.weight); 828 capabilities.expand(installedFont.capabilities); 911 829 } 912 830 … … 922 840 923 841 Vector<InstalledFont> installedFonts; 924 Range stretchBounds; 925 Range styleBounds; 926 Range weightBounds; 842 FontSelectionCapabilities capabilities; 927 843 }; 928 844 … … 970 886 } 971 887 888 static FontSelectionCapabilities capabilitiesForFontDescriptor(CTFontDescriptorRef fontDescriptor) 889 { 890 if (!fontDescriptor) 891 return { }; 892 893 auto traits = adoptCF(static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute))); 894 FontSelectionValue width; 895 FontSelectionValue slant; 896 FontSelectionValue weight; 897 if (traits) { 898 auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontWidthTrait)); 899 if (widthNumber) { 900 // FIXME: The normalization from Core Text's [-1, 1] range to CSS's [50%, 200%] range isn't perfect. 901 float ctWidth; 902 auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &ctWidth); 903 ASSERT_UNUSED(success, success); 904 width = FontSelectionValue(ctWidth < 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50); 905 } 906 907 auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait)); 908 if (symbolicTraitsNumber) { 909 int32_t symbolicTraits; 910 auto success = CFNumberGetValue(symbolicTraitsNumber, kCFNumberSInt32Type, &symbolicTraits); 911 ASSERT_UNUSED(success, success); 912 slant = symbolicTraits & kCTFontTraitItalic ? italicThreshold() : FontSelectionValue(); 913 } 914 } 915 916 auto weightNumber = adoptCF(static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontCSSWeightAttribute))); 917 if (weightNumber) { 918 float cssWeight; 919 auto success = CFNumberGetValue(weightNumber.get(), kCFNumberFloatType, &cssWeight); 920 ASSERT_UNUSED(success, success); 921 weight = FontSelectionValue(cssWeight); 922 } 923 924 // FIXME: Educate this function about font variations. 925 926 return { { weight, weight }, { width, width }, { slant, slant } }; 927 } 928 929 static const FontSelectionValue stretchThreshold() 930 { 931 static NeverDestroyed<FontSelectionValue> threshold(100); 932 return threshold.get(); 933 } 934 935 static const FontSelectionValue italicThreshold() 936 { 937 static NeverDestroyed<FontSelectionValue> threshold(20); 938 return threshold.get(); 939 } 940 941 static const FontSelectionValue weightThreshold() 942 { 943 static NeverDestroyed<FontSelectionValue> threshold(500); 944 return threshold.get(); 945 } 946 972 947 private: 973 948 friend class NeverDestroyed<FontDatabase>; … … 1003 978 } 1004 979 1005 static inline std::optional< float> findClosestStretch(floattargetStretch, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)980 static inline std::optional<FontSelectionValue> findClosestStretch(FontSelectionValue targetStretch, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 1006 981 { 1007 982 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 1008 983 1009 if (targetStretch >= stretchThreshold) {1010 float threshold = std::max(targetStretch, installedFonts.stretchBounds.maximum);984 if (targetStretch >= FontDatabase::stretchThreshold()) { 985 auto threshold = std::max(targetStretch, installedFonts.capabilities.width.maximum); 1011 986 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1012 ASSERT(font.stretch.isValid()); 1013 if (font.stretch.includes(targetStretch)) 987 auto width = font.capabilities.width; 988 ASSERT(width.isValid()); 989 if (width.includes(targetStretch)) 1014 990 return 0; 1015 ASSERT( font.stretch.minimum > targetStretch || font.stretch.maximum < targetStretch);1016 if ( font.stretch.minimum > targetStretch)1017 return font.stretch.minimum - targetStretch;1018 ASSERT( font.stretch.maximum < targetStretch);1019 return threshold - font.stretch.maximum;991 ASSERT(width.minimum > targetStretch || width.maximum < targetStretch); 992 if (width.minimum > targetStretch) 993 return width.minimum - targetStretch; 994 ASSERT(width.maximum < targetStretch); 995 return threshold - width.maximum; 1020 996 }; 1021 997 } else { 1022 ASSERT(targetStretch < stretchThreshold);1023 float threshold = std::min(targetStretch, installedFonts.stretchBounds.minimum);998 ASSERT(targetStretch < FontDatabase::stretchThreshold()); 999 auto threshold = std::min(targetStretch, installedFonts.capabilities.width.minimum); 1024 1000 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1025 if (font.stretch.includes(targetStretch)) 1001 auto width = font.capabilities.width; 1002 if (width.includes(targetStretch)) 1026 1003 return 0; 1027 ASSERT( font.stretch.minimum > targetStretch || font.stretch.maximum < targetStretch);1028 if ( font.stretch.maximum < targetStretch)1029 return targetStretch - font.stretch.maximum;1030 ASSERT( font.stretch.minimum > targetStretch);1031 return font.stretch.minimum - threshold;1004 ASSERT(width.minimum > targetStretch || width.maximum < targetStretch); 1005 if (width.maximum < targetStretch) 1006 return targetStretch - width.maximum; 1007 ASSERT(width.minimum > targetStretch); 1008 return width.minimum - threshold; 1032 1009 }; 1033 1010 } … … 1046 1023 return std::nullopt; 1047 1024 auto& winner = installedFonts.installedFonts[closestIndex]; 1048 if (winner.stretch.includes(targetStretch)) 1025 auto width = winner.capabilities.width; 1026 if (width.includes(targetStretch)) 1049 1027 return targetStretch; 1050 if (wi nner.stretch.minimum > targetStretch)1051 return wi nner.stretch.minimum;1052 ASSERT(wi nner.stretch.maximum < targetStretch);1053 return wi nner.stretch.maximum;1054 } 1055 1056 static inline void filterStretch( floattarget, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)1028 if (width.minimum > targetStretch) 1029 return width.minimum; 1030 ASSERT(width.maximum < targetStretch); 1031 return width.maximum; 1032 } 1033 1034 static inline void filterStretch(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter) 1057 1035 { 1058 1036 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1059 if (!installedFont. stretch.includes(target))1037 if (!installedFont.capabilities.width.includes(target)) 1060 1038 filter[i] = false; 1061 1039 }); 1062 1040 } 1063 1041 1064 static inline std::optional< float> findClosestStyle(floattargetStyle, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)1042 static inline std::optional<FontSelectionValue> findClosestStyle(FontSelectionValue targetStyle, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 1065 1043 { 1066 1044 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 1067 1045 1068 if (targetStyle >= italicThreshold) {1069 float threshold = std::max(targetStyle, installedFonts.styleBounds.maximum);1046 if (targetStyle >= FontDatabase::italicThreshold()) { 1047 auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum); 1070 1048 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1071 ASSERT(font.style.isValid()); 1072 if (font.style.includes(targetStyle)) 1049 auto slope = font.capabilities.slope; 1050 ASSERT(slope.isValid()); 1051 if (slope.includes(targetStyle)) 1073 1052 return 0; 1074 ASSERT( font.style.minimum > targetStyle || font.style.maximum < targetStyle);1075 if ( font.style.minimum > targetStyle)1076 return font.style.minimum - targetStyle;1077 ASSERT(targetStyle > font.style.maximum);1078 return threshold - font.style.maximum;1053 ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle); 1054 if (slope.minimum > targetStyle) 1055 return slope.minimum - targetStyle; 1056 ASSERT(targetStyle > slope.maximum); 1057 return threshold - slope.maximum; 1079 1058 }; 1080 } else if (targetStyle >= 0) {1081 float threshold = std::max(targetStyle, installedFonts.styleBounds.maximum);1059 } else if (targetStyle >= FontSelectionValue()) { 1060 auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum); 1082 1061 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1083 ASSERT(font.style.isValid()); 1084 if (font.style.includes(targetStyle)) 1062 auto slope = font.capabilities.slope; 1063 ASSERT(slope.isValid()); 1064 if (slope.includes(targetStyle)) 1085 1065 return 0; 1086 ASSERT( font.style.minimum > targetStyle || font.style.maximum < targetStyle);1087 if ( font.style.maximum >= 0 && font.style.maximum < targetStyle)1088 return targetStyle - font.style.maximum;1089 if ( font.style.minimum > targetStyle)1090 return font.style.minimum;1091 ASSERT( font.style.maximum < 0);1092 return threshold - font.style.maximum;1066 ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle); 1067 if (slope.maximum >= FontSelectionValue() && slope.maximum < targetStyle) 1068 return targetStyle - slope.maximum; 1069 if (slope.minimum > targetStyle) 1070 return slope.minimum; 1071 ASSERT(slope.maximum < FontSelectionValue()); 1072 return threshold - slope.maximum; 1093 1073 }; 1094 } else if (targetStyle > - italicThreshold) {1095 float threshold = std::min(targetStyle, installedFonts.styleBounds.minimum);1074 } else if (targetStyle > -FontDatabase::italicThreshold()) { 1075 auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum); 1096 1076 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1097 ASSERT(font.style.isValid()); 1098 if (font.style.includes(targetStyle)) 1077 auto slope = font.capabilities.slope; 1078 ASSERT(slope.isValid()); 1079 if (slope.includes(targetStyle)) 1099 1080 return 0; 1100 ASSERT( font.style.minimum > targetStyle || font.style.maximum < targetStyle);1101 if ( font.style.minimum > targetStyle && font.style.minimum <= 0)1102 return font.style.minimum - targetStyle;1103 if ( font.style.maximum < targetStyle)1104 return - font.style.maximum;1105 ASSERT( font.style.minimum > 0);1106 return font.style.minimum - threshold;1081 ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle); 1082 if (slope.minimum > targetStyle && slope.minimum <= FontSelectionValue()) 1083 return slope.minimum - targetStyle; 1084 if (slope.maximum < targetStyle) 1085 return -slope.maximum; 1086 ASSERT(slope.minimum > FontSelectionValue()); 1087 return slope.minimum - threshold; 1107 1088 }; 1108 1089 } else { 1109 ASSERT(targetStyle <= - italicThreshold);1110 float threshold = std::min(targetStyle, installedFonts.styleBounds.minimum);1090 ASSERT(targetStyle <= -FontDatabase::italicThreshold()); 1091 auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum); 1111 1092 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1112 ASSERT(font.style.isValid()); 1113 if (font.style.includes(targetStyle)) 1093 auto slope = font.capabilities.slope; 1094 ASSERT(slope.isValid()); 1095 if (slope.includes(targetStyle)) 1114 1096 return 0; 1115 ASSERT( font.style.minimum > targetStyle || font.style.maximum < targetStyle);1116 if ( font.style.maximum < targetStyle)1117 return targetStyle - font.style.maximum;1118 ASSERT( font.style.minimum > targetStyle);1119 return font.style.minimum - threshold;1097 ASSERT(slope.minimum > targetStyle || slope.maximum < targetStyle); 1098 if (slope.maximum < targetStyle) 1099 return targetStyle - slope.maximum; 1100 ASSERT(slope.minimum > targetStyle); 1101 return slope.minimum - threshold; 1120 1102 }; 1121 1103 } … … 1134 1116 return std::nullopt; 1135 1117 auto& winner = installedFonts.installedFonts[closestIndex]; 1136 if (winner.style.includes(targetStyle)) 1118 auto slope = winner.capabilities.slope; 1119 if (slope.includes(targetStyle)) 1137 1120 return targetStyle; 1138 if ( winner.style.minimum > targetStyle)1139 return winner.style.minimum;1140 ASSERT( winner.style.maximum < targetStyle);1141 return winner.style.maximum;1142 } 1143 1144 static inline void filterStyle( floattarget, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)1121 if (slope.minimum > targetStyle) 1122 return slope.minimum; 1123 ASSERT(slope.maximum < targetStyle); 1124 return slope.maximum; 1125 } 1126 1127 static inline void filterStyle(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter) 1145 1128 { 1146 1129 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1147 if (!installedFont. style.includes(target))1130 if (!installedFont.capabilities.slope.includes(target)) 1148 1131 filter[i] = false; 1149 1132 }); 1150 1133 } 1151 1134 1152 static inline std::optional< float> findClosestWeight(floattargetWeight, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter)1135 static inline std::optional<FontSelectionValue> findClosestWeight(FontSelectionValue targetWeight, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 1153 1136 { 1154 1137 { 1155 1138 // The spec states: "If the desired weight is 400, 500 is checked first ... If the desired weight is 500, 400 is checked first" 1156 IterateActiveFontsWithReturnCallback< float> searchFor400 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<float> {1157 if (font. weight.includes(400))1158 return 400;1139 IterateActiveFontsWithReturnCallback<FontSelectionValue> searchFor400 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<FontSelectionValue> { 1140 if (font.capabilities.weight.includes(FontSelectionValue(400))) 1141 return FontSelectionValue(400); 1159 1142 return std::nullopt; 1160 1143 }; 1161 IterateActiveFontsWithReturnCallback< float> searchFor500 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<float> {1162 if (font. weight.includes(500))1163 return 500;1144 IterateActiveFontsWithReturnCallback<FontSelectionValue> searchFor500 = [&](const FontDatabase::InstalledFont& font, size_t) -> std::optional<FontSelectionValue> { 1145 if (font.capabilities.weight.includes(FontSelectionValue(500))) 1146 return FontSelectionValue(500); 1164 1147 return std::nullopt; 1165 1148 }; 1166 if (targetWeight == 400) {1149 if (targetWeight == FontSelectionValue(400)) { 1167 1150 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor400)) 1168 1151 return result; 1169 1152 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500)) 1170 1153 return result; 1171 } else if (targetWeight == 500) {1154 } else if (targetWeight == FontSelectionValue(500)) { 1172 1155 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500)) 1173 1156 return result; … … 1178 1161 1179 1162 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 1180 if (targetWeight <= weightThreshold) { 1181 float threshold = std::min(targetWeight, installedFonts.weightBounds.minimum); 1182 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1183 if (font.weight.includes(targetWeight)) 1184 return 0; 1185 ASSERT(font.weight.minimum > targetWeight || font.weight.maximum < targetWeight); 1186 if (font.weight.maximum < targetWeight) 1187 return targetWeight - font.weight.maximum; 1188 ASSERT(font.weight.minimum > targetWeight); 1189 return font.weight.minimum - threshold; 1163 if (targetWeight <= FontDatabase::weightThreshold()) { 1164 auto threshold = std::min(targetWeight, installedFonts.capabilities.weight.minimum); 1165 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> FontSelectionValue { 1166 auto weight = font.capabilities.weight; 1167 if (weight.includes(targetWeight)) 1168 return FontSelectionValue(); 1169 ASSERT(weight.minimum > targetWeight || weight.maximum < targetWeight); 1170 if (weight.maximum < targetWeight) 1171 return targetWeight - weight.maximum; 1172 ASSERT(weight.minimum > targetWeight); 1173 return weight.minimum - threshold; 1190 1174 }; 1191 1175 } else { 1192 ASSERT(targetWeight > weightThreshold); 1193 float threshold = std::max(targetWeight, installedFonts.weightBounds.maximum); 1194 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1195 if (font.weight.includes(targetWeight)) 1196 return 0; 1197 ASSERT(font.weight.minimum > targetWeight || font.weight.maximum < targetWeight); 1198 if (font.weight.minimum > targetWeight) 1199 return font.weight.minimum - targetWeight; 1200 ASSERT(font.weight.maximum < targetWeight); 1201 return threshold - font.weight.maximum; 1176 ASSERT(targetWeight > FontDatabase::weightThreshold()); 1177 auto threshold = std::max(targetWeight, installedFonts.capabilities.weight.maximum); 1178 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> FontSelectionValue { 1179 auto weight = font.capabilities.weight; 1180 if (weight.includes(targetWeight)) 1181 return FontSelectionValue(); 1182 ASSERT(weight.minimum > targetWeight || weight.maximum < targetWeight); 1183 if (weight.minimum > targetWeight) 1184 return weight.minimum - targetWeight; 1185 ASSERT(weight.maximum < targetWeight); 1186 return threshold - weight.maximum; 1202 1187 }; 1203 1188 } … … 1216 1201 return std::nullopt; 1217 1202 auto& winner = installedFonts.installedFonts[closestIndex]; 1218 if (winner.weight.includes(targetWeight)) 1203 auto weight = winner.capabilities.weight; 1204 if (weight.includes(targetWeight)) 1219 1205 return targetWeight; 1220 if (w inner.weight.minimum > targetWeight)1221 return w inner.weight.minimum;1222 ASSERT(w inner.weight.maximum < targetWeight);1223 return w inner.weight.maximum;1224 } 1225 1226 static inline void filterWeight( floattarget, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter)1206 if (weight.minimum > targetWeight) 1207 return weight.minimum; 1208 ASSERT(weight.maximum < targetWeight); 1209 return weight.maximum; 1210 } 1211 1212 static inline void filterWeight(FontSelectionValue target, const FontDatabase::InstalledFontFamily& installedFonts, std::unique_ptr<bool[]>& filter) 1227 1213 { 1228 1214 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1229 if (!installedFont. weight.includes(target))1215 if (!installedFont.capabilities.weight.includes(target)) 1230 1216 filter[i] = false; 1231 1217 }); 1232 1218 } 1233 1219 1234 static inline floatcomputeTargetWeight(FontWeight weight)1220 static inline FontSelectionValue computeTargetWeight(FontWeight weight) 1235 1221 { 1236 1222 switch (weight) { 1237 1223 case FontWeight100: 1238 return 100;1224 return FontSelectionValue(100); 1239 1225 case FontWeight200: 1240 return 200;1226 return FontSelectionValue(200); 1241 1227 case FontWeight300: 1242 return 300;1228 return FontSelectionValue(300); 1243 1229 case FontWeight400: 1244 return 400;1230 return FontSelectionValue(400); 1245 1231 case FontWeight500: 1246 return 500;1232 return FontSelectionValue(500); 1247 1233 case FontWeight600: 1248 return 600;1234 return FontSelectionValue(600); 1249 1235 case FontWeight700: 1250 return 700;1236 return FontSelectionValue(700); 1251 1237 case FontWeight800: 1252 return 800;1238 return FontSelectionValue(800); 1253 1239 case FontWeight900: 1254 return 900;1240 return FontSelectionValue(900); 1255 1241 default: 1256 1242 ASSERT_NOT_REACHED(); 1257 return 400;1258 } 1259 } 1260 1261 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, CTFontSymbolicTraits requestedTraits, FontWeight weight, floatstretch)1243 return FontSelectionValue(400); 1244 } 1245 } 1246 1247 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch) 1262 1248 { 1263 1249 ASSERT(!familyFonts.isEmpty()); … … 1268 1254 filter[i] = true; 1269 1255 1270 // FIXME: Implement this. 1271 float targetStretch = stretch; 1272 if (auto closestStretch = findClosestStretch(targetStretch, familyFonts, filter)) 1256 if (auto closestStretch = findClosestStretch(stretch, familyFonts, filter)) 1273 1257 filterStretch(closestStretch.value(), familyFonts, filter); 1274 1258 else 1275 1259 return nullptr; 1276 1260 1277 float targetStyle = requestedTraits & kCTFontTraitItalic ? italicThreshold : 0;1261 FontSelectionValue targetStyle = requestedTraits & kCTFontTraitItalic ? FontDatabase::italicThreshold() : FontSelectionValue(); 1278 1262 if (auto closestStyle = findClosestStyle(targetStyle, familyFonts, filter)) 1279 1263 filterStyle(closestStyle.value(), familyFonts, filter); … … 1281 1265 return nullptr; 1282 1266 1283 floattargetWeight = computeTargetWeight(weight);1267 FontSelectionValue targetWeight = computeTargetWeight(weight); 1284 1268 if (auto closestWeight = findClosestWeight(targetWeight, familyFonts, filter)) 1285 1269 filterWeight(closestWeight.value(), familyFonts, filter); … … 1294 1278 #endif // !SHOULD_USE_CORE_TEXT_FONT_LOOKUP 1295 1279 1296 static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, floatstretch, float size)1280 static RetainPtr<CTFontRef> platformFontLookupWithFamily(const AtomicString& family, CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch, float size) 1297 1281 { 1298 1282 const auto& whitelist = fontWhitelist(); … … 1317 1301 if (!postScriptFont.fontDescriptor) 1318 1302 return nullptr; 1319 if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.style.maximum < italicThreshold) || (weight >= FontWeight600 && postScriptFont.weight.maximum < 600)) { 1303 if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.capabilities.slope.maximum < FontDatabase::italicThreshold()) 1304 || (weight >= FontWeight600 && postScriptFont.capabilities.weight.maximum < FontSelectionValue(600))) { 1320 1305 auto postScriptFamilyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(postScriptFont.fontDescriptor.get(), kCTFontFamilyNameAttribute))); 1321 1306 if (!postScriptFamilyName) … … 1357 1342 } 1358 1343 1359 static RetainPtr<CTFontRef> fontWithFamily(const AtomicString& family, CTFontSymbolicTraits desiredTraits, FontWeight weight, floatstretch, const FontFeatureSettings& featureSettings, const FontVariantSettings& variantSettings, const FontVariationSettings& variationSettings, const FontFeatureSettings* fontFaceFeatures, const FontVariantSettings* fontFaceVariantSettings, const TextRenderingMode& textRenderingMode, float size)1344 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) 1360 1345 { 1361 1346 if (family.isEmpty()) -
trunk/Source/WebCore/platform/text/TextFlags.h
r209875 r213341 24 24 */ 25 25 26 #ifndef TextFlags_h 27 #define TextFlags_h 26 #pragma once 27 28 #include <wtf/NeverDestroyed.h> 28 29 29 30 namespace WebCore { … … 398 399 }; 399 400 401 // Unclamped, unchecked, signed fixed-point number representing a value used for font variations. 402 // Sixteen bits in total, one sign bit, two fractional bits, means the smallest positive representable value is 0.25, 403 // the maximum representable value is 8191.75, and the minimum representable value is -8192. 404 class FontSelectionValue { 405 public: 406 FontSelectionValue() = default; 407 408 // Explicit because it is lossy. 409 explicit FontSelectionValue(int x) 410 : m_backing(x * fractionalEntropy) 411 { 412 } 413 414 // Explicit because it is lossy. 415 explicit FontSelectionValue(float x) 416 : m_backing(x * fractionalEntropy) 417 { 418 } 419 420 operator float() const 421 { 422 // floats have 23 fractional bits, but only 14 fractional bits are necessary, so every value can be represented losslessly. 423 return m_backing / static_cast<float>(fractionalEntropy); 424 } 425 426 FontSelectionValue operator+(const FontSelectionValue other) const 427 { 428 return FontSelectionValue(m_backing + other.m_backing, RawTag::RawTag); 429 } 430 431 FontSelectionValue operator-(const FontSelectionValue other) const 432 { 433 return FontSelectionValue(m_backing - other.m_backing, RawTag::RawTag); 434 } 435 436 FontSelectionValue operator*(const FontSelectionValue other) const 437 { 438 return FontSelectionValue(static_cast<int32_t>(m_backing) * other.m_backing / fractionalEntropy, RawTag::RawTag); 439 } 440 441 FontSelectionValue operator/(const FontSelectionValue other) const 442 { 443 return FontSelectionValue(static_cast<int32_t>(m_backing) / other.m_backing * fractionalEntropy, RawTag::RawTag); 444 } 445 446 FontSelectionValue operator-() const 447 { 448 return FontSelectionValue(-m_backing, RawTag::RawTag); 449 } 450 451 bool operator==(const FontSelectionValue other) const 452 { 453 return m_backing == other.m_backing; 454 } 455 456 bool operator!=(const FontSelectionValue other) const 457 { 458 return !operator==(other); 459 } 460 461 bool operator<(const FontSelectionValue other) const 462 { 463 return m_backing < other.m_backing; 464 } 465 466 bool operator<=(const FontSelectionValue other) const 467 { 468 return m_backing <= other.m_backing; 469 } 470 471 bool operator>(const FontSelectionValue other) const 472 { 473 return m_backing > other.m_backing; 474 } 475 476 bool operator>=(const FontSelectionValue other) const 477 { 478 return m_backing >= other.m_backing; 479 } 480 481 int16_t rawValue() const 482 { 483 return m_backing; 484 } 485 486 static FontSelectionValue maximumValue() 487 { 488 static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<int16_t>::max(), RawTag::RawTag); 489 return result.get(); 490 } 491 492 static FontSelectionValue minimumValue() 493 { 494 static NeverDestroyed<FontSelectionValue> result = FontSelectionValue(std::numeric_limits<int16_t>::min(), RawTag::RawTag); 495 return result.get(); 496 } 497 498 private: 499 enum class RawTag { RawTag }; 500 501 FontSelectionValue(int16_t rawValue, RawTag) 502 : m_backing(rawValue) 503 { 504 } 505 506 static constexpr int fractionalEntropy = 4; 507 int16_t m_backing { 0 }; 508 }; 509 510 // [Inclusive, Inclusive] 511 struct FontSelectionRange { 512 bool isValid() const 513 { 514 return minimum <= maximum; 515 } 516 517 void expand(const FontSelectionRange& other) 518 { 519 ASSERT(other.isValid()); 520 if (!isValid()) 521 *this = other; 522 else { 523 minimum = std::min(minimum, other.minimum); 524 maximum = std::max(maximum, other.maximum); 525 } 526 ASSERT(isValid()); 527 } 528 529 bool includes(FontSelectionValue target) const 530 { 531 return target >= minimum && target <= maximum; 532 } 533 534 FontSelectionValue minimum { FontSelectionValue(1) }; 535 FontSelectionValue maximum { FontSelectionValue(0) }; 536 }; 537 538 struct FontSelectionRequest { 539 FontSelectionValue weight; 540 FontSelectionValue width; 541 FontSelectionValue slope; 542 }; 543 544 struct FontSelectionCapabilities { 545 void expand(const FontSelectionCapabilities& capabilities) 546 { 547 weight.expand(capabilities.weight); 548 width.expand(capabilities.width); 549 slope.expand(capabilities.slope); 550 } 551 552 FontSelectionRange weight; 553 FontSelectionRange width; 554 FontSelectionRange slope; 555 }; 556 400 557 enum class Kerning { 401 558 Auto, … … 405 562 406 563 } 407 408 #endif -
trunk/Tools/ChangeLog
r213331 r213341 1 2017-03-02 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Migrate font-stretch to use fixed-point values 4 https://bugs.webkit.org/show_bug.cgi?id=169107 5 6 Reviewed by Dean Jackson. 7 8 Update to new types. 9 10 * TestWebKitAPI/Tests/WebCore/FontCache.cpp: 11 (TestWebKitAPI::createPlatformFont): 12 1 13 2017-03-02 Brady Eidson <beidson@apple.com> 2 14 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/FontCache.cpp
r213267 r213341 57 57 description.setWeight(weight); 58 58 description.setItalic(italic); 59 description.setStretch( stretch);59 description.setStretch(FontSelectionValue(stretch)); 60 60 description.setComputedSize(size); 61 61
Note: See TracChangeset
for help on using the changeset viewer.