Changeset 213436 in webkit
- Timestamp:
- Mar 5, 2017 12:14:02 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r213434 r213436 1 2017-03-04 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Update CSSFontSelector's matching algorithm to understand ranges 4 https://bugs.webkit.org/show_bug.cgi?id=168892 5 6 Reviewed by Jon Lee. 7 8 Update CSS Font Loading API test to accept font-stretch values. 9 10 * fast/text/font-face-javascript-expected.txt: 11 * fast/text/font-face-javascript.html: 12 1 13 2017-03-05 Carlos Garcia Campos <cgarcia@igalia.com> 2 14 -
trunk/LayoutTests/fast/text/font-face-javascript-expected.txt
r212412 r213436 17 17 PASS new FontFace('family_name', 'url(\'asdf\')', {'weight': 'lighter'}).weight is "200" 18 18 PASS new FontFace('family_name', 'url(\'asdf\')', {'weight': 'inherit'}).weight threw exception SyntaxError (DOM Exception 12): The string did not match the expected pattern.. 19 PASS new FontFace('family_name', 'url(\'asdf\')', {'stretch': ' stretch_name'}).stretch is "normal"19 PASS new FontFace('family_name', 'url(\'asdf\')', {'stretch': 'ultra-expanded'}).stretch is "ultra-expanded" 20 20 PASS new FontFace('family_name', 'url(\'asdf\')', {'unicodeRange': 'U+26'}).unicodeRange is "U+26-26" 21 21 PASS new FontFace('family_name', 'url(\'asdf\')', {'unicodeRange': 'U+0-7F'}).unicodeRange is "U+0-7f" … … 26 26 PASS everything.style is "italic" 27 27 PASS everything.weight is "bold" 28 PASS everything.stretch is " normal"28 PASS everything.stretch is "extra-expanded" 29 29 PASS everything.unicodeRange is "U+26-26" 30 30 PASS everything.variant is "small-caps" … … 33 33 PASS everything.style is "normal" 34 34 PASS everything.weight is "300" 35 PASS everything.stretch is " normal"35 PASS everything.stretch is "condensed" 36 36 PASS everything.unicodeRange is "U+0-7f" 37 37 PASS everything.variant is "stacked-fractions" -
trunk/LayoutTests/fast/text/font-face-javascript.html
r212405 r213436 25 25 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'weight': 'lighter'}).weight", "200"); 26 26 shouldThrow("new FontFace('family_name', 'url(\\'asdf\\')', {'weight': 'inherit'}).weight"); 27 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'stretch': ' stretch_name'}).stretch", "normal");27 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'stretch': 'ultra-expanded'}).stretch", "ultra-expanded"); 28 28 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'unicodeRange': 'U+26'}).unicodeRange", "U+26-26"); 29 29 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'unicodeRange': 'U+0-7F'}).unicodeRange", "U+0-7f"); … … 33 33 shouldBeEqualToString("new FontFace('family_name', 'url(\\'asdf\\')', {'featureSettings': '\\'titl\\''}).featureSettings", "'titl' 1"); 34 34 35 var everything = new FontFace('family_name', 'url(\'asdf\')', {'style': 'italic', 'weight': 'bold', 'stretch': ' stretch_name', 'unicodeRange': 'U+26', 'variant': 'small-caps', 'featureSettings': '\'titl\''});35 var everything = new FontFace('family_name', 'url(\'asdf\')', {'style': 'italic', 'weight': 'bold', 'stretch': 'extra-expanded', 'unicodeRange': 'U+26', 'variant': 'small-caps', 'featureSettings': '\'titl\''}); 36 36 shouldBeEqualToString("everything.style", "italic"); 37 37 shouldBeEqualToString("everything.weight", "bold"); 38 shouldBeEqualToString("everything.stretch", " normal");38 shouldBeEqualToString("everything.stretch", "extra-expanded"); 39 39 shouldBeEqualToString("everything.unicodeRange", "U+26-26"); 40 40 shouldBeEqualToString("everything.variant", "small-caps"); … … 47 47 everything.weight = "300"; 48 48 shouldBeEqualToString("everything.weight", "300"); 49 everything.stretch = " other_stretch_name";50 shouldBeEqualToString("everything.stretch", " normal");49 everything.stretch = "condensed"; 50 shouldBeEqualToString("everything.stretch", "condensed"); 51 51 everything.unicodeRange = "U+0-7F"; 52 52 shouldBeEqualToString("everything.unicodeRange", "U+0-7f"); -
trunk/Source/WebCore/CMakeLists.txt
r213423 r213436 2201 2201 platform/graphics/FontCascadeFonts.cpp 2202 2202 platform/graphics/FontDescription.cpp 2203 platform/graphics/FontSelectionAlgorithm.cpp 2203 2204 platform/graphics/FontTaggedSettings.cpp 2204 2205 platform/graphics/FontGenericFamilies.cpp -
trunk/Source/WebCore/ChangeLog
r213435 r213436 1 2017-03-04 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Update CSSFontSelector's matching algorithm to understand ranges 4 https://bugs.webkit.org/show_bug.cgi?id=168892 5 6 Reviewed by Jon Lee. 7 8 This patch migrates the font selection algorithm out of FontCacheCoreText and into its own file which can be shared 9 among all ports. It then migrates our web font selection algorithm to use it. 10 11 This patch doesn't actually change the parsing rules; it just changes the internal machinery for how fonts get 12 selected. Therefore, this patch simply makes zero-length ranges from the discrete values the parser emits, and passes 13 those zero-length ranges to the range-based font selection routine. This means that this patch doesn't actually 14 change the results of the font selection algorithm. 15 16 One of the inputs to the new font selection algorithm is font-stretch, which previously was not parsed inside 17 @font-face blocks or the CSS Font Loading API. This patch therefore adds parsing support and modifies the existing 18 tests for these pieces to expect parsing to work. Because the font selection algorithm itself is shared between 19 installed fonts and webfonts, this patch doesn't add any additional tests for it (because it is already covered under 20 existing tests). 21 22 No new tests because there is no behavior change. 23 24 * CMakeLists.txt: 25 * WebCore.xcodeproj/project.pbxproj: Add new file for the font selection algorithm. 26 * css/CSSFontFace.cpp: 27 (WebCore::CSSFontFace::calculateStretch): Used on @font-face blocks and the CSS Font Loading API. 28 (WebCore::CSSFontFace::setStretch): Fill out the previously stubbed function. 29 * css/CSSFontFace.h: Add the range member variable to CSSFontFaces. 30 * css/CSSFontFaceSet.cpp: 31 (WebCore::CSSFontFaceSet::ensureLocalFontFacesForFamilyRegistered): Now that we care about font-stretch, we need to 32 look it up for local fonts too. This current approach of an extra FontSelectionValue hanging around with a 33 FontTraitsMask is very ugly and will be removed soon (https://bugs.webkit.org/show_bug.cgi?id=168889 and 34 https://bugs.webkit.org/show_bug.cgi?id=168890). 35 (WebCore::computeFontStretch): Used on @font-face blocks and the CSS Font Loading API. 36 (WebCore::CSSFontFaceSet::matchingFaces): Educate about font-stretch. 37 (WebCore::CSSFontFaceSet::fontFace): Migrate to the new font-selection algorithm. 38 (WebCore::fontFaceComparator): Deleted. 39 * css/CSSFontFaceSet.h: 40 * css/CSSFontSelector.cpp: 41 (WebCore::CSSFontSelector::addFontFaceRule): Educate about font-stretch. 42 (WebCore::CSSFontSelector::fontRangesForFamily): Ditto. 43 * css/FontFace.cpp: 44 (WebCore::FontFace::setStretch): Ditto. 45 (WebCore::FontFace::stretch): Ditto. 46 * css/parser/CSSPropertyParser.cpp: 47 (WebCore::CSSPropertyParser::parseFontFaceDescriptor): Ditto. 48 * platform/graphics/FontCache.h: Ditto. 49 * platform/graphics/FontDescription.h: 50 * platform/graphics/FontSelectionAlgorithm.cpp: Added. 51 (WebCore::FontSelectionAlgorithm::filterCapability): 52 (WebCore::FontSelectionAlgorithm::indexOfBestCapabilities): 53 (WebCore::fontSelectionRequestForTraitsMask): 54 (WebCore::initialFontSelectionCapabilitiesForTraitsMask): 55 (WebCore::fontSelectionCapabilitiesForTraitsMask): 56 * platform/graphics/FontSelectionAlgorithm.h: Added. Taken from FontCacheCoreText.cpp. 57 (WebCore::FontSelectionValue::FontSelectionValue): 58 (WebCore::FontSelectionValue::operator float): 59 (WebCore::FontSelectionValue::rawValue): 60 (WebCore::FontSelectionValue::maximumValue): 61 (WebCore::FontSelectionValue::minimumValue): 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::operator<=): 70 (WebCore::FontSelectionValue::operator>): 71 (WebCore::FontSelectionValue::operator>=): 72 (WebCore::FontSelectionRange::isValid): 73 (WebCore::FontSelectionRange::expand): 74 (WebCore::FontSelectionRange::includes): 75 (WebCore::FontSelectionRequest::operator==): 76 (WebCore::FontSelectionRequest::operator!=): 77 (WebCore::FontSelectionRequestKey::FontSelectionRequestKey): 78 (WebCore::FontSelectionRequestKey::isHashTableDeletedValue): 79 (WebCore::FontSelectionRequestKey::operator==): 80 (WebCore::FontSelectionRequestKeyHash::hash): 81 (WebCore::FontSelectionRequestKeyHash::equal): 82 (WebCore::FontSelectionCapabilities::expand): 83 (WebCore::FontSelectionAlgorithm::FontSelectionAlgorithm): 84 (WebCore::FontSelectionAlgorithm::iterateActiveCapabilitiesWithReturn): 85 (WebCore::FontSelectionAlgorithm::iterateActiveCapabilities): 86 * platform/graphics/cocoa/FontCacheCoreText.cpp: Moved to FontSelectionAlgorithm. 87 (WebCore::stretchFromCoreTextTraits): 88 (WebCore::FontDatabase::capabilitiesForFontDescriptor): 89 (WebCore::findClosestFont): 90 (WebCore::calculateFontSelectionRequest): 91 (WebCore::platformFontLookupWithFamily): 92 (WebCore::FontCache::getTraitsInFamily): Deleted. 93 (WebCore::iterateActiveFontsWithReturn): Deleted. 94 (WebCore::iterateActiveFonts): Deleted. 95 (WebCore::findClosestStretch): Deleted. 96 (WebCore::filterStretch): Deleted. 97 (WebCore::findClosestStyle): Deleted. 98 (WebCore::filterStyle): Deleted. 99 (WebCore::findClosestWeight): Deleted. 100 (WebCore::filterWeight): Deleted. 101 (WebCore::computeTargetWeight): Deleted. 102 * platform/text/TextFlags.h: Moved to FontSelectionAlgorithm. 103 (WebCore::FontSelectionValue::FontSelectionValue): Deleted. 104 (WebCore::FontSelectionValue::operator float): Deleted. 105 (WebCore::FontSelectionValue::operator+): Deleted. 106 (WebCore::FontSelectionValue::operator-): Deleted. 107 (WebCore::FontSelectionValue::operator*): Deleted. 108 (WebCore::FontSelectionValue::operator/): Deleted. 109 (WebCore::FontSelectionValue::operator==): Deleted. 110 (WebCore::FontSelectionValue::operator!=): Deleted. 111 (WebCore::FontSelectionValue::operator<): Deleted. 112 (WebCore::FontSelectionValue::operator<=): Deleted. 113 (WebCore::FontSelectionValue::operator>): Deleted. 114 (WebCore::FontSelectionValue::operator>=): Deleted. 115 (WebCore::FontSelectionValue::rawValue): Deleted. 116 (WebCore::FontSelectionValue::maximumValue): Deleted. 117 (WebCore::FontSelectionValue::minimumValue): Deleted. 118 (WebCore::FontSelectionRange::isValid): Deleted. 119 (WebCore::FontSelectionRange::expand): Deleted. 120 (WebCore::FontSelectionRange::includes): Deleted. 121 (WebCore::FontSelectionCapabilities::expand): Deleted. 122 1 123 2017-03-05 Simon Fraser <simon.fraser@apple.com> 2 124 -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r213423 r213436 5748 5748 C28083401C6DC275001451B6 /* JSFontFace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C280833D1C6DC22C001451B6 /* JSFontFace.cpp */; }; 5749 5749 C28083421C6DC96A001451B6 /* JSFontFaceCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28083411C6DC96A001451B6 /* JSFontFaceCustom.cpp */; }; 5750 C2AB0AF61E6B3C6C001348C5 /* FontSelectionAlgorithm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2AB0AF41E6B3C6C001348C5 /* FontSelectionAlgorithm.cpp */; }; 5751 C2AB0AF71E6B3C6C001348C5 /* FontSelectionAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = C2AB0AF51E6B3C6C001348C5 /* FontSelectionAlgorithm.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5750 5752 C2E1F43F1D6254E10094625C /* BreakLines.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA4816097D93020094C9E4 /* BreakLines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5751 5753 C2F4E78A1E45BEA1006D7105 /* ComplexTextController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */; }; … … 13874 13876 C280833E1C6DC22C001451B6 /* JSFontFace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFontFace.h; sourceTree = "<group>"; }; 13875 13877 C28083411C6DC96A001451B6 /* JSFontFaceCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFontFaceCustom.cpp; sourceTree = "<group>"; }; 13878 C2AB0AF41E6B3C6C001348C5 /* FontSelectionAlgorithm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontSelectionAlgorithm.cpp; sourceTree = "<group>"; }; 13879 C2AB0AF51E6B3C6C001348C5 /* FontSelectionAlgorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontSelectionAlgorithm.h; sourceTree = "<group>"; }; 13876 13880 C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComplexTextController.cpp; sourceTree = "<group>"; }; 13877 13881 C2F4E7891E45AEDF006D7105 /* ComplexTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComplexTextController.h; sourceTree = "<group>"; }; … … 22370 22374 379919941200DDF400EA041C /* WOFFFileFormat.cpp */, 22371 22375 379919951200DDF400EA041C /* WOFFFileFormat.h */, 22376 C2AB0AF41E6B3C6C001348C5 /* FontSelectionAlgorithm.cpp */, 22377 C2AB0AF51E6B3C6C001348C5 /* FontSelectionAlgorithm.h */, 22372 22378 ); 22373 22379 path = graphics; … … 27640 27646 A818721B0977D3C0005826D9 /* NodeList.h in Headers */, 27641 27647 63189AE30E83A33300012E41 /* NodeRareData.h in Headers */, 27648 C2AB0AF71E6B3C6C001348C5 /* FontSelectionAlgorithm.h in Headers */, 27642 27649 63D7B32D0E78CD3F00F7617C /* NodeRenderStyle.h in Headers */, 27643 27650 E43105BB16750F1600DB2FB8 /* NodeTraversal.h in Headers */, … … 29507 29514 1A8A645F1D19FCFC00D0E00F /* ApplePayShippingMethodSelectedEvent.cpp in Sources */, 29508 29515 1A8A64621D19FCFC00D0E00F /* ApplePayValidateMerchantEvent.cpp in Sources */, 29516 C2AB0AF61E6B3C6C001348C5 /* FontSelectionAlgorithm.cpp in Sources */, 29509 29517 1A8F6BBC0DB55CDC001DB794 /* ApplicationCache.cpp in Sources */, 29510 29518 1A8F6BBE0DB55CDC001DB794 /* ApplicationCacheGroup.cpp in Sources */, -
trunk/Source/WebCore/css/CSSFontFace.cpp
r212513 r213436 195 195 } 196 196 197 std::optional<FontSelectionValue> CSSFontFace::calculateStretch(CSSValue& stretch) 198 { 199 if (!is<CSSPrimitiveValue>(stretch)) 200 return std::nullopt; 201 202 const auto& primitiveValue = downcast<CSSPrimitiveValue>(stretch); 203 if (primitiveValue.isPercentage() || primitiveValue.isNumber()) { 204 auto value = primitiveValue.floatValue(); 205 if (value < static_cast<float>(FontSelectionValue::minimumValue())) 206 return FontSelectionValue::minimumValue(); 207 if (value > static_cast<float>(FontSelectionValue::maximumValue())) 208 return FontSelectionValue::maximumValue(); 209 return FontSelectionValue(value); 210 } 211 212 switch (primitiveValue.valueID()) { 213 case CSSValueUltraCondensed: 214 return FontSelectionValue(50); 215 case CSSValueExtraCondensed: 216 return FontSelectionValue(62.5f); 217 case CSSValueCondensed: 218 return FontSelectionValue(75); 219 case CSSValueSemiCondensed: 220 return FontSelectionValue(87.5f); 221 case CSSValueNormal: 222 return FontSelectionValue(100); 223 case CSSValueSemiExpanded: 224 return FontSelectionValue(112.5f); 225 case CSSValueExpanded: 226 return FontSelectionValue(125); 227 case CSSValueExtraExpanded: 228 return FontSelectionValue(150); 229 case CSSValueUltraExpanded: 230 return FontSelectionValue(200); 231 default: 232 ASSERT_NOT_REACHED(); 233 return std::nullopt; 234 } 235 } 236 197 237 bool CSSFontFace::setWeight(CSSValue& weight) 198 238 { … … 202 242 if (m_cssConnection) 203 243 m_cssConnection->mutableProperties().setProperty(CSSPropertyFontWeight, &weight); 244 245 iterateClients(m_clients, [&](Client& client) { 246 client.fontPropertyChanged(*this); 247 }); 248 249 return true; 250 } 251 252 return false; 253 } 254 255 bool CSSFontFace::setStretch(CSSValue& stretch) 256 { 257 if (auto parsedStretch = calculateStretch(stretch)) { 258 m_stretch = FontSelectionRange(parsedStretch.value(), parsedStretch.value()); 259 260 if (m_cssConnection) 261 m_cssConnection->mutableProperties().setProperty(CSSPropertyFontStretch, &stretch); 204 262 205 263 iterateClients(m_clients, [&](Client& client) { -
trunk/Source/WebCore/css/CSSFontFace.h
r208985 r213436 27 27 28 28 #include "CSSFontFaceRule.h" 29 #include "FontSelectionAlgorithm.h" 29 30 #include "FontTaggedSettings.h" 30 31 #include "TextFlags.h" … … 66 67 bool setStyle(CSSValue&); 67 68 bool setWeight(CSSValue&); 69 bool setStretch(CSSValue&); 68 70 bool setUnicodeRange(CSSValue&); 69 71 bool setVariantLigatures(CSSValue&); … … 79 81 const CSSValueList* families() const { return m_families.get(); } 80 82 FontTraitsMask traitsMask() const { return m_traitsMask; } 83 FontSelectionRange stretch() const { return m_stretch; } 81 84 const Vector<UnicodeRange>& ranges() const { return m_ranges; } 82 85 const FontFeatureSettings& featureSettings() const { return m_featureSettings; } … … 84 87 void setVariantSettings(const FontVariantSettings& variantSettings) { m_variantSettings = variantSettings; } 85 88 void setTraitsMask(FontTraitsMask traitsMask) { m_traitsMask = traitsMask; } 89 void setStretch(FontSelectionRange stretch) { m_stretch = stretch; } 86 90 bool isLocalFallback() const { return m_isLocalFallback; } 87 91 Status status() const { return m_status; } 88 92 StyleRuleFontFace* cssConnection() const { return m_cssConnection.get(); } 93 FontSelectionCapabilities fontSelectionCapabilities() const { return fontSelectionCapabilitiesForTraitsMask(m_traitsMask, m_stretch); } 89 94 90 95 static std::optional<FontTraitsMask> calculateStyleMask(CSSValue& style); 91 96 static std::optional<FontTraitsMask> calculateWeightMask(CSSValue& weight); 97 static std::optional<FontSelectionValue> calculateStretch(CSSValue& stretch); 92 98 93 99 class Client; … … 174 180 WeakPtr<FontFace> m_wrapper; 175 181 Status m_status { Status::Pending }; 182 FontSelectionRange m_stretch { FontSelectionValue(100), FontSelectionValue(100) }; 176 183 bool m_isLocalFallback { false }; 177 184 bool m_sourcesPopulated { false }; -
trunk/Source/WebCore/css/CSSFontFaceSet.cpp
r212985 r213436 102 102 return; 103 103 104 Vector<Font TraitsMask> traitsMasks = FontCache::singleton().getTraitsInFamily(familyName);105 if (traits Masks.isEmpty())104 Vector<FontCache::TraitsAndStretch> traitsAndStretch = FontCache::singleton().getTraitsAndStretchInFamily(familyName); 105 if (traitsAndStretch.isEmpty()) 106 106 return; 107 107 108 108 Vector<Ref<CSSFontFace>> faces; 109 for (auto mask : traitsMasks) {109 for (auto item : traitsAndStretch) { 110 110 Ref<CSSFontFace> face = CSSFontFace::create(nullptr, nullptr, nullptr, true); 111 111 … … 113 113 familyList->append(CSSValuePool::singleton().createFontFamilyValue(familyName)); 114 114 face->setFamilies(familyList.get()); 115 face->setTraitsMask(mask); 115 face->setTraitsMask(item.traits); 116 face->setStretch(item.stretch); 116 117 face->adoptSource(std::make_unique<CSSFontFaceSource>(face.get(), familyName)); 117 118 ASSERT(!face->allSourcesFailed()); … … 312 313 } 313 314 315 static std::optional<FontSelectionValue> computeFontStretch(MutableStyleProperties& style) 316 { 317 RefPtr<CSSValue> stretchValue = style.getPropertyCSSValue(CSSPropertyFontStretch).get(); 318 if (!stretchValue) 319 stretchValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal).ptr(); 320 321 if (auto stretchOptional = CSSFontFace::calculateStretch(*stretchValue)) 322 return stretchOptional.value(); 323 return std::nullopt; 324 } 325 314 326 static HashSet<UChar32> codePointsFromString(StringView stringView) 315 327 { … … 341 353 return Exception { SYNTAX_ERR }; 342 354 355 FontSelectionValue stretch; 356 if (auto stretchOptional = computeFontStretch(style.get())) 357 stretch = stretchOptional.value(); 358 else 359 return Exception { SYNTAX_ERR }; 360 343 361 auto family = style->getPropertyCSSValue(CSSPropertyFontFamily); 344 362 if (!is<CSSValueList>(family.get())) … … 360 378 bool found = false; 361 379 for (auto& family : familyOrder) { 362 auto* faces = fontFace(fontTraitsMask, family);380 auto* faces = fontFace(fontTraitsMask, stretch, family); 363 381 if (!faces) 364 382 continue; … … 395 413 } 396 414 397 static bool fontFaceComparator(FontTraitsMask desiredTraitsMaskForComparison, const CSSFontFace& first, const CSSFontFace& second) 398 { 399 FontTraitsMask firstTraitsMask = first.traitsMask(); 400 FontTraitsMask secondTraitsMask = second.traitsMask(); 401 402 bool firstHasDesiredStyle = firstTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; 403 bool secondHasDesiredStyle = secondTraitsMask & desiredTraitsMaskForComparison & FontStyleMask; 404 405 if (firstHasDesiredStyle != secondHasDesiredStyle) 406 return firstHasDesiredStyle; 407 408 if ((desiredTraitsMaskForComparison & FontStyleItalicMask) && !first.isLocalFallback() && !second.isLocalFallback()) { 409 // Prefer a font that has indicated that it can only support italics to a font that claims to support 410 // all styles. The specialized font is more likely to be the one the author wants used. 411 bool firstRequiresItalics = (firstTraitsMask & FontStyleItalicMask) && !(firstTraitsMask & FontStyleNormalMask); 412 bool secondRequiresItalics = (secondTraitsMask & FontStyleItalicMask) && !(secondTraitsMask & FontStyleNormalMask); 413 if (firstRequiresItalics != secondRequiresItalics) 414 return firstRequiresItalics; 415 } 416 417 if (secondTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) 418 return false; 419 if (firstTraitsMask & desiredTraitsMaskForComparison & FontWeightMask) 420 return true; 421 422 // http://www.w3.org/TR/2011/WD-css3-fonts-20111004/#font-matching-algorithm says : 423 // - If the desired weight is less than 400, weights below the desired weight are checked in descending order followed by weights above the desired weight in ascending order until a match is found. 424 // - If the desired weight is greater than 500, weights above the desired weight are checked in ascending order followed by weights below the desired weight in descending order until a match is found. 425 // - If the desired weight is 400, 500 is checked first and then the rule for desired weights less than 400 is used. 426 // - If the desired weight is 500, 400 is checked first and then the rule for desired weights less than 400 is used. 427 428 static const unsigned fallbackRuleSets = 9; 429 static const unsigned rulesPerSet = 8; 430 static const FontTraitsMask weightFallbackRuleSets[fallbackRuleSets][rulesPerSet] = { 431 { FontWeight200Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, 432 { FontWeight100Mask, FontWeight300Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, 433 { FontWeight200Mask, FontWeight100Mask, FontWeight400Mask, FontWeight500Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, 434 { FontWeight500Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, 435 { FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask, FontWeight600Mask, FontWeight700Mask, FontWeight800Mask, FontWeight900Mask }, 436 { FontWeight700Mask, FontWeight800Mask, FontWeight900Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, 437 { FontWeight800Mask, FontWeight900Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, 438 { FontWeight900Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask }, 439 { FontWeight800Mask, FontWeight700Mask, FontWeight600Mask, FontWeight500Mask, FontWeight400Mask, FontWeight300Mask, FontWeight200Mask, FontWeight100Mask } 440 }; 441 442 unsigned ruleSetIndex = 0; 443 for (; !(desiredTraitsMaskForComparison & (1 << (FontWeight100Bit + ruleSetIndex))); ruleSetIndex++) { } 444 445 const FontTraitsMask* weightFallbackRule = weightFallbackRuleSets[ruleSetIndex]; 446 for (unsigned i = 0; i < rulesPerSet; ++i) { 447 if (secondTraitsMask & weightFallbackRule[i]) 448 return false; 449 if (firstTraitsMask & weightFallbackRule[i]) 450 return true; 451 } 452 453 return false; 454 } 455 456 CSSSegmentedFontFace* CSSFontFaceSet::fontFace(FontTraitsMask traitsMask, const AtomicString& family) 415 CSSSegmentedFontFace* CSSFontFaceSet::fontFace(FontTraitsMask traitsMask, FontSelectionValue stretch, const AtomicString& family) 457 416 { 458 417 auto iterator = m_facesLookupTable.find(family); … … 488 447 } 489 448 490 std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [traitsMask](const CSSFontFace& first, const CSSFontFace& second) { 491 return fontFaceComparator(traitsMask, first, second); 492 }); 493 for (auto& candidate : candidateFontFaces) 494 face->appendFontFace(candidate.get()); 449 if (!candidateFontFaces.isEmpty()) { 450 Vector<FontSelectionCapabilities> capabilities; 451 capabilities.reserveInitialCapacity(candidateFontFaces.size()); 452 for (auto& face : candidateFontFaces) 453 capabilities.uncheckedAppend(face.get().fontSelectionCapabilities()); 454 FontSelectionAlgorithm fontSelectionAlgorithm(fontSelectionRequestForTraitsMask(traitsMask, stretch), capabilities); 455 std::stable_sort(candidateFontFaces.begin(), candidateFontFaces.end(), [&fontSelectionAlgorithm](const CSSFontFace& first, const CSSFontFace& second) { 456 auto firstCapabilities = first.fontSelectionCapabilities(); 457 auto secondCapabilities = second.fontSelectionCapabilities(); 458 459 auto stretchDistanceFirst = fontSelectionAlgorithm.stretchDistance(firstCapabilities).distance; 460 auto stretchDistanceSecond = fontSelectionAlgorithm.stretchDistance(secondCapabilities).distance; 461 if (stretchDistanceFirst < stretchDistanceSecond) 462 return true; 463 if (stretchDistanceFirst > stretchDistanceSecond) 464 return false; 465 466 auto styleDistanceFirst = fontSelectionAlgorithm.styleDistance(firstCapabilities).distance; 467 auto styleDistanceSecond = fontSelectionAlgorithm.styleDistance(secondCapabilities).distance; 468 if (styleDistanceFirst < styleDistanceSecond) 469 return true; 470 if (styleDistanceFirst > styleDistanceSecond) 471 return false; 472 473 auto weightDistanceFirst = fontSelectionAlgorithm.weightDistance(firstCapabilities).distance; 474 auto weightDistanceSecond = fontSelectionAlgorithm.weightDistance(secondCapabilities).distance; 475 if (weightDistanceFirst < weightDistanceSecond) 476 return true; 477 return false; 478 }); 479 for (auto& candidate : candidateFontFaces) 480 face->appendFontFace(candidate.get()); 481 } 495 482 496 483 return face.get(); -
trunk/Source/WebCore/css/CSSFontFaceSet.h
r207396 r213436 68 68 ExceptionOr<bool> check(const String& font, const String& text); 69 69 70 CSSSegmentedFontFace* fontFace(FontTraitsMask, const AtomicString& family);70 CSSSegmentedFontFace* fontFace(FontTraitsMask, FontSelectionValue stretch, const AtomicString& family); 71 71 72 72 enum class Status { Loading, Loaded }; -
trunk/Source/WebCore/css/CSSFontSelector.cpp
r212449 r213436 146 146 RefPtr<CSSValue> fontStyle = style.getPropertyCSSValue(CSSPropertyFontStyle); 147 147 RefPtr<CSSValue> fontWeight = style.getPropertyCSSValue(CSSPropertyFontWeight); 148 RefPtr<CSSValue> fontStretch = style.getPropertyCSSValue(CSSPropertyFontStretch); 148 149 RefPtr<CSSValue> src = style.getPropertyCSSValue(CSSPropertySrc); 149 150 RefPtr<CSSValue> unicodeRange = style.getPropertyCSSValue(CSSPropertyUnicodeRange); … … 168 169 fontWeight = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); 169 170 171 if (!fontStretch) 172 fontStretch = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); 173 170 174 CSSValueList* rangeList = downcast<CSSValueList>(unicodeRange.get()); 171 175 … … 182 186 return; 183 187 if (!fontFace->setWeight(*fontWeight)) 188 return; 189 if (!fontFace->setStretch(*fontStretch)) 184 190 return; 185 191 if (rangeList && !fontFace->setUnicodeRange(*rangeList)) … … 296 302 297 303 AtomicString familyForLookup = resolveGenericFamilyFirst ? resolveGenericFamily(m_document, fontDescription, familyName) : familyName; 298 auto* face = m_cssFontFaceSet->fontFace(fontDescription.traitsMask(), f amilyForLookup);304 auto* face = m_cssFontFaceSet->fontFace(fontDescription.traitsMask(), fontDescription.stretch(), familyForLookup); 299 305 if (!face) { 300 306 if (!resolveGenericFamilyFirst) -
trunk/Source/WebCore/css/FontFace.cpp
r212535 r213436 185 185 } 186 186 187 ExceptionOr<void> FontFace::setStretch(const String&) 188 { 189 // We don't support font-stretch. Swallow the call. 187 ExceptionOr<void> FontFace::setStretch(const String& stretch) 188 { 189 if (stretch.isEmpty()) 190 return Exception { SYNTAX_ERR }; 191 192 bool success = false; 193 if (auto value = parseString(stretch, CSSPropertyFontStretch)) 194 success = m_backing->setStretch(*value); 195 if (!success) 196 return Exception { SYNTAX_ERR }; 190 197 return { }; 191 198 } … … 319 326 String FontFace::stretch() const 320 327 { 321 return ASCIILiteral("normal"); 328 m_backing->updateStyleIfNeeded(); 329 auto stretch = m_backing->stretch(); 330 331 auto rangeIsSingleValue = [](FontSelectionRange range, FontSelectionValue value) -> bool { 332 return range.minimum == value && range.maximum == value; 333 }; 334 335 if (rangeIsSingleValue(stretch, FontSelectionValue(50))) 336 return ASCIILiteral("ultra-condensed"); 337 if (rangeIsSingleValue(stretch, FontSelectionValue(62.5f))) 338 return ASCIILiteral("extra-condensed"); 339 if (rangeIsSingleValue(stretch, FontSelectionValue(75))) 340 return ASCIILiteral("condensed"); 341 if (rangeIsSingleValue(stretch, FontSelectionValue(87.5f))) 342 return ASCIILiteral("semi-condensed"); 343 if (rangeIsSingleValue(stretch, FontSelectionValue(100))) 344 return ASCIILiteral("normal"); 345 if (rangeIsSingleValue(stretch, FontSelectionValue(112.5f))) 346 return ASCIILiteral("semi-expanded"); 347 if (rangeIsSingleValue(stretch, FontSelectionValue(125))) 348 return ASCIILiteral("expanded"); 349 if (rangeIsSingleValue(stretch, FontSelectionValue(150))) 350 return ASCIILiteral("extra-expanded"); 351 if (rangeIsSingleValue(stretch, FontSelectionValue(200))) 352 return ASCIILiteral("ultra-expanded"); 353 354 return String::format("%f-%f", static_cast<float>(stretch.minimum), static_cast<float>(stretch.maximum)); 322 355 } 323 356 -
trunk/Source/WebCore/css/parser/CSSPropertyParser.cpp
r213305 r213436 4186 4186 break; 4187 4187 case CSSPropertyFontStretch: 4188 // FIXME: Implement this. 4189 m_range.consumeIncludingWhitespace(); 4190 parsedValue = CSSValuePool::singleton().createIdentifierValue(CSSValueNormal); 4188 parsedValue = consumeFontStretch(m_range); 4191 4189 break; 4192 4190 case CSSPropertyFontStyle: { -
trunk/Source/WebCore/platform/graphics/FontCache.h
r213341 r213436 204 204 // This function exists so CSSFontSelector can have a unified notion of preinstalled fonts and @font-face. 205 205 // It comes into play when you create an @font-face which shares a family name as a preinstalled font. 206 Vector<FontTraitsMask> getTraitsInFamily(const AtomicString&); 206 struct TraitsAndStretch { 207 FontTraitsMask traits; 208 FontSelectionRange stretch; 209 }; 210 Vector<TraitsAndStretch> getTraitsAndStretchInFamily(const AtomicString&); 207 211 208 212 WEBCORE_EXPORT RefPtr<Font> fontForFamily(const FontDescription&, const AtomicString&, const FontFeatureSettings* fontFaceFeatures = nullptr, const FontVariantSettings* fontFaceVariantSettings = nullptr, bool checkingAlternateName = false); -
trunk/Source/WebCore/platform/graphics/FontDescription.h
r213341 r213436 27 27 28 28 #include "CSSValueKeywords.h" 29 #include "FontSelectionAlgorithm.h" 29 30 #include "FontTaggedSettings.h" 30 31 #include "TextFlags.h" -
trunk/Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
r213341 r213436 663 663 } 664 664 665 Vector<FontTraitsMask> FontCache::getTraitsInFamily(const AtomicString& familyName) 665 static FontSelectionValue stretchFromCoreTextTraits(CFDictionaryRef traits) 666 { 667 auto widthNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits, kCTFontWidthTrait)); 668 if (widthNumber) { 669 // FIXME: The normalization from Core Text's [-1, 1] range to CSS's [50%, 200%] range isn't perfect. 670 float ctWidth; 671 auto success = CFNumberGetValue(widthNumber, kCFNumberFloatType, &ctWidth); 672 ASSERT_UNUSED(success, success); 673 return FontSelectionValue(ctWidth < 0.5 ? ctWidth * 50 + 100 : ctWidth * 150 + 50); 674 } 675 return FontSelectionValue(100); 676 } 677 678 auto FontCache::getTraitsAndStretchInFamily(const AtomicString& familyName) -> Vector<TraitsAndStretch> 666 679 { 667 680 auto familyNameStr = familyName.string().createCFString(); … … 678 691 return { }; 679 692 680 Vector< FontTraitsMask> traitsMasks;681 traitsMasks.reserveInitialCapacity(numMatches);693 Vector<TraitsAndStretch> result; 694 result.reserveInitialCapacity(numMatches); 682 695 for (CFIndex i = 0; i < numMatches; ++i) { 683 696 auto traits = adoptCF((CFDictionaryRef)CTFontDescriptorCopyAttribute((CTFontDescriptorRef)CFArrayGetValueAtIndex(matchedDescriptors.get(), i), kCTFontTraitsAttribute)); … … 689 702 CGFloat weight = 0; 690 703 CFNumberGetValue(weightRef, kCFNumberCGFloatType, &weight); 691 traitsMasks.uncheckedAppend(toTraitsMask(symbolicTraits, weight)); 692 } 693 } 694 return traitsMasks; 704 auto stretch = stretchFromCoreTextTraits(traits.get()); 705 result.uncheckedAppend({ toTraitsMask(symbolicTraits, weight), { stretch, stretch } }); 706 } 707 } 708 return result; 695 709 } 696 710 … … 896 910 FontSelectionValue weight; 897 911 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 } 912 width = stretchFromCoreTextTraits(traits.get()); 906 913 907 914 auto symbolicTraitsNumber = static_cast<CFNumberRef>(CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait)); … … 927 934 } 928 935 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 947 936 private: 948 937 friend class NeverDestroyed<FontDatabase>; … … 954 943 }; 955 944 956 template <typename T> 957 using IterateActiveFontsWithReturnCallback = std::function<std::optional<T>(const FontDatabase::InstalledFont&, size_t)>; 958 959 template <typename T> 960 inline std::optional<T> iterateActiveFontsWithReturn(const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter, IterateActiveFontsWithReturnCallback<T> callback) 961 { 962 for (size_t i = 0; i < installedFonts.size(); ++i) { 963 if (!filter[i]) 964 continue; 965 if (auto result = callback(installedFonts.installedFonts[i], i)) 966 return result; 967 } 968 return std::nullopt; 969 } 970 971 template <typename T> 972 inline void iterateActiveFonts(const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter, T callback) 973 { 974 iterateActiveFontsWithReturn<int>(installedFonts, filter, [&](const FontDatabase::InstalledFont& font, size_t i) -> std::optional<int> { 975 callback(font, i); 976 return std::nullopt; 977 }); 978 } 979 980 static inline std::optional<FontSelectionValue> findClosestStretch(FontSelectionValue targetStretch, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 981 { 982 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 983 984 if (targetStretch >= FontDatabase::stretchThreshold()) { 985 auto threshold = std::max(targetStretch, installedFonts.capabilities.width.maximum); 986 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 987 auto width = font.capabilities.width; 988 ASSERT(width.isValid()); 989 if (width.includes(targetStretch)) 990 return 0; 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; 996 }; 997 } else { 998 ASSERT(targetStretch < FontDatabase::stretchThreshold()); 999 auto threshold = std::min(targetStretch, installedFonts.capabilities.width.minimum); 1000 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1001 auto width = font.capabilities.width; 1002 if (width.includes(targetStretch)) 1003 return 0; 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; 1009 }; 1010 } 1011 1012 size_t closestIndex = 0; 1013 std::optional<float> minimumScore; 1014 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1015 auto score = computeScore(installedFont); 1016 if (!minimumScore || score < minimumScore.value()) { 1017 minimumScore = score; 1018 closestIndex = i; 1019 } 1020 }); 1021 1022 if (!minimumScore) 1023 return std::nullopt; 1024 auto& winner = installedFonts.installedFonts[closestIndex]; 1025 auto width = winner.capabilities.width; 1026 if (width.includes(targetStretch)) 1027 return targetStretch; 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) 1035 { 1036 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1037 if (!installedFont.capabilities.width.includes(target)) 1038 filter[i] = false; 1039 }); 1040 } 1041 1042 static inline std::optional<FontSelectionValue> findClosestStyle(FontSelectionValue targetStyle, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 1043 { 1044 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 1045 1046 if (targetStyle >= FontDatabase::italicThreshold()) { 1047 auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum); 1048 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1049 auto slope = font.capabilities.slope; 1050 ASSERT(slope.isValid()); 1051 if (slope.includes(targetStyle)) 1052 return 0; 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; 1058 }; 1059 } else if (targetStyle >= FontSelectionValue()) { 1060 auto threshold = std::max(targetStyle, installedFonts.capabilities.slope.maximum); 1061 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1062 auto slope = font.capabilities.slope; 1063 ASSERT(slope.isValid()); 1064 if (slope.includes(targetStyle)) 1065 return 0; 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; 1073 }; 1074 } else if (targetStyle > -FontDatabase::italicThreshold()) { 1075 auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum); 1076 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1077 auto slope = font.capabilities.slope; 1078 ASSERT(slope.isValid()); 1079 if (slope.includes(targetStyle)) 1080 return 0; 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; 1088 }; 1089 } else { 1090 ASSERT(targetStyle <= -FontDatabase::italicThreshold()); 1091 auto threshold = std::min(targetStyle, installedFonts.capabilities.slope.minimum); 1092 computeScore = [&, threshold](const FontDatabase::InstalledFont& font) -> float { 1093 auto slope = font.capabilities.slope; 1094 ASSERT(slope.isValid()); 1095 if (slope.includes(targetStyle)) 1096 return 0; 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; 1102 }; 1103 } 1104 1105 size_t closestIndex = 0; 1106 std::optional<float> minimumScore; 1107 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1108 auto score = computeScore(installedFont); 1109 if (!minimumScore || score < minimumScore.value()) { 1110 minimumScore = score; 1111 closestIndex = i; 1112 } 1113 }); 1114 1115 if (!minimumScore) 1116 return std::nullopt; 1117 auto& winner = installedFonts.installedFonts[closestIndex]; 1118 auto slope = winner.capabilities.slope; 1119 if (slope.includes(targetStyle)) 1120 return targetStyle; 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) 1128 { 1129 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1130 if (!installedFont.capabilities.slope.includes(target)) 1131 filter[i] = false; 1132 }); 1133 } 1134 1135 static inline std::optional<FontSelectionValue> findClosestWeight(FontSelectionValue targetWeight, const FontDatabase::InstalledFontFamily& installedFonts, const std::unique_ptr<bool[]>& filter) 1136 { 1137 { 1138 // The spec states: "If the desired weight is 400, 500 is checked first ... If the desired weight is 500, 400 is checked first" 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); 1142 return std::nullopt; 1143 }; 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); 1147 return std::nullopt; 1148 }; 1149 if (targetWeight == FontSelectionValue(400)) { 1150 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor400)) 1151 return result; 1152 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500)) 1153 return result; 1154 } else if (targetWeight == FontSelectionValue(500)) { 1155 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor500)) 1156 return result; 1157 if (auto result = iterateActiveFontsWithReturn(installedFonts, filter, searchFor400)) 1158 return result; 1159 } 1160 } 1161 1162 std::function<float(const FontDatabase::InstalledFont&)> computeScore; 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; 1174 }; 1175 } else { 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; 1187 }; 1188 } 1189 1190 size_t closestIndex = 0; 1191 std::optional<float> minimumScore; 1192 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1193 auto score = computeScore(installedFont); 1194 if (!minimumScore || score < minimumScore.value()) { 1195 minimumScore = score; 1196 closestIndex = i; 1197 } 1198 }); 1199 1200 if (!minimumScore) 1201 return std::nullopt; 1202 auto& winner = installedFonts.installedFonts[closestIndex]; 1203 auto weight = winner.capabilities.weight; 1204 if (weight.includes(targetWeight)) 1205 return targetWeight; 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) 1213 { 1214 iterateActiveFonts(installedFonts, filter, [&](auto& installedFont, size_t i) { 1215 if (!installedFont.capabilities.weight.includes(target)) 1216 filter[i] = false; 1217 }); 1218 } 1219 1220 static inline FontSelectionValue computeTargetWeight(FontWeight weight) 1221 { 945 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, FontSelectionRequest fontSelectionRequest) 946 { 947 Vector<FontSelectionCapabilities> capabilities; 948 capabilities.reserveInitialCapacity(familyFonts.size()); 949 for (auto& font : familyFonts.installedFonts) 950 capabilities.uncheckedAppend(font.capabilities); 951 FontSelectionAlgorithm fontSelectionAlgorithm(fontSelectionRequest, capabilities, familyFonts.capabilities); 952 return &familyFonts.installedFonts[fontSelectionAlgorithm.indexOfBestCapabilities()]; 953 } 954 955 static FontSelectionRequest calculateFontSelectionRequest(CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch) 956 { 957 FontSelectionRequest result; 1222 958 switch (weight) { 1223 959 case FontWeight100: 1224 return FontSelectionValue(100); 960 result.weight = FontSelectionValue(100); 961 break; 1225 962 case FontWeight200: 1226 return FontSelectionValue(200); 963 result.weight = FontSelectionValue(200); 964 break; 1227 965 case FontWeight300: 1228 return FontSelectionValue(300); 966 result.weight = FontSelectionValue(300); 967 break; 1229 968 case FontWeight400: 1230 return FontSelectionValue(400); 969 result.weight = FontSelectionValue(400); 970 break; 1231 971 case FontWeight500: 1232 return FontSelectionValue(500); 972 result.weight = FontSelectionValue(500); 973 break; 1233 974 case FontWeight600: 1234 return FontSelectionValue(600); 975 result.weight = FontSelectionValue(600); 976 break; 1235 977 case FontWeight700: 1236 return FontSelectionValue(700); 978 result.weight = FontSelectionValue(700); 979 break; 1237 980 case FontWeight800: 1238 return FontSelectionValue(800); 981 result.weight = FontSelectionValue(800); 982 break; 1239 983 case FontWeight900: 1240 return FontSelectionValue(900); 1241 default: 1242 ASSERT_NOT_REACHED(); 1243 return FontSelectionValue(400); 1244 } 1245 } 1246 1247 static const FontDatabase::InstalledFont* findClosestFont(const FontDatabase::InstalledFontFamily& familyFonts, CTFontSymbolicTraits requestedTraits, FontWeight weight, FontSelectionValue stretch) 1248 { 1249 ASSERT(!familyFonts.isEmpty()); 1250 1251 // Parallel to familyFonts. 1252 std::unique_ptr<bool[]> filter { new bool[familyFonts.size()] }; 1253 for (size_t i = 0; i < familyFonts.size(); ++i) 1254 filter[i] = true; 1255 1256 if (auto closestStretch = findClosestStretch(stretch, familyFonts, filter)) 1257 filterStretch(closestStretch.value(), familyFonts, filter); 984 result.weight = FontSelectionValue(900); 985 break; 986 default: 987 ASSERT_NOT_REACHED(); 988 result.weight = FontSelectionValue(400); 989 break; 990 } 991 992 result.width = stretch; 993 994 if (requestedTraits & kCTFontTraitItalic) 995 result.slope = italicThreshold(); 1258 996 else 1259 return nullptr; 1260 1261 FontSelectionValue targetStyle = requestedTraits & kCTFontTraitItalic ? FontDatabase::italicThreshold() : FontSelectionValue(); 1262 if (auto closestStyle = findClosestStyle(targetStyle, familyFonts, filter)) 1263 filterStyle(closestStyle.value(), familyFonts, filter); 1264 else 1265 return nullptr; 1266 1267 FontSelectionValue targetWeight = computeTargetWeight(weight); 1268 if (auto closestWeight = findClosestWeight(targetWeight, familyFonts, filter)) 1269 filterWeight(closestWeight.value(), familyFonts, filter); 1270 else 1271 return nullptr; 1272 1273 return iterateActiveFontsWithReturn<const FontDatabase::InstalledFont*>(familyFonts, filter, [](const FontDatabase::InstalledFont& font, size_t) { 1274 return &font; 1275 }).value_or(nullptr); 997 result.slope = FontSelectionValue(); 998 999 return result; 1276 1000 } 1277 1001 … … 1283 1007 if (!isSystemFont(family) && whitelist.size() && !whitelist.contains(family)) 1284 1008 return nullptr; 1285 1286 1009 1287 1010 #if SHOULD_USE_CORE_TEXT_FONT_LOOKUP … … 1301 1024 if (!postScriptFont.fontDescriptor) 1302 1025 return nullptr; 1303 if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.capabilities.slope.maximum < FontDatabase::italicThreshold())1304 || (weight >= FontWeight600 && postScriptFont.capabilities.weight.maximum < FontSelectionValue(600))) {1026 if (((requestedTraits & kCTFontTraitItalic) && postScriptFont.capabilities.slope.maximum < italicThreshold()) 1027 || (weight >= FontWeight600 && postScriptFont.capabilities.weight.maximum < boldThreshold())) { 1305 1028 auto postScriptFamilyName = adoptCF(static_cast<CFStringRef>(CTFontDescriptorCopyAttribute(postScriptFont.fontDescriptor.get(), kCTFontFamilyNameAttribute))); 1306 1029 if (!postScriptFamilyName) … … 1309 1032 if (familyFonts.isEmpty()) 1310 1033 return nullptr; 1311 if (const auto* installedFont = findClosestFont(familyFonts, requestedTraits, weight, stretch)) {1034 if (const auto* installedFont = findClosestFont(familyFonts, calculateFontSelectionRequest(requestedTraits, weight, stretch))) { 1312 1035 if (!installedFont->fontDescriptor) 1313 1036 return nullptr; … … 1319 1042 } 1320 1043 1321 if (const auto* installedFont = findClosestFont(familyFonts, requestedTraits, weight, stretch))1044 if (const auto* installedFont = findClosestFont(familyFonts, calculateFontSelectionRequest(requestedTraits, weight, stretch))) 1322 1045 return adoptCF(CTFontCreateWithFontDescriptor(installedFont->fontDescriptor.get(), size, nullptr)); 1323 1046 -
trunk/Source/WebCore/platform/graphics/freetype/FontCacheFreeType.cpp
r212513 r213436 139 139 } 140 140 141 Vector<FontTraitsMask> FontCache::getTraitsInFamily(const AtomicString&) 141 auto FontCache::getTraitsAndStretchInFamily(const AtomicString& familyName) -> Vector<TraitsAndStretch> 142 142 { 143 143 return { }; -
trunk/Source/WebCore/platform/graphics/win/FontCacheWin.cpp
r212513 r213436 560 560 } 561 561 562 Vector<FontTraitsMask> FontCache::getTraitsInFamily(const AtomicString& familyName) 562 auto FontCache::getTraitsAndStretchInFamily(const AtomicString& familyName) -> Vector<TraitsAndStretch> 563 563 { 564 564 HWndDC hdc(0); … … 573 573 TraitsInFamilyProcData procData(familyName); 574 574 EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); 575 Vector< FontTraitsMask> result;575 Vector<TraitsAndStretch> result; 576 576 result.reserveInitialCapacity(procData.m_traitsMasks.size()); 577 577 for (unsigned mask : procData.m_traitsMasks) 578 result.uncheckedAppend( static_cast<FontTraitsMask>(mask));578 result.uncheckedAppend({ static_cast<FontTraitsMask>(mask), FontSelectionRange(FontSelectionValue(), FontSelectionValue()) }); 579 579 return result; 580 580 } -
trunk/Source/WebCore/platform/text/TextFlags.h
r213341 r213436 25 25 26 26 #pragma once 27 28 #include <wtf/NeverDestroyed.h>29 27 30 28 namespace WebCore { … … 399 397 }; 400 398 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() const421 {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) const427 {428 return FontSelectionValue(m_backing + other.m_backing, RawTag::RawTag);429 }430 431 FontSelectionValue operator-(const FontSelectionValue other) const432 {433 return FontSelectionValue(m_backing - other.m_backing, RawTag::RawTag);434 }435 436 FontSelectionValue operator*(const FontSelectionValue other) const437 {438 return FontSelectionValue(static_cast<int32_t>(m_backing) * other.m_backing / fractionalEntropy, RawTag::RawTag);439 }440 441 FontSelectionValue operator/(const FontSelectionValue other) const442 {443 return FontSelectionValue(static_cast<int32_t>(m_backing) / other.m_backing * fractionalEntropy, RawTag::RawTag);444 }445 446 FontSelectionValue operator-() const447 {448 return FontSelectionValue(-m_backing, RawTag::RawTag);449 }450 451 bool operator==(const FontSelectionValue other) const452 {453 return m_backing == other.m_backing;454 }455 456 bool operator!=(const FontSelectionValue other) const457 {458 return !operator==(other);459 }460 461 bool operator<(const FontSelectionValue other) const462 {463 return m_backing < other.m_backing;464 }465 466 bool operator<=(const FontSelectionValue other) const467 {468 return m_backing <= other.m_backing;469 }470 471 bool operator>(const FontSelectionValue other) const472 {473 return m_backing > other.m_backing;474 }475 476 bool operator>=(const FontSelectionValue other) const477 {478 return m_backing >= other.m_backing;479 }480 481 int16_t rawValue() const482 {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() const513 {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) const530 {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 557 399 enum class Kerning { 558 400 Auto,
Note: See TracChangeset
for help on using the changeset viewer.