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