1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/renderer_host/dwrite_font_proxy_impl_win.h"
6 
7 #include <shlobj.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <algorithm>
12 #include <memory>
13 #include <set>
14 #include <utility>
15 
16 #include "base/callback_helpers.h"
17 #include "base/check_op.h"
18 #include "base/feature_list.h"
19 #include "base/i18n/case_conversion.h"
20 #include "base/metrics/histogram_functions.h"
21 #include "base/metrics/histogram_macros.h"
22 #include "base/stl_util.h"
23 #include "base/strings/string16.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/task/post_task.h"
27 #include "base/threading/platform_thread.h"
28 #include "base/time/time.h"
29 #include "content/browser/renderer_host/dwrite_font_file_util_win.h"
30 #include "content/browser/renderer_host/dwrite_font_uma_logging_win.h"
31 #include "content/public/common/content_features.h"
32 #include "mojo/public/cpp/bindings/callback_helpers.h"
33 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
34 #include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h"
35 #include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h"
36 #include "third_party/skia/include/core/SkFontMgr.h"
37 #include "third_party/skia/include/core/SkTypeface.h"
38 #include "third_party/skia/include/ports/SkTypeface_win.h"
39 #include "ui/gfx/win/direct_write.h"
40 #include "ui/gfx/win/text_analysis_source.h"
41 
42 namespace mswr = Microsoft::WRL;
43 
44 namespace content {
45 
46 namespace {
47 
48 // These are the fonts that Blink tries to load in getLastResortFallbackFont,
49 // and will crash if none can be loaded.
50 const wchar_t* kLastResortFontNames[] = {
51     L"Sans",     L"Arial",   L"MS UI Gothic",    L"Microsoft Sans Serif",
52     L"Segoe UI", L"Calibri", L"Times New Roman", L"Courier New"};
53 
54 struct RequiredFontStyle {
55   const wchar_t* family_name;
56   DWRITE_FONT_WEIGHT required_weight;
57   DWRITE_FONT_STRETCH required_stretch;
58   DWRITE_FONT_STYLE required_style;
59 };
60 
61 const RequiredFontStyle kRequiredStyles[] = {
62     // The regular version of Gill Sans is actually in the Gill Sans MT family,
63     // and the Gill Sans family typically contains just the ultra-bold styles.
64     {L"gill sans", DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
65      DWRITE_FONT_STYLE_NORMAL},
66     {L"helvetica", DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
67      DWRITE_FONT_STYLE_NORMAL},
68     {L"open sans", DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
69      DWRITE_FONT_STYLE_NORMAL},
70 };
71 
72 // As a workaround for crbug.com/635932, refuse to load some common fonts that
73 // do not contain certain styles. We found that sometimes these fonts are
74 // installed only in specialized styles ('Open Sans' might only be available in
75 // the condensed light variant, or Helvetica might only be available in bold).
76 // That results in a poor user experience because websites that use those fonts
77 // usually expect them to be rendered in the regular variant.
CheckRequiredStylesPresent(IDWriteFontCollection * collection,const base::string16 & family_name,uint32_t family_index)78 bool CheckRequiredStylesPresent(IDWriteFontCollection* collection,
79                                 const base::string16& family_name,
80                                 uint32_t family_index) {
81   for (const auto& font_style : kRequiredStyles) {
82     if (base::EqualsCaseInsensitiveASCII(family_name, font_style.family_name)) {
83       mswr::ComPtr<IDWriteFontFamily> family;
84       if (FAILED(collection->GetFontFamily(family_index, &family))) {
85         DCHECK(false);
86         return true;
87       }
88       mswr::ComPtr<IDWriteFont> font;
89       if (FAILED(family->GetFirstMatchingFont(
90               font_style.required_weight, font_style.required_stretch,
91               font_style.required_style, &font))) {
92         DCHECK(false);
93         return true;
94       }
95 
96       // GetFirstMatchingFont doesn't require strict style matching, so check
97       // the actual font that we got.
98       if (font->GetWeight() != font_style.required_weight ||
99           font->GetStretch() != font_style.required_stretch ||
100           font->GetStyle() != font_style.required_style) {
101         // Not really a loader type, but good to have telemetry on how often
102         // fonts like these are encountered, and the data can be compared with
103         // the other loader types.
104         LogLoaderType(
105             DirectWriteFontLoaderType::FONT_WITH_MISSING_REQUIRED_STYLES);
106         return false;
107       }
108       break;
109     }
110   }
111   return true;
112 }
113 
114 }  // namespace
115 
DWriteFontProxyImpl()116 DWriteFontProxyImpl::DWriteFontProxyImpl()
117     : windows_fonts_path_(GetWindowsFontsPath()) {}
118 
119 DWriteFontProxyImpl::~DWriteFontProxyImpl() = default;
120 
121 // static
Create(mojo::PendingReceiver<blink::mojom::DWriteFontProxy> receiver)122 void DWriteFontProxyImpl::Create(
123     mojo::PendingReceiver<blink::mojom::DWriteFontProxy> receiver) {
124   mojo::MakeSelfOwnedReceiver(std::make_unique<DWriteFontProxyImpl>(),
125                               std::move(receiver));
126 }
127 
SetWindowsFontsPathForTesting(base::string16 path)128 void DWriteFontProxyImpl::SetWindowsFontsPathForTesting(base::string16 path) {
129   windows_fonts_path_.swap(path);
130 }
131 
FindFamily(const base::string16 & family_name,FindFamilyCallback callback)132 void DWriteFontProxyImpl::FindFamily(const base::string16& family_name,
133                                      FindFamilyCallback callback) {
134   InitializeDirectWrite();
135   TRACE_EVENT0("dwrite,fonts", "FontProxyHost::OnFindFamily");
136   UINT32 family_index = UINT32_MAX;
137   if (collection_) {
138     BOOL exists = FALSE;
139     UINT32 index = UINT32_MAX;
140     HRESULT hr =
141         collection_->FindFamilyName(family_name.data(), &index, &exists);
142     if (SUCCEEDED(hr) && exists &&
143         CheckRequiredStylesPresent(collection_.Get(), family_name, index)) {
144       family_index = index;
145     }
146   }
147   std::move(callback).Run(family_index);
148 }
149 
GetFamilyCount(GetFamilyCountCallback callback)150 void DWriteFontProxyImpl::GetFamilyCount(GetFamilyCountCallback callback) {
151   InitializeDirectWrite();
152   TRACE_EVENT0("dwrite,fonts", "FontProxyHost::OnGetFamilyCount");
153   std::move(callback).Run(collection_ ? collection_->GetFontFamilyCount() : 0);
154 }
155 
GetFamilyNames(UINT32 family_index,GetFamilyNamesCallback callback)156 void DWriteFontProxyImpl::GetFamilyNames(UINT32 family_index,
157                                          GetFamilyNamesCallback callback) {
158   InitializeDirectWrite();
159   TRACE_EVENT0("dwrite,fonts", "FontProxyHost::OnGetFamilyNames");
160   callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
161       std::move(callback), std::vector<blink::mojom::DWriteStringPairPtr>());
162   if (!collection_)
163     return;
164 
165   TRACE_EVENT0("dwrite,fonts", "FontProxyHost::DoGetFamilyNames");
166 
167   mswr::ComPtr<IDWriteFontFamily> family;
168   HRESULT hr = collection_->GetFontFamily(family_index, &family);
169   if (FAILED(hr)) {
170     return;
171   }
172 
173   mswr::ComPtr<IDWriteLocalizedStrings> localized_names;
174   hr = family->GetFamilyNames(&localized_names);
175   if (FAILED(hr)) {
176     return;
177   }
178 
179   size_t string_count = localized_names->GetCount();
180 
181   std::vector<base::char16> locale;
182   std::vector<base::char16> name;
183   std::vector<blink::mojom::DWriteStringPairPtr> family_names;
184   for (size_t index = 0; index < string_count; ++index) {
185     UINT32 length = 0;
186     hr = localized_names->GetLocaleNameLength(index, &length);
187     if (FAILED(hr)) {
188       return;
189     }
190     ++length;  // Reserve space for the null terminator.
191     locale.resize(length);
192     hr = localized_names->GetLocaleName(index, locale.data(), length);
193     if (FAILED(hr)) {
194       return;
195     }
196     CHECK_EQ(L'\0', locale[length - 1]);
197 
198     length = 0;
199     hr = localized_names->GetStringLength(index, &length);
200     if (FAILED(hr)) {
201       return;
202     }
203     ++length;  // Reserve space for the null terminator.
204     name.resize(length);
205     hr = localized_names->GetString(index, name.data(), length);
206     if (FAILED(hr)) {
207       return;
208     }
209     CHECK_EQ(L'\0', name[length - 1]);
210 
211     family_names.emplace_back(base::in_place, base::string16(locale.data()),
212                               base::string16(name.data()));
213   }
214   std::move(callback).Run(std::move(family_names));
215 }
216 
GetFontFiles(uint32_t family_index,GetFontFilesCallback callback)217 void DWriteFontProxyImpl::GetFontFiles(uint32_t family_index,
218                                        GetFontFilesCallback callback) {
219   InitializeDirectWrite();
220   TRACE_EVENT0("dwrite,fonts", "FontProxyHost::OnGetFontFiles");
221   callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
222       std::move(callback), std::vector<base::FilePath>(),
223       std::vector<base::File>());
224   if (!collection_)
225     return;
226 
227   mswr::ComPtr<IDWriteFontFamily> family;
228   HRESULT hr = collection_->GetFontFamily(family_index, &family);
229   if (FAILED(hr)) {
230     if (IsLastResortFallbackFont(family_index))
231       LogMessageFilterError(
232           MessageFilterError::LAST_RESORT_FONT_GET_FAMILY_FAILED);
233     return;
234   }
235 
236   UINT32 font_count = family->GetFontCount();
237 
238   std::set<base::string16> path_set;
239   std::set<base::string16> custom_font_path_set;
240   // Iterate through all the fonts in the family, and all the files for those
241   // fonts. If anything goes wrong, bail on the entire family to avoid having
242   // a partially-loaded font family.
243   for (UINT32 font_index = 0; font_index < font_count; ++font_index) {
244     mswr::ComPtr<IDWriteFont> font;
245     hr = family->GetFont(font_index, &font);
246     if (FAILED(hr)) {
247       if (IsLastResortFallbackFont(family_index))
248         LogMessageFilterError(
249             MessageFilterError::LAST_RESORT_FONT_GET_FONT_FAILED);
250       return;
251     }
252 
253     uint32_t dummy_ttc_index = 0;
254     if (!AddFilesForFont(font.Get(), windows_fonts_path_, &path_set,
255                          &custom_font_path_set, &dummy_ttc_index)) {
256       if (IsLastResortFallbackFont(family_index))
257         LogMessageFilterError(
258             MessageFilterError::LAST_RESORT_FONT_ADD_FILES_FAILED);
259     }
260   }
261 
262   std::vector<base::File> file_handles;
263   // For files outside the windows fonts directory we pass them to the renderer
264   // as file handles. The renderer would be unable to open the files directly
265   // due to sandbox policy (it would get ERROR_ACCESS_DENIED instead). Passing
266   // handles allows the renderer to bypass the restriction and use the fonts.
267   for (const base::string16& custom_font_path : custom_font_path_set) {
268     // Specify FLAG_EXCLUSIVE_WRITE to prevent base::File from opening the file
269     // with FILE_SHARE_WRITE access. FLAG_EXCLUSIVE_WRITE doesn't actually open
270     // the file for write access.
271     base::File file(base::FilePath(custom_font_path),
272                     base::File::FLAG_OPEN | base::File::FLAG_READ |
273                         base::File::FLAG_EXCLUSIVE_WRITE);
274     if (file.IsValid()) {
275       file_handles.push_back(std::move(file));
276     }
277   }
278 
279   std::vector<base::FilePath> file_paths;
280   for (const auto& path : path_set) {
281     file_paths.emplace_back(base::FilePath(path));
282   }
283   LogLastResortFontFileCount(file_paths.size());
284   std::move(callback).Run(file_paths, std::move(file_handles));
285 }
286 
MapCharacters(const base::string16 & text,blink::mojom::DWriteFontStylePtr font_style,const base::string16 & locale_name,uint32_t reading_direction,const base::string16 & base_family_name,MapCharactersCallback callback)287 void DWriteFontProxyImpl::MapCharacters(
288     const base::string16& text,
289     blink::mojom::DWriteFontStylePtr font_style,
290     const base::string16& locale_name,
291     uint32_t reading_direction,
292     const base::string16& base_family_name,
293     MapCharactersCallback callback) {
294   InitializeDirectWrite();
295   callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
296       std::move(callback),
297       blink::mojom::MapCharactersResult::New(
298           UINT32_MAX, L"", text.length(), 0.0,
299           blink::mojom::DWriteFontStyle::New(DWRITE_FONT_STYLE_NORMAL,
300                                              DWRITE_FONT_STRETCH_NORMAL,
301                                              DWRITE_FONT_WEIGHT_NORMAL)));
302   if (factory2_ == nullptr || collection_ == nullptr)
303     return;
304   if (font_fallback_ == nullptr) {
305     if (FAILED(factory2_->GetSystemFontFallback(&font_fallback_))) {
306       return;
307     }
308   }
309 
310   mswr::ComPtr<IDWriteFont> mapped_font;
311 
312   mswr::ComPtr<IDWriteNumberSubstitution> number_substitution;
313   if (FAILED(factory2_->CreateNumberSubstitution(
314           DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, locale_name.c_str(),
315           TRUE /* ignoreUserOverride */, &number_substitution))) {
316     DCHECK(false);
317     return;
318   }
319   mswr::ComPtr<IDWriteTextAnalysisSource> analysis_source;
320   if (FAILED(gfx::win::TextAnalysisSource::Create(
321           &analysis_source, text, locale_name, number_substitution.Get(),
322           static_cast<DWRITE_READING_DIRECTION>(reading_direction)))) {
323     DCHECK(false);
324     return;
325   }
326 
327   auto result = blink::mojom::MapCharactersResult::New(
328       UINT32_MAX, L"", text.length(), 0.0,
329       blink::mojom::DWriteFontStyle::New(DWRITE_FONT_STYLE_NORMAL,
330                                          DWRITE_FONT_STRETCH_NORMAL,
331                                          DWRITE_FONT_WEIGHT_NORMAL));
332   if (FAILED(font_fallback_->MapCharacters(
333           analysis_source.Get(), 0, text.length(), collection_.Get(),
334           base_family_name.c_str(),
335           static_cast<DWRITE_FONT_WEIGHT>(font_style->font_weight),
336           static_cast<DWRITE_FONT_STYLE>(font_style->font_slant),
337           static_cast<DWRITE_FONT_STRETCH>(font_style->font_stretch),
338           &result->mapped_length, &mapped_font, &result->scale))) {
339     DCHECK(false);
340     return;
341   }
342 
343   if (mapped_font == nullptr) {
344     std::move(callback).Run(std::move(result));
345     return;
346   }
347 
348   mswr::ComPtr<IDWriteFontFamily> mapped_family;
349   if (FAILED(mapped_font->GetFontFamily(&mapped_family))) {
350     DCHECK(false);
351     return;
352   }
353   mswr::ComPtr<IDWriteLocalizedStrings> family_names;
354   if (FAILED(mapped_family->GetFamilyNames(&family_names))) {
355     DCHECK(false);
356     return;
357   }
358 
359   result->font_style->font_slant = mapped_font->GetStyle();
360   result->font_style->font_stretch = mapped_font->GetStretch();
361   result->font_style->font_weight = mapped_font->GetWeight();
362 
363   std::vector<base::char16> name;
364   size_t name_count = family_names->GetCount();
365   for (size_t name_index = 0; name_index < name_count; name_index++) {
366     UINT32 name_length = 0;
367     if (FAILED(family_names->GetStringLength(name_index, &name_length)))
368       continue;  // Keep trying other names
369 
370     ++name_length;  // Reserve space for the null terminator.
371     name.resize(name_length);
372     if (FAILED(family_names->GetString(name_index, name.data(), name_length)))
373       continue;
374     UINT32 index = UINT32_MAX;
375     BOOL exists = false;
376     if (FAILED(collection_->FindFamilyName(name.data(), &index, &exists)) ||
377         !exists)
378       continue;
379 
380     // Found a matching family!
381     result->family_index = index;
382     result->family_name = name.data();
383     std::move(callback).Run(std::move(result));
384     return;
385   }
386 
387   // Could not find a matching family
388   LogMessageFilterError(MessageFilterError::MAP_CHARACTERS_NO_FAMILY);
389   DCHECK_EQ(result->family_index, UINT32_MAX);
390   DCHECK_GT(result->mapped_length, 0u);
391 }
392 
GetUniqueNameLookupTableIfAvailable(GetUniqueNameLookupTableIfAvailableCallback callback)393 void DWriteFontProxyImpl::GetUniqueNameLookupTableIfAvailable(
394     GetUniqueNameLookupTableIfAvailableCallback callback) {
395   DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching));
396   /* Table is not synchronously available, return immediately. */
397   if (!DWriteFontLookupTableBuilder::GetInstance()
398            ->FontUniqueNameTableReady()) {
399     std::move(callback).Run(false, base::ReadOnlySharedMemoryRegion());
400     return;
401   }
402 
403   std::move(callback).Run(
404       true,
405       DWriteFontLookupTableBuilder::GetInstance()->DuplicateMemoryRegion());
406 }
407 
MatchUniqueFont(const base::string16 & unique_font_name,MatchUniqueFontCallback callback)408 void DWriteFontProxyImpl::MatchUniqueFont(
409     const base::string16& unique_font_name,
410     MatchUniqueFontCallback callback) {
411   TRACE_EVENT0("dwrite,fonts", "DWriteFontProxyImpl::MatchUniqueFont");
412 
413   DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching));
414   callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(std::move(callback),
415                                                          base::FilePath(), 0);
416   InitializeDirectWrite();
417 
418   // We must not get here if this version of DWrite can't handle performing the
419   // search.
420   DCHECK(factory3_.Get());
421   mswr::ComPtr<IDWriteFontSet> system_font_set;
422   HRESULT hr = factory3_->GetSystemFontSet(&system_font_set);
423   if (FAILED(hr))
424     return;
425 
426   DCHECK_GT(system_font_set->GetFontCount(), 0U);
427 
428   mswr::ComPtr<IDWriteFontSet> filtered_set;
429 
430   auto filter_set = [&system_font_set, &filtered_set,
431                      &unique_font_name](DWRITE_FONT_PROPERTY_ID property_id) {
432     TRACE_EVENT0("dwrite,fonts",
433                  "DWriteFontProxyImpl::MatchUniqueFont::filter_set");
434     std::wstring unique_font_name_wide = base::UTF16ToWide(unique_font_name);
435     DWRITE_FONT_PROPERTY search_property = {property_id,
436                                             unique_font_name_wide.c_str(), L""};
437     // GetMatchingFonts() matches all languages according to:
438     // https://docs.microsoft.com/en-us/windows/desktop/api/dwrite_3/ns-dwrite_3-dwrite_font_property
439     HRESULT hr =
440         system_font_set->GetMatchingFonts(&search_property, 1, &filtered_set);
441     return SUCCEEDED(hr);
442   };
443 
444   // Search PostScript name first, otherwise try searching for full font name.
445   // Return if filtering failed.
446   if (!filter_set(DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME))
447     return;
448 
449   if (!filtered_set->GetFontCount() &&
450       !filter_set(DWRITE_FONT_PROPERTY_ID_FULL_NAME)) {
451     return;
452   }
453 
454   if (!filtered_set->GetFontCount())
455     return;
456 
457   mswr::ComPtr<IDWriteFontFaceReference> first_font;
458   hr = filtered_set->GetFontFaceReference(0, &first_font);
459   if (FAILED(hr))
460     return;
461 
462   mswr::ComPtr<IDWriteFontFace3> first_font_face_3;
463   hr = first_font->CreateFontFace(&first_font_face_3);
464   if (FAILED(hr))
465     return;
466 
467   mswr::ComPtr<IDWriteFontFace> first_font_face;
468   hr = first_font_face_3.As<IDWriteFontFace>(&first_font_face);
469   if (FAILED(hr))
470     return;
471 
472   base::string16 font_file_pathname;
473   uint32_t ttc_index;
474   if (FAILED(FontFilePathAndTtcIndex(first_font_face.Get(), font_file_pathname,
475                                      ttc_index))) {
476     return;
477   }
478 
479   base::FilePath path(base::UTF16ToWide(font_file_pathname));
480   std::move(callback).Run(path, ttc_index);
481 }
482 
GetUniqueFontLookupMode(GetUniqueFontLookupModeCallback callback)483 void DWriteFontProxyImpl::GetUniqueFontLookupMode(
484     GetUniqueFontLookupModeCallback callback) {
485   InitializeDirectWrite();
486   // If factory3_ is available, that means we can use IDWriteFontSet to filter
487   // for PostScript name and full font name directly and do not need to build
488   // the lookup table.
489   blink::mojom::UniqueFontLookupMode lookup_mode =
490       factory3_.Get() ? blink::mojom::UniqueFontLookupMode::kSingleLookups
491                       : blink::mojom::UniqueFontLookupMode::kRetrieveTable;
492   std::move(callback).Run(lookup_mode);
493 }
494 
GetUniqueNameLookupTable(GetUniqueNameLookupTableCallback callback)495 void DWriteFontProxyImpl::GetUniqueNameLookupTable(
496     GetUniqueNameLookupTableCallback callback) {
497   DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching));
498   DWriteFontLookupTableBuilder::GetInstance()->QueueShareMemoryRegionWhenReady(
499       base::SequencedTaskRunnerHandle::Get(), std::move(callback));
500 }
501 
FallbackFamilyAndStyleForCodepoint(const std::string & base_family_name,const std::string & locale_name,uint32_t codepoint,FallbackFamilyAndStyleForCodepointCallback callback)502 void DWriteFontProxyImpl::FallbackFamilyAndStyleForCodepoint(
503     const std::string& base_family_name,
504     const std::string& locale_name,
505     uint32_t codepoint,
506     FallbackFamilyAndStyleForCodepointCallback callback) {
507   InitializeDirectWrite();
508   callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
509       std::move(callback),
510       blink::mojom::FallbackFamilyAndStyle::New("",
511                                                 /* weight */ 0,
512                                                 /* width */ 0,
513                                                 /* slant */ 0));
514 
515   if (!codepoint || !collection_ || !factory_)
516     return;
517 
518   sk_sp<SkFontMgr> font_mgr(
519       SkFontMgr_New_DirectWrite(factory_.Get(), collection_.Get()));
520 
521   if (!font_mgr)
522     return;
523 
524   const char* bcp47_locales[] = {locale_name.c_str()};
525   int num_locales = locale_name.empty() ? 0 : 1;
526   const char** locales = locale_name.empty() ? nullptr : bcp47_locales;
527 
528   sk_sp<SkTypeface> typeface(font_mgr->matchFamilyStyleCharacter(
529       base_family_name.c_str(), SkFontStyle(), locales, num_locales,
530       codepoint));
531 
532   if (!typeface)
533     return;
534 
535   SkString family_name;
536   typeface->getFamilyName(&family_name);
537 
538   SkFontStyle font_style = typeface->fontStyle();
539 
540   auto result_fallback_and_style = blink::mojom::FallbackFamilyAndStyle::New(
541       family_name.c_str(), font_style.weight(), font_style.width(),
542       font_style.slant());
543   std::move(callback).Run(std::move(result_fallback_and_style));
544 }
545 
InitializeDirectWrite()546 void DWriteFontProxyImpl::InitializeDirectWrite() {
547   if (direct_write_initialized_)
548     return;
549   direct_write_initialized_ = true;
550 
551   TRACE_EVENT0("dwrite,fonts", "DWriteFontProxyImpl::InitializeDirectWrite");
552 
553   gfx::win::CreateDWriteFactory(&factory_);
554   if (factory_ == nullptr) {
555     // We won't be able to load fonts, but we should still return messages so
556     // renderers don't hang if they for some reason send us a font message.
557     return;
558   }
559 
560   // QueryInterface for IDWriteFactory2. It's ok for this to fail if we are
561   // running an older version of DirectWrite (earlier than Win8.1).
562   factory_.As<IDWriteFactory2>(&factory2_);
563 
564   // QueryInterface for IDwriteFactory3, needed for MatchUniqueFont on Windows
565   // 10. May fail on older versions, in which case, unique font matching must be
566   // done through indexing system fonts using DWriteFontLookupTableBuilder.
567   factory_.As<IDWriteFactory3>(&factory3_);
568 
569   HRESULT hr = factory_->GetSystemFontCollection(&collection_);
570   DCHECK(SUCCEEDED(hr));
571 
572   if (!collection_) {
573     base::UmaHistogramSparse(
574         "DirectWrite.Fonts.Proxy.GetSystemFontCollectionResult", hr);
575     LogMessageFilterError(MessageFilterError::ERROR_NO_COLLECTION);
576     return;
577   }
578 
579   // Temp code to help track down crbug.com/561873
580   for (size_t font = 0; font < base::size(kLastResortFontNames); font++) {
581     uint32_t font_index = 0;
582     BOOL exists = FALSE;
583     if (SUCCEEDED(collection_->FindFamilyName(kLastResortFontNames[font],
584                                               &font_index, &exists)) &&
585         exists && font_index != UINT32_MAX) {
586       last_resort_fonts_.push_back(font_index);
587     }
588   }
589   LogLastResortFontCount(last_resort_fonts_.size());
590 }
591 
IsLastResortFallbackFont(uint32_t font_index)592 bool DWriteFontProxyImpl::IsLastResortFallbackFont(uint32_t font_index) {
593   for (auto iter = last_resort_fonts_.begin(); iter != last_resort_fonts_.end();
594        ++iter) {
595     if (*iter == font_index)
596       return true;
597   }
598   return false;
599 }
600 
601 }  // namespace content
602