1 /*
2 * Copyright (C) 2006, 2007 Apple Computer, Inc.
3 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
33
34 #include <ft2build.h>
35 #include <freetype/freetype.h>
36 #include <unicode/uscript.h>
37
38 #include <memory>
39 #include <string>
40 #include <utility>
41
42 #include "base/debug/alias.h"
43 #include "base/stl_util.h"
44 #include "base/trace_event/trace_event.h"
45 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
46 #include "third_party/blink/public/platform/platform.h"
47 #include "third_party/blink/renderer/platform/fonts/bitmap_glyphs_block_list.h"
48 #include "third_party/blink/renderer/platform/fonts/font_description.h"
49 #include "third_party/blink/renderer/platform/fonts/font_face_creation_params.h"
50 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
51 #include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
52 #include "third_party/blink/renderer/platform/fonts/win/font_fallback_win.h"
53 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
54 #include "third_party/blink/renderer/platform/language.h"
55 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
56 #include "third_party/skia/include/core/SkFontMgr.h"
57 #include "third_party/skia/include/core/SkStream.h"
58 #include "third_party/skia/include/ports/SkTypeface_win.h"
59
60
61 namespace blink {
62
63 HashMap<String, sk_sp<SkTypeface>, CaseFoldingHash>*
64 FontCache::sideloaded_fonts_ = nullptr;
65
66 // Cached system font metrics.
67 AtomicString* FontCache::menu_font_family_name_ = nullptr;
68 int32_t FontCache::menu_font_height_ = 0;
69 AtomicString* FontCache::small_caption_font_family_name_ = nullptr;
70 int32_t FontCache::small_caption_font_height_ = 0;
71 AtomicString* FontCache::status_font_family_name_ = nullptr;
72 int32_t FontCache::status_font_height_ = 0;
73
74 namespace {
75
76 enum FallbackAgreementError {
77 kNoneFound,
78 kLegacyNoneFound,
79 kWinAPINoneFound,
80 kLegacyWinAPIDisagree
81 };
82
LogUmaHistogramFallbackAgreemenError(FallbackAgreementError agreement_error,UBlockCode block_code)83 void LogUmaHistogramFallbackAgreemenError(
84 FallbackAgreementError agreement_error,
85 UBlockCode block_code) {
86 DEFINE_THREAD_SAFE_STATIC_LOCAL(SparseHistogram, legacy_none_found_histogram,
87 ("Blink.Fonts.WinFallback.LegacyNoneFound"));
88 DEFINE_THREAD_SAFE_STATIC_LOCAL(SparseHistogram, win_api_none_found_histogram,
89 ("Blink.Fonts.WinFallback.WinAPINoneFound"));
90 DEFINE_THREAD_SAFE_STATIC_LOCAL(
91 SparseHistogram, legacy_win_api_disagree_histogram,
92 ("Blink.Fonts.WinFallback.LegacyWinAPIDisagree"));
93 DEFINE_THREAD_SAFE_STATIC_LOCAL(SparseHistogram, none_found_histogram,
94 ("Blink.Fonts.WinFallback.NoFallbackFound"));
95 switch (agreement_error) {
96 case kLegacyNoneFound:
97 legacy_none_found_histogram.Sample(block_code);
98 break;
99 case kWinAPINoneFound:
100 win_api_none_found_histogram.Sample(block_code);
101 break;
102 case kLegacyWinAPIDisagree:
103 legacy_win_api_disagree_histogram.Sample(block_code);
104 break;
105 case kNoneFound:
106 none_found_histogram.Sample(block_code);
107 break;
108 }
109 }
110
EnsureMinimumFontHeightIfNeeded(int32_t font_height)111 int32_t EnsureMinimumFontHeightIfNeeded(int32_t font_height) {
112 // Adjustment for codepage 936 to make the fonts more legible in Simplified
113 // Chinese. Please refer to LayoutThemeFontProviderWin.cpp for more
114 // information.
115 return (font_height < 12.0f) && (GetACP() == 936) ? 12.0f : font_height;
116 }
117
118 // Test-only code for matching sideloaded fonts by postscript name. This
119 // implementation is incomplete, as it does not match the full font name and
120 // only uses FT_Get_Postscript_Name, which returns an ASCII font name. This is
121 // intended to pass tests on Windows, where for example src: local(Ahem) is used
122 // in @font-face CSS declarations. Skia does not expose getAdvancedMetrics, so
123 // we use FreeType here to parse the font's postscript name.
FindUniqueFontNameFromSideloadedFonts(const String & font_name,HashMap<String,sk_sp<SkTypeface>,CaseFoldingHash> * sideloaded_fonts)124 sk_sp<SkTypeface> FindUniqueFontNameFromSideloadedFonts(
125 const String& font_name,
126 HashMap<String, sk_sp<SkTypeface>, CaseFoldingHash>* sideloaded_fonts) {
127 CHECK(sideloaded_fonts);
128 FT_Library library;
129 FT_Init_FreeType(&library);
130
131 sk_sp<SkTypeface> return_typeface(nullptr);
132 for (auto& sideloaded_font : sideloaded_fonts->Values()) {
133 // Open ttc index zero as we can assume that we do not sideload TrueType
134 // collections.
135 std::unique_ptr<SkStreamAsset> typeface_stream(
136 sideloaded_font->openStream(nullptr));
137 CHECK(typeface_stream->getMemoryBase());
138 std::string font_family_name;
139 FT_Face font_face;
140 FT_Open_Args open_args = {
141 FT_OPEN_MEMORY,
142 reinterpret_cast<const FT_Byte*>(typeface_stream->getMemoryBase()),
143 typeface_stream->getLength()};
144 CHECK_EQ(FT_Err_Ok, FT_Open_Face(library, &open_args, 0, &font_face));
145 font_family_name = FT_Get_Postscript_Name(font_face);
146 FT_Done_Face(font_face);
147
148 if (font_name.FoldCase() == String(font_family_name.c_str()).FoldCase()) {
149 return_typeface = sideloaded_font;
150 break;
151 }
152 }
153 FT_Done_FreeType(library);
154 return return_typeface;
155 }
156
157 static const char kColorEmojiLocale[] = "und-Zsye";
158 static const char kChineseSimplified[] = "zh-Hant";
159
160 // For Windows out-of-process fallback calls, there is a limiation: only one
161 // passed locale is taken into account when requesting a fallback font from the
162 // DWrite API via Skia API. If we request fallback for a Han ideograph without a
163 // disambiguating locale, results from DWrite are unpredictable and caching such
164 // a font under the ambiguous locale leads to returning wrong fonts for
165 // subsequent requests in font_fallback_win, hence prioritize a
166 // Han-disambiguating locale for CJK characters.
FallbackLocaleForCharacter(const FontDescription & font_description,const FontFallbackPriority & fallback_priority,const UChar32 codepoint)167 const LayoutLocale* FallbackLocaleForCharacter(
168 const FontDescription& font_description,
169 const FontFallbackPriority& fallback_priority,
170 const UChar32 codepoint) {
171 if (fallback_priority == FontFallbackPriority::kEmojiEmoji)
172 return LayoutLocale::Get(kColorEmojiLocale);
173
174 UErrorCode error_code = U_ZERO_ERROR;
175 const UScriptCode char_script = uscript_getScript(codepoint, &error_code);
176 if (U_SUCCESS(error_code) && char_script == USCRIPT_HAN) {
177 // If we were unable to disambiguate the requested Han ideograph from the
178 // content locale, the Accept-Language headers or system locale, assume it's
179 // simplified Chinese. It's important to pass a CJK locale to the fallback
180 // call in order to avoid priming the browser side cache incorrectly with an
181 // ambiguous locale for Han fallback requests.
182 const LayoutLocale* han_locale =
183 LayoutLocale::LocaleForHan(font_description.Locale());
184 return han_locale ? han_locale : LayoutLocale::Get(kChineseSimplified);
185 }
186
187 return font_description.Locale() ? font_description.Locale()
188 : &LayoutLocale::GetDefault();
189 }
190
191 } // namespace
192
193 // static
AddSideloadedFontForTesting(sk_sp<SkTypeface> typeface)194 void FontCache::AddSideloadedFontForTesting(sk_sp<SkTypeface> typeface) {
195 if (!sideloaded_fonts_)
196 sideloaded_fonts_ = new HashMap<String, sk_sp<SkTypeface>, CaseFoldingHash>;
197 SkString name;
198 typeface->getFamilyName(&name);
199 String name_wtf(name.c_str());
200 sideloaded_fonts_->Set(name_wtf, std::move(typeface));
201 }
202
203 // static
SystemFontFamily()204 const AtomicString& FontCache::SystemFontFamily() {
205 return MenuFontFamily();
206 }
207
208 // static
SetMenuFontMetrics(const wchar_t * family_name,int32_t font_height)209 void FontCache::SetMenuFontMetrics(const wchar_t* family_name,
210 int32_t font_height) {
211 menu_font_family_name_ = new AtomicString(family_name);
212 menu_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
213 }
214
215 // static
SetSmallCaptionFontMetrics(const wchar_t * family_name,int32_t font_height)216 void FontCache::SetSmallCaptionFontMetrics(const wchar_t* family_name,
217 int32_t font_height) {
218 small_caption_font_family_name_ = new AtomicString(family_name);
219 small_caption_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
220 }
221
222 // static
SetStatusFontMetrics(const wchar_t * family_name,int32_t font_height)223 void FontCache::SetStatusFontMetrics(const wchar_t* family_name,
224 int32_t font_height) {
225 status_font_family_name_ = new AtomicString(family_name);
226 status_font_height_ = EnsureMinimumFontHeightIfNeeded(font_height);
227 }
228
EnsureServiceConnected()229 void FontCache::EnsureServiceConnected() {
230 if (service_)
231 return;
232 Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
233 service_.BindNewPipeAndPassReceiver());
234 }
235
236 // TODO(https://crbug.com/976737): This function is deprecated and only intended
237 // to run in parallel with the API based OOP font fallback calls to compare the
238 // results and track them in UMA for a while until we decide to remove this
239 // completely.
240 scoped_refptr<SimpleFontData>
GetFallbackFamilyNameFromHardcodedChoices(const FontDescription & font_description,UChar32 codepoint,FontFallbackPriority fallback_priority)241 FontCache::GetFallbackFamilyNameFromHardcodedChoices(
242 const FontDescription& font_description,
243 UChar32 codepoint,
244 FontFallbackPriority fallback_priority) {
245 UScriptCode script;
246 const UChar* legacy_fallback_family = GetFallbackFamily(
247 codepoint, font_description.GenericFamily(), font_description.Locale(),
248 &script, fallback_priority, font_manager_.get());
249
250 if (legacy_fallback_family) {
251 FontFaceCreationParams create_by_family(legacy_fallback_family);
252 FontPlatformData* data =
253 GetFontPlatformData(font_description, create_by_family);
254 if (data && data->FontContainsCharacter(codepoint)) {
255 return FontDataFromFontPlatformData(data, kDoNotRetain);
256 }
257 }
258
259 // If instantiating the returned fallback family was not successful, probe for
260 // a set of potential fonts with wide coverage.
261
262 // Last resort font list : PanUnicode. CJK fonts have a pretty
263 // large repertoire. Eventually, we need to scan all the fonts
264 // on the system to have a Firefox-like coverage.
265 // Make sure that all of them are lowercased.
266 const static wchar_t* const kCjkFonts[] = {
267 L"arial unicode ms", L"ms pgothic", L"simsun", L"gulim", L"pmingliu",
268 L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely
269 // known to Chinese users.
270 L"ar pl shanheisun uni", L"ar pl zenkai uni",
271 L"han nom a", // Complete CJK Ext. A coverage.
272 L"code2000" // Complete CJK Ext. A coverage.
273 // CJK Ext. B fonts are not listed here because it's of no use
274 // with our current non-BMP character handling because we use
275 // Uniscribe for it and that code path does not go through here.
276 };
277
278 const static wchar_t* const kCommonFonts[] = {
279 L"tahoma", L"arial unicode ms", L"lucida sans unicode",
280 L"microsoft sans serif", L"palatino linotype",
281 // Six fonts below (and code2000 at the end) are not from MS, but
282 // once installed, cover a very wide range of characters.
283 L"dejavu serif", L"dejavu sasns", L"freeserif", L"freesans", L"gentium",
284 L"gentiumalt", L"ms pgothic", L"simsun", L"gulim", L"pmingliu",
285 L"code2000"};
286
287 const wchar_t* const* pan_uni_fonts = nullptr;
288 int num_fonts = 0;
289 if (script == USCRIPT_HAN) {
290 pan_uni_fonts = kCjkFonts;
291 num_fonts = base::size(kCjkFonts);
292 } else {
293 pan_uni_fonts = kCommonFonts;
294 num_fonts = base::size(kCommonFonts);
295 }
296 // Font returned from getFallbackFamily may not cover |character|
297 // because it's based on script to font mapping. This problem is
298 // critical enough for non-Latin scripts (especially Han) to
299 // warrant an additional (real coverage) check with fontCotainsCharacter.
300 for (int i = 0; i < num_fonts; ++i) {
301 legacy_fallback_family = pan_uni_fonts[i];
302 FontFaceCreationParams create_by_family(legacy_fallback_family);
303 FontPlatformData* data =
304 GetFontPlatformData(font_description, create_by_family);
305 if (data && data->FontContainsCharacter(codepoint))
306 return FontDataFromFontPlatformData(data, kDoNotRetain);
307 }
308 return nullptr;
309 }
310
GetDWriteFallbackFamily(const FontDescription & font_description,UChar32 codepoint,FontFallbackPriority fallback_priority)311 scoped_refptr<SimpleFontData> FontCache::GetDWriteFallbackFamily(
312 const FontDescription& font_description,
313 UChar32 codepoint,
314 FontFallbackPriority fallback_priority) {
315 const LayoutLocale* fallback_locale = FallbackLocaleForCharacter(
316 font_description, fallback_priority, codepoint);
317 DCHECK(fallback_locale);
318
319 // On Pre Windows 8.1 (where use_skia_font_fallback_ is false) we cannot call
320 // the Skia version, as there is no IDWriteFontFallback (which is
321 // proxyable). If no IDWriteFontFallback API exists in the DWrite Skia
322 // SkTypeface implemnetation it will proceed to call the layoutFallback method
323 // of SkTypeface DWrite implementation. This method we must not call in the
324 // renderer as it causes stability issues due to reaching a path that will try
325 // to load the system font collection in-process and thus load DLLs that are
326 // blocked in the renderer, see comment in dwrite_font_proxy_init_impl_win.cc
327 // InitializeDWriteFontProxy(). Hence, for Windows pre 8.1 we add a
328 // DWriteFontProxy code path to retrieve a family name as string for a
329 // character + language tag and call matchFamilyStyleCharacter on the browser
330 // side, where we can do that.
331 if (!use_skia_font_fallback_) {
332 String fallback_family;
333 SkFontStyle fallback_style;
334
335 if (UNLIKELY(!fallback_params_cache_)) {
336 fallback_params_cache_ = std::make_unique<FallbackFamilyStyleCache>();
337 }
338
339 fallback_params_cache_->Get(
340 font_description.GenericFamily(), fallback_locale->LocaleForSkFontMgr(),
341 fallback_priority, codepoint, &fallback_family, &fallback_style);
342 bool result_from_cache = !fallback_family.IsNull();
343
344 if (!result_from_cache) {
345 EnsureServiceConnected();
346
347 // After Mojo IPC, on the browser side, this ultimately reaches
348 // Skia's matchFamilyStyleCharacter for Windows, which does not implement
349 // traversing the language tag stack but only processes the most important
350 // one, so we use FallbackLocaleForCharacter() to determine what locale to
351 // choose to achieve the best possible result.
352
353 if (!GetOutOfProcessFallbackFamily(
354 codepoint, font_description.GenericFamily(),
355 fallback_locale->LocaleForSkFontMgr(), fallback_priority,
356 service_, &fallback_family, &fallback_style))
357 return nullptr;
358
359 if (fallback_family.IsEmpty())
360 return nullptr;
361 }
362
363 FontFaceCreationParams create_by_family((AtomicString(fallback_family)));
364 FontDescription fallback_updated_font_description(font_description);
365 fallback_updated_font_description.UpdateFromSkiaFontStyle(fallback_style);
366 FontPlatformData* data = GetFontPlatformData(
367 fallback_updated_font_description, create_by_family);
368 if (!data || !data->FontContainsCharacter(codepoint))
369 return nullptr;
370
371 if (!result_from_cache) {
372 fallback_params_cache_->Put(font_description.GenericFamily(),
373 fallback_locale->LocaleForSkFontMgr(),
374 fallback_priority, data->Typeface());
375 }
376 return FontDataFromFontPlatformData(data, kDoNotRetain);
377 } else {
378 std::string family_name = font_description.Family().Family().Utf8();
379
380 Bcp47Vector locales;
381 locales.push_back(fallback_locale->LocaleForSkFontMgr());
382 SkTypeface* typeface = font_manager_->matchFamilyStyleCharacter(
383 family_name.c_str(), font_description.SkiaFontStyle(), locales.data(),
384 locales.size(), codepoint);
385
386 if (!typeface)
387 return nullptr;
388
389 SkString skia_family;
390 typeface->getFamilyName(&skia_family);
391 FontDescription fallback_updated_font_description(font_description);
392 fallback_updated_font_description.UpdateFromSkiaFontStyle(
393 typeface->fontStyle());
394 FontFaceCreationParams create_by_family(ToAtomicString(skia_family));
395 FontPlatformData* data = GetFontPlatformData(
396 fallback_updated_font_description, create_by_family);
397 if (!data || !data->FontContainsCharacter(codepoint))
398 return nullptr;
399 return FontDataFromFontPlatformData(data, kDoNotRetain);
400 }
401 NOTREACHED();
402 return nullptr;
403 }
404
405 // Given the desired base font, this will create a SimpleFontData for a specific
406 // font that can be used to render the given range of characters.
PlatformFallbackFontForCharacter(const FontDescription & font_description,UChar32 character,const SimpleFontData * original_font_data,FontFallbackPriority fallback_priority)407 scoped_refptr<SimpleFontData> FontCache::PlatformFallbackFontForCharacter(
408 const FontDescription& font_description,
409 UChar32 character,
410 const SimpleFontData* original_font_data,
411 FontFallbackPriority fallback_priority) {
412 TRACE_EVENT0("ui", "FontCache::PlatformFallbackFontForCharacter");
413
414 // First try the specified font with standard style & weight.
415 if (fallback_priority != FontFallbackPriority::kEmojiEmoji &&
416 (font_description.Style() == ItalicSlopeValue() ||
417 font_description.Weight() >= BoldWeightValue())) {
418 scoped_refptr<SimpleFontData> font_data =
419 FallbackOnStandardFontStyle(font_description, character);
420 if (font_data)
421 return font_data;
422 }
423
424 scoped_refptr<SimpleFontData> hardcoded_list_fallback_font =
425 GetFallbackFamilyNameFromHardcodedChoices(font_description, character,
426 fallback_priority);
427
428 // Fall through to running the API based fallback on Windows 8.1 and above
429 // where API fallback was previously available.
430 if (RuntimeEnabledFeatures::LegacyWindowsDWriteFontFallbackEnabled() ||
431 (!hardcoded_list_fallback_font && use_skia_font_fallback_)) {
432 scoped_refptr<SimpleFontData> dwrite_fallback_font =
433 GetDWriteFallbackFamily(font_description, character, fallback_priority);
434 if (dwrite_fallback_font) {
435 String dwrite_name =
436 dwrite_fallback_font->PlatformData().FontFamilyName();
437 }
438
439 UBlockCode block_code = ublock_getCode(character);
440 if (!hardcoded_list_fallback_font) {
441 LogUmaHistogramFallbackAgreemenError(kLegacyNoneFound, block_code);
442 }
443 if (!dwrite_fallback_font) {
444 LogUmaHistogramFallbackAgreemenError(kWinAPINoneFound, block_code);
445 }
446 if (hardcoded_list_fallback_font && dwrite_fallback_font) {
447 String hardcoded_family_name =
448 hardcoded_list_fallback_font->PlatformData().FontFamilyName();
449 String dwrite_family_name =
450 dwrite_fallback_font->PlatformData().FontFamilyName();
451 if (hardcoded_family_name != dwrite_family_name) {
452 LogUmaHistogramFallbackAgreemenError(kLegacyWinAPIDisagree, block_code);
453 }
454 }
455 if (!hardcoded_list_fallback_font && !dwrite_fallback_font) {
456 LogUmaHistogramFallbackAgreemenError(kNoneFound, block_code);
457 }
458 return dwrite_fallback_font;
459 }
460
461 return hardcoded_list_fallback_font;
462 }
463
DeprecatedEqualIgnoringCase(const AtomicString & a,const SkString & b)464 static inline bool DeprecatedEqualIgnoringCase(const AtomicString& a,
465 const SkString& b) {
466 return DeprecatedEqualIgnoringCase(a, ToAtomicString(b));
467 }
468
TypefacesMatchesFamily(const SkTypeface * tf,const AtomicString & family)469 static bool TypefacesMatchesFamily(const SkTypeface* tf,
470 const AtomicString& family) {
471 SkTypeface::LocalizedStrings* actual_families =
472 tf->createFamilyNameIterator();
473 bool matches_requested_family = false;
474 SkTypeface::LocalizedString actual_family;
475
476 while (actual_families->next(&actual_family)) {
477 if (DeprecatedEqualIgnoringCase(family, actual_family.fString)) {
478 matches_requested_family = true;
479 break;
480 }
481 }
482 actual_families->unref();
483
484 // getFamilyName may return a name not returned by the
485 // createFamilyNameIterator.
486 // Specifically in cases where Windows substitutes the font based on the
487 // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry
488 // entries.
489 if (!matches_requested_family) {
490 SkString family_name;
491 tf->getFamilyName(&family_name);
492 if (DeprecatedEqualIgnoringCase(family, family_name))
493 matches_requested_family = true;
494 }
495
496 return matches_requested_family;
497 }
498
TypefacesHasWeightSuffix(const AtomicString & family,AtomicString & adjusted_name,FontSelectionValue & variant_weight)499 static bool TypefacesHasWeightSuffix(const AtomicString& family,
500 AtomicString& adjusted_name,
501 FontSelectionValue& variant_weight) {
502 struct FamilyWeightSuffix {
503 const wchar_t* suffix;
504 size_t length;
505 FontSelectionValue weight;
506 };
507 // Mapping from suffix to weight from the DirectWrite documentation.
508 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368082.aspx
509 const static FamilyWeightSuffix kVariantForSuffix[] = {
510 {L" thin", 5, FontSelectionValue(100)},
511 {L" extralight", 11, FontSelectionValue(200)},
512 {L" ultralight", 11, FontSelectionValue(200)},
513 {L" light", 6, FontSelectionValue(300)},
514 {L" regular", 8, FontSelectionValue(400)},
515 {L" medium", 7, FontSelectionValue(500)},
516 {L" demibold", 9, FontSelectionValue(600)},
517 {L" semibold", 9, FontSelectionValue(600)},
518 {L" extrabold", 10, FontSelectionValue(800)},
519 {L" ultrabold", 10, FontSelectionValue(800)},
520 {L" black", 6, FontSelectionValue(900)},
521 {L" heavy", 6, FontSelectionValue(900)}};
522 size_t num_variants = base::size(kVariantForSuffix);
523 for (size_t i = 0; i < num_variants; i++) {
524 const FamilyWeightSuffix& entry = kVariantForSuffix[i];
525 if (family.EndsWith(entry.suffix, kTextCaseUnicodeInsensitive)) {
526 String family_name = family.GetString();
527 family_name.Truncate(family.length() - entry.length);
528 adjusted_name = AtomicString(family_name);
529 variant_weight = entry.weight;
530 return true;
531 }
532 }
533
534 return false;
535 }
536
TypefacesHasStretchSuffix(const AtomicString & family,AtomicString & adjusted_name,FontSelectionValue & variant_stretch)537 static bool TypefacesHasStretchSuffix(const AtomicString& family,
538 AtomicString& adjusted_name,
539 FontSelectionValue& variant_stretch) {
540 struct FamilyStretchSuffix {
541 const wchar_t* suffix;
542 size_t length;
543 FontSelectionValue stretch;
544 };
545 // Mapping from suffix to stretch value from the DirectWrite documentation.
546 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368078.aspx
547 // Also includes Narrow as a synonym for Condensed to to support Arial
548 // Narrow and other fonts following the same naming scheme.
549 const static FamilyStretchSuffix kVariantForSuffix[] = {
550 {L" ultracondensed", 15, UltraCondensedWidthValue()},
551 {L" extracondensed", 15, ExtraCondensedWidthValue()},
552 {L" condensed", 10, CondensedWidthValue()},
553 {L" narrow", 7, CondensedWidthValue()},
554 {L" semicondensed", 14, SemiCondensedWidthValue()},
555 {L" semiexpanded", 13, SemiExpandedWidthValue()},
556 {L" expanded", 9, ExpandedWidthValue()},
557 {L" extraexpanded", 14, ExtraExpandedWidthValue()},
558 {L" ultraexpanded", 14, UltraExpandedWidthValue()}};
559 size_t num_variants = base::size(kVariantForSuffix);
560 for (size_t i = 0; i < num_variants; i++) {
561 const FamilyStretchSuffix& entry = kVariantForSuffix[i];
562 if (family.EndsWith(entry.suffix, kTextCaseUnicodeInsensitive)) {
563 String family_name = family.GetString();
564 family_name.Truncate(family.length() - entry.length);
565 adjusted_name = AtomicString(family_name);
566 variant_stretch = entry.stretch;
567 return true;
568 }
569 }
570
571 return false;
572 }
573
CreateFontPlatformData(const FontDescription & font_description,const FontFaceCreationParams & creation_params,float font_size,AlternateFontName alternate_font_name)574 std::unique_ptr<FontPlatformData> FontCache::CreateFontPlatformData(
575 const FontDescription& font_description,
576 const FontFaceCreationParams& creation_params,
577 float font_size,
578 AlternateFontName alternate_font_name) {
579 TRACE_EVENT0("ui", "FontCache::CreateFontPlatformData");
580
581 DCHECK_EQ(creation_params.CreationType(), kCreateFontByFamily);
582 sk_sp<SkTypeface> typeface;
583
584 std::string name;
585
586 if (alternate_font_name == AlternateFontName::kLocalUniqueFace &&
587 RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()) {
588 typeface = CreateTypefaceFromUniqueName(creation_params);
589
590 if (!typeface && sideloaded_fonts_) {
591 typeface = FindUniqueFontNameFromSideloadedFonts(creation_params.Family(),
592 sideloaded_fonts_);
593 }
594
595 // We do not need to try any heuristic around the font name, as below, for
596 // family matching.
597 if (!typeface)
598 return nullptr;
599
600 } else {
601 typeface = CreateTypeface(font_description, creation_params, name);
602
603 // For a family match, Windows will always give us a valid pointer here,
604 // even if the face name is non-existent. We have to double-check and see if
605 // the family name was really used.
606 if (!typeface ||
607 !TypefacesMatchesFamily(typeface.get(), creation_params.Family())) {
608 AtomicString adjusted_name;
609 FontSelectionValue variant_weight;
610 FontSelectionValue variant_stretch;
611
612 // TODO: crbug.com/627143 LocalFontFaceSource.cpp, which implements
613 // retrieving src: local() font data uses getFontData, which in turn comes
614 // here, to retrieve fonts from the cache and specifies the argument to
615 // local() as family name. So we do not match by full font name or
616 // postscript name as the spec says:
617 // https://drafts.csswg.org/css-fonts-3/#src-desc
618
619 // Prevent one side effect of the suffix translation below where when
620 // matching local("Roboto Regular") it tries to find the closest match
621 // even though that can be a bold font in case of Roboto Bold.
622 if (alternate_font_name == AlternateFontName::kLocalUniqueFace) {
623 return nullptr;
624 }
625
626 if (alternate_font_name == AlternateFontName::kLastResort) {
627 if (!typeface)
628 return nullptr;
629 } else if (TypefacesHasWeightSuffix(creation_params.Family(),
630 adjusted_name, variant_weight)) {
631 FontFaceCreationParams adjusted_params(adjusted_name);
632 FontDescription adjusted_font_description = font_description;
633 adjusted_font_description.SetWeight(variant_weight);
634 typeface =
635 CreateTypeface(adjusted_font_description, adjusted_params, name);
636 if (!typeface ||
637 !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
638 return nullptr;
639 }
640
641 } else if (TypefacesHasStretchSuffix(creation_params.Family(),
642 adjusted_name, variant_stretch)) {
643 FontFaceCreationParams adjusted_params(adjusted_name);
644 FontDescription adjusted_font_description = font_description;
645 adjusted_font_description.SetStretch(variant_stretch);
646 typeface =
647 CreateTypeface(adjusted_font_description, adjusted_params, name);
648 if (!typeface ||
649 !TypefacesMatchesFamily(typeface.get(), adjusted_name)) {
650 return nullptr;
651 }
652 } else {
653 return nullptr;
654 }
655 }
656 }
657
658 std::unique_ptr<FontPlatformData> result = std::make_unique<FontPlatformData>(
659 typeface, name.data(), font_size,
660 (font_description.Weight() >= BoldThreshold() && !typeface->isBold()) ||
661 font_description.IsSyntheticBold(),
662 ((font_description.Style() == ItalicSlopeValue()) &&
663 !typeface->isItalic()) ||
664 font_description.IsSyntheticItalic(),
665 font_description.Orientation());
666
667 result->SetAvoidEmbeddedBitmaps(
668 BitmapGlyphsBlockList::ShouldAvoidEmbeddedBitmapsForTypeface(*typeface));
669
670 return result;
671 }
672
673 } // namespace blink
674