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