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/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/debug/crash_logging.h"
14 #include "base/feature_list.h"
15 #include "base/logging.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/no_destructor.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/task/post_task.h"
20 #include "base/task/thread_pool.h"
21 #include "base/trace_event/trace_event.h"
22 #include "content/child/dwrite_font_proxy/dwrite_localized_strings_win.h"
23 #include "content/public/child/child_thread.h"
24 #include "content/public/common/service_names.mojom.h"
25 
26 namespace mswr = Microsoft::WRL;
27 
28 namespace content {
29 
30 namespace {
31 
32 // This enum is used to define the buckets for an enumerated UMA histogram.
33 // Hence,
34 //   (a) existing enumerated constants should never be deleted or reordered, and
35 //   (b) new constants should only be appended at the end of the enumeration.
36 enum DirectWriteLoadFamilyResult {
37   LOAD_FAMILY_SUCCESS_SINGLE_FAMILY = 0,
38   LOAD_FAMILY_SUCCESS_MATCHED_FAMILY = 1,
39   LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES = 2,
40   LOAD_FAMILY_ERROR_NO_FAMILIES = 3,
41   LOAD_FAMILY_ERROR_NO_COLLECTION = 4,
42 
43   LOAD_FAMILY_MAX_VALUE
44 };
45 
46 // This enum is used to define the buckets for an enumerated UMA histogram.
47 // Hence,
48 //   (a) existing enumerated constants should never be deleted or reordered, and
49 //   (b) new constants should only be appended at the end of the enumeration.
50 enum FontProxyError {
51   FIND_FAMILY_SEND_FAILED = 0,
52   GET_FAMILY_COUNT_SEND_FAILED = 1,
53   COLLECTION_KEY_INVALID = 2,
54   FAMILY_INDEX_OUT_OF_RANGE = 3,
55   GET_FONT_FILES_SEND_FAILED = 4,
56   MAPPED_FILE_FAILED = 5,
57   DUPLICATE_HANDLE_FAILED = 6,
58 
59   FONT_PROXY_ERROR_MAX_VALUE
60 };
61 
LogLoadFamilyResult(DirectWriteLoadFamilyResult result)62 void LogLoadFamilyResult(DirectWriteLoadFamilyResult result) {
63   UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamilyResult", result,
64                             LOAD_FAMILY_MAX_VALUE);
65 }
66 
LogFamilyCount(uint32_t count)67 void LogFamilyCount(uint32_t count) {
68   UMA_HISTOGRAM_COUNTS_1000("DirectWrite.Fonts.Proxy.FamilyCount", count);
69 }
70 
LogFontProxyError(FontProxyError error)71 void LogFontProxyError(FontProxyError error) {
72   UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.FontProxyError", error,
73                             FONT_PROXY_ERROR_MAX_VALUE);
74 }
75 
76 }  // namespace
77 
Create(DWriteFontCollectionProxy ** proxy_out,IDWriteFactory * dwrite_factory,mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy)78 HRESULT DWriteFontCollectionProxy::Create(
79     DWriteFontCollectionProxy** proxy_out,
80     IDWriteFactory* dwrite_factory,
81     mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy) {
82   return Microsoft::WRL::MakeAndInitialize<DWriteFontCollectionProxy>(
83       proxy_out, dwrite_factory, std::move(proxy));
84 }
85 
86 DWriteFontCollectionProxy::DWriteFontCollectionProxy() = default;
87 
88 DWriteFontCollectionProxy::~DWriteFontCollectionProxy() = default;
89 
FindFamilyName(const WCHAR * family_name,UINT32 * index,BOOL * exists)90 HRESULT DWriteFontCollectionProxy::FindFamilyName(const WCHAR* family_name,
91                                                   UINT32* index,
92                                                   BOOL* exists) {
93   DCHECK(family_name);
94   DCHECK(index);
95   DCHECK(exists);
96   TRACE_EVENT0("dwrite,fonts", "FontProxy::FindFamilyName");
97 
98   uint32_t family_index = 0;
99   base::string16 name(family_name);
100 
101   auto iter = family_names_.find(name);
102   if (iter != family_names_.end()) {
103     *index = iter->second;
104     *exists = iter->second != UINT_MAX;
105     return S_OK;
106   }
107 
108   if (!GetFontProxy().FindFamily(name, &family_index)) {
109     LogFontProxyError(FIND_FAMILY_SEND_FAILED);
110     return E_FAIL;
111   }
112 
113   if (family_index != UINT32_MAX) {
114     if (!CreateFamily(family_index))
115       return E_FAIL;
116     *exists = TRUE;
117     *index = family_index;
118     families_[family_index]->SetName(name);
119   } else {
120     *exists = FALSE;
121     *index = UINT32_MAX;
122   }
123 
124   family_names_[name] = *index;
125   return S_OK;
126 }
127 
GetFontFamily(UINT32 index,IDWriteFontFamily ** font_family)128 HRESULT DWriteFontCollectionProxy::GetFontFamily(
129     UINT32 index,
130     IDWriteFontFamily** font_family) {
131   DCHECK(font_family);
132 
133   if (index < families_.size() && families_[index]) {
134     families_[index].CopyTo(font_family);
135     return S_OK;
136   }
137 
138   if (!CreateFamily(index))
139     return E_FAIL;
140 
141   families_[index].CopyTo(font_family);
142   return S_OK;
143 }
144 
GetFontFamilyCount()145 UINT32 DWriteFontCollectionProxy::GetFontFamilyCount() {
146   if (family_count_ != UINT_MAX)
147     return family_count_;
148 
149   TRACE_EVENT0("dwrite,fonts", "FontProxy::GetFontFamilyCount");
150 
151   uint32_t family_count = 0;
152   if (!GetFontProxy().GetFamilyCount(&family_count)) {
153     LogFontProxyError(GET_FAMILY_COUNT_SEND_FAILED);
154     return 0;
155   }
156 
157   LogFamilyCount(family_count);
158   family_count_ = family_count;
159   return family_count;
160 }
161 
GetFontFromFontFace(IDWriteFontFace * font_face,IDWriteFont ** font)162 HRESULT DWriteFontCollectionProxy::GetFontFromFontFace(
163     IDWriteFontFace* font_face,
164     IDWriteFont** font) {
165   DCHECK(font_face);
166   DCHECK(font);
167 
168   for (const auto& family : families_) {
169     if (family && family->GetFontFromFontFace(font_face, font)) {
170       return S_OK;
171     }
172   }
173   // If the font came from our collection, at least one family should match
174   DCHECK(false);
175 
176   return E_FAIL;
177 }
178 
CreateEnumeratorFromKey(IDWriteFactory * factory,const void * collection_key,UINT32 collection_key_size,IDWriteFontFileEnumerator ** font_file_enumerator)179 HRESULT DWriteFontCollectionProxy::CreateEnumeratorFromKey(
180     IDWriteFactory* factory,
181     const void* collection_key,
182     UINT32 collection_key_size,
183     IDWriteFontFileEnumerator** font_file_enumerator) {
184   if (!collection_key || collection_key_size != sizeof(uint32_t)) {
185     LogFontProxyError(COLLECTION_KEY_INVALID);
186     return E_INVALIDARG;
187   }
188 
189   TRACE_EVENT0("dwrite,fonts", "FontProxy::LoadingFontFiles");
190 
191   const uint32_t* family_index =
192       reinterpret_cast<const uint32_t*>(collection_key);
193 
194   if (*family_index >= GetFontFamilyCount()) {
195     LogFontProxyError(FAMILY_INDEX_OUT_OF_RANGE);
196     return E_INVALIDARG;
197   }
198 
199   // If we already loaded the family we should reuse the existing collection.
200   DCHECK(!families_[*family_index]->IsLoaded());
201 
202   std::vector<base::FilePath> file_names;
203   std::vector<base::File> file_handles;
204   if (!GetFontProxy().GetFontFiles(*family_index, &file_names, &file_handles)) {
205     LogFontProxyError(GET_FONT_FILES_SEND_FAILED);
206     return E_FAIL;
207   }
208 
209   std::vector<HANDLE> handles;
210   handles.reserve(file_names.size() + file_handles.size());
211   for (const base::FilePath& file_name : file_names) {
212     // This leaks the handles, since they are used as the reference key to
213     // CreateStreamFromKey, and DirectWrite requires the reference keys to
214     // remain valid for the lifetime of the loader. The loader is the font
215     // collection proxy, which remains alive for the lifetime of the renderer.
216     HANDLE handle =
217         CreateFile(file_name.value().c_str(), GENERIC_READ, FILE_SHARE_READ,
218                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
219     if (handle != INVALID_HANDLE_VALUE)
220       handles.push_back(handle);
221   }
222   for (auto& file_handle : file_handles) {
223     handles.push_back(file_handle.TakePlatformFile());
224   }
225 
226   HRESULT hr = mswr::MakeAndInitialize<FontFileEnumerator>(
227       font_file_enumerator, factory, this, &handles);
228 
229   if (!SUCCEEDED(hr)) {
230     DCHECK(false);
231     return E_FAIL;
232   }
233 
234   return S_OK;
235 }
236 
CreateStreamFromKey(const void * font_file_reference_key,UINT32 font_file_reference_key_size,IDWriteFontFileStream ** font_file_stream)237 HRESULT DWriteFontCollectionProxy::CreateStreamFromKey(
238     const void* font_file_reference_key,
239     UINT32 font_file_reference_key_size,
240     IDWriteFontFileStream** font_file_stream) {
241   if (font_file_reference_key_size != sizeof(HANDLE)) {
242     return E_FAIL;
243   }
244 
245   TRACE_EVENT0("dwrite,fonts", "FontFileEnumerator::CreateStreamFromKey");
246 
247   HANDLE file_handle =
248       *reinterpret_cast<const HANDLE*>(font_file_reference_key);
249 
250   if (file_handle == NULL || file_handle == INVALID_HANDLE_VALUE) {
251     DCHECK(false);
252     return E_FAIL;
253   }
254 
255   mswr::ComPtr<FontFileStream> stream;
256   if (!SUCCEEDED(
257           mswr::MakeAndInitialize<FontFileStream>(&stream, file_handle))) {
258     DCHECK(false);
259     return E_FAIL;
260   }
261   *font_file_stream = stream.Detach();
262   return S_OK;
263 }
264 
RuntimeClassInitialize(IDWriteFactory * factory,mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy)265 HRESULT DWriteFontCollectionProxy::RuntimeClassInitialize(
266     IDWriteFactory* factory,
267     mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy) {
268   DCHECK(factory);
269 
270   factory_ = factory;
271   if (proxy)
272     SetProxy(std::move(proxy));
273   else
274     main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
275 
276   HRESULT hr = factory->RegisterFontCollectionLoader(this);
277   DCHECK(SUCCEEDED(hr));
278   hr = factory_->RegisterFontFileLoader(this);
279   DCHECK(SUCCEEDED(hr));
280   return S_OK;
281 }
282 
Unregister()283 void DWriteFontCollectionProxy::Unregister() {
284   factory_->UnregisterFontCollectionLoader(this);
285   factory_->UnregisterFontFileLoader(this);
286 }
287 
LoadFamily(UINT32 family_index,IDWriteFontCollection ** containing_collection)288 bool DWriteFontCollectionProxy::LoadFamily(
289     UINT32 family_index,
290     IDWriteFontCollection** containing_collection) {
291   TRACE_EVENT0("dwrite,fonts", "FontProxy::LoadFamily");
292 
293   uint32_t index = family_index;
294   // CreateCustomFontCollection ends up calling
295   // DWriteFontCollectionProxy::CreateEnumeratorFromKey.
296   HRESULT hr = factory_->CreateCustomFontCollection(
297       this /*collectionLoader*/, reinterpret_cast<const void*>(&index),
298       sizeof(index), containing_collection);
299 
300   return SUCCEEDED(hr);
301 }
302 
GetFontFamily(UINT32 family_index,const base::string16 & family_name,IDWriteFontFamily ** font_family)303 bool DWriteFontCollectionProxy::GetFontFamily(UINT32 family_index,
304                                               const base::string16& family_name,
305                                               IDWriteFontFamily** font_family) {
306   DCHECK(font_family);
307   DCHECK(!family_name.empty());
308   if (!CreateFamily(family_index))
309     return false;
310 
311   mswr::ComPtr<DWriteFontFamilyProxy>& family = families_[family_index];
312   if (!family->IsLoaded() || family->GetName().empty())
313     family->SetName(family_name);
314 
315   family.CopyTo(font_family);
316   return true;
317 }
318 
LoadFamilyNames(UINT32 family_index,IDWriteLocalizedStrings ** localized_strings)319 bool DWriteFontCollectionProxy::LoadFamilyNames(
320     UINT32 family_index,
321     IDWriteLocalizedStrings** localized_strings) {
322   TRACE_EVENT0("dwrite,fonts", "FontProxy::LoadFamilyNames");
323 
324   std::vector<blink::mojom::DWriteStringPairPtr> pairs;
325   if (!GetFontProxy().GetFamilyNames(family_index, &pairs)) {
326     return false;
327   }
328   std::vector<std::pair<base::string16, base::string16>> strings;
329   for (auto& pair : pairs) {
330     strings.emplace_back(std::move(pair->first), std::move(pair->second));
331   }
332 
333   HRESULT hr = mswr::MakeAndInitialize<DWriteLocalizedStrings>(
334       localized_strings, &strings);
335 
336   return SUCCEEDED(hr);
337 }
338 
CreateFamily(UINT32 family_index)339 bool DWriteFontCollectionProxy::CreateFamily(UINT32 family_index) {
340   if (family_index < families_.size() && families_[family_index])
341     return true;
342 
343   UINT32 family_count = GetFontFamilyCount();
344   if (family_index >= family_count) {
345     return false;
346   }
347 
348   if (families_.size() < family_count)
349     families_.resize(family_count);
350 
351   mswr::ComPtr<DWriteFontFamilyProxy> family;
352   HRESULT hr = mswr::MakeAndInitialize<DWriteFontFamilyProxy>(&family, this,
353                                                               family_index);
354   DCHECK(SUCCEEDED(hr));
355   DCHECK_LT(family_index, families_.size());
356 
357   families_[family_index] = family;
358   return true;
359 }
360 
SetProxy(mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy)361 void DWriteFontCollectionProxy::SetProxy(
362     mojo::PendingRemote<blink::mojom::DWriteFontProxy> proxy) {
363   font_proxy_ = blink::mojom::ThreadSafeDWriteFontProxyPtr::Create(
364       std::move(proxy), base::ThreadPool::CreateSequencedTaskRunner(
365                             {base::WithBaseSyncPrimitives()}));
366 }
367 
GetFontProxy()368 blink::mojom::DWriteFontProxy& DWriteFontCollectionProxy::GetFontProxy() {
369   if (!font_proxy_) {
370     mojo::PendingRemote<blink::mojom::DWriteFontProxy> dwrite_font_proxy;
371     if (main_task_runner_->RunsTasksInCurrentSequence()) {
372       ChildThread::Get()->BindHostReceiver(
373           dwrite_font_proxy.InitWithNewPipeAndPassReceiver());
374     } else {
375       main_task_runner_->PostTask(
376           FROM_HERE,
377           base::BindOnce(
378               [](mojo::PendingReceiver<blink::mojom::DWriteFontProxy>
379                      receiver) {
380                 ChildThread::Get()->BindHostReceiver(std::move(receiver));
381               },
382               dwrite_font_proxy.InitWithNewPipeAndPassReceiver()));
383     }
384     SetProxy(std::move(dwrite_font_proxy));
385   }
386   return **font_proxy_;
387 }
388 
389 DWriteFontFamilyProxy::DWriteFontFamilyProxy() = default;
390 
391 DWriteFontFamilyProxy::~DWriteFontFamilyProxy() = default;
392 
GetFontCollection(IDWriteFontCollection ** font_collection)393 HRESULT DWriteFontFamilyProxy::GetFontCollection(
394     IDWriteFontCollection** font_collection) {
395   DCHECK(font_collection);
396 
397   proxy_collection_.CopyTo(font_collection);
398   return S_OK;
399 }
400 
GetFontCount()401 UINT32 DWriteFontFamilyProxy::GetFontCount() {
402   // We could conceivably proxy just the font count. However, calling
403   // GetFontCount is almost certain to be followed by a series of GetFont
404   // calls which will need to load all the fonts anyway, so we might as
405   // well save an IPC here.
406   if (!LoadFamily())
407     return 0;
408 
409   return family_->GetFontCount();
410 }
411 
GetFont(UINT32 index,IDWriteFont ** font)412 HRESULT DWriteFontFamilyProxy::GetFont(UINT32 index, IDWriteFont** font) {
413   DCHECK(font);
414 
415   if (index >= GetFontCount()) {
416     return E_INVALIDARG;
417   }
418   if (!LoadFamily())
419     return E_FAIL;
420 
421   return family_->GetFont(index, font);
422 }
423 
GetFamilyNames(IDWriteLocalizedStrings ** names)424 HRESULT DWriteFontFamilyProxy::GetFamilyNames(IDWriteLocalizedStrings** names) {
425   DCHECK(names);
426 
427   // Prefer the real thing, if available.
428   if (family_) {
429     family_names_.Reset();  // Release cached data.
430     return family_->GetFamilyNames(names);
431   }
432 
433   // If already cached, use the cache.
434   if (family_names_) {
435     family_names_.CopyTo(names);
436     return S_OK;
437   }
438 
439   TRACE_EVENT0("dwrite,fonts", "FontProxy::GetFamilyNames");
440 
441   // Otherwise, do the IPC.
442   if (!proxy_collection_->LoadFamilyNames(family_index_, &family_names_))
443     return E_FAIL;
444 
445   family_names_.CopyTo(names);
446   return S_OK;
447 }
448 
GetFirstMatchingFont(DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFont ** matching_font)449 HRESULT DWriteFontFamilyProxy::GetFirstMatchingFont(
450     DWRITE_FONT_WEIGHT weight,
451     DWRITE_FONT_STRETCH stretch,
452     DWRITE_FONT_STYLE style,
453     IDWriteFont** matching_font) {
454   DCHECK(matching_font);
455 
456   if (!LoadFamily())
457     return E_FAIL;
458 
459   return family_->GetFirstMatchingFont(weight, stretch, style, matching_font);
460 }
461 
GetMatchingFonts(DWRITE_FONT_WEIGHT weight,DWRITE_FONT_STRETCH stretch,DWRITE_FONT_STYLE style,IDWriteFontList ** matching_fonts)462 HRESULT DWriteFontFamilyProxy::GetMatchingFonts(
463     DWRITE_FONT_WEIGHT weight,
464     DWRITE_FONT_STRETCH stretch,
465     DWRITE_FONT_STYLE style,
466     IDWriteFontList** matching_fonts) {
467   DCHECK(matching_fonts);
468 
469   if (!LoadFamily())
470     return E_FAIL;
471 
472   return family_->GetMatchingFonts(weight, stretch, style, matching_fonts);
473 }
474 
RuntimeClassInitialize(DWriteFontCollectionProxy * collection,UINT32 index)475 HRESULT DWriteFontFamilyProxy::RuntimeClassInitialize(
476     DWriteFontCollectionProxy* collection,
477     UINT32 index) {
478   DCHECK(collection);
479 
480   proxy_collection_ = collection;
481   family_index_ = index;
482   return S_OK;
483 }
484 
GetFontFromFontFace(IDWriteFontFace * font_face,IDWriteFont ** font)485 bool DWriteFontFamilyProxy::GetFontFromFontFace(IDWriteFontFace* font_face,
486                                                 IDWriteFont** font) {
487   DCHECK(font_face);
488   DCHECK(font);
489 
490   if (!family_)
491     return false;
492 
493   mswr::ComPtr<IDWriteFontCollection> collection;
494   HRESULT hr = family_->GetFontCollection(&collection);
495   DCHECK(SUCCEEDED(hr));
496   hr = collection->GetFontFromFontFace(font_face, font);
497 
498   return SUCCEEDED(hr);
499 }
500 
SetName(const base::string16 & family_name)501 void DWriteFontFamilyProxy::SetName(const base::string16& family_name) {
502   family_name_.assign(family_name);
503 }
504 
GetName()505 const base::string16& DWriteFontFamilyProxy::GetName() {
506   return family_name_;
507 }
508 
IsLoaded()509 bool DWriteFontFamilyProxy::IsLoaded() {
510   return family_ != nullptr;
511 }
512 
LoadFamily()513 bool DWriteFontFamilyProxy::LoadFamily() {
514   if (family_)
515     return true;
516 
517   SCOPED_UMA_HISTOGRAM_TIMER("DirectWrite.Fonts.Proxy.LoadFamilyTime");
518   TRACE_EVENT0("dwrite,fonts", "DWriteFontFamilyProxy::LoadFamily");
519 
520   auto* font_key_name = base::debug::AllocateCrashKeyString(
521       "font_key_name", base::debug::CrashKeySize::Size32);
522   base::debug::ScopedCrashKeyString crash_key(font_key_name,
523                                               base::WideToUTF8(family_name_));
524 
525   mswr::ComPtr<IDWriteFontCollection> collection;
526   if (!proxy_collection_->LoadFamily(family_index_, &collection)) {
527     LogLoadFamilyResult(LOAD_FAMILY_ERROR_NO_COLLECTION);
528     return false;
529   }
530 
531   UINT32 family_count = collection->GetFontFamilyCount();
532 
533   HRESULT hr;
534   if (family_count > 1) {
535     // Some fonts are packaged in a single file containing multiple families. In
536     // such a case we can find the right family by family name.
537     DCHECK(!family_name_.empty());
538     UINT32 family_index = 0;
539     BOOL found = FALSE;
540     hr =
541         collection->FindFamilyName(family_name_.c_str(), &family_index, &found);
542     if (SUCCEEDED(hr) && found) {
543       hr = collection->GetFontFamily(family_index, &family_);
544       LogLoadFamilyResult(LOAD_FAMILY_SUCCESS_MATCHED_FAMILY);
545       return SUCCEEDED(hr);
546     }
547   }
548 
549   DCHECK_LE(family_count, 1u);
550 
551   if (family_count == 0) {
552     // This is really strange, we successfully loaded no fonts?!
553     LogLoadFamilyResult(LOAD_FAMILY_ERROR_NO_FAMILIES);
554     return false;
555   }
556 
557   LogLoadFamilyResult(family_count == 1 ? LOAD_FAMILY_SUCCESS_SINGLE_FAMILY
558                                         : LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES);
559 
560   hr = collection->GetFontFamily(0, &family_);
561 
562   return SUCCEEDED(hr);
563 }
564 
565 FontFileEnumerator::FontFileEnumerator() = default;
566 
567 FontFileEnumerator::~FontFileEnumerator() = default;
568 
GetCurrentFontFile(IDWriteFontFile ** file)569 HRESULT FontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** file) {
570   DCHECK(file);
571   if (current_file_ >= files_.size()) {
572     return E_FAIL;
573   }
574 
575   TRACE_EVENT0("dwrite,fonts", "FontFileEnumerator::GetCurrentFontFile");
576 
577   // CreateCustomFontFileReference ends up calling
578   // DWriteFontCollectionProxy::CreateStreamFromKey.
579   HRESULT hr = factory_->CreateCustomFontFileReference(
580       reinterpret_cast<const void*>(&files_[current_file_]),
581       sizeof(files_[current_file_]), loader_.Get() /*IDWriteFontFileLoader*/,
582       file);
583   DCHECK(SUCCEEDED(hr));
584   return hr;
585 }
586 
MoveNext(BOOL * has_current_file)587 HRESULT FontFileEnumerator::MoveNext(BOOL* has_current_file) {
588   DCHECK(has_current_file);
589 
590   TRACE_EVENT0("dwrite,fonts", "FontFileEnumerator::MoveNext");
591   if (next_file_ >= files_.size()) {
592     *has_current_file = FALSE;
593     current_file_ = UINT_MAX;
594     return S_OK;
595   }
596 
597   current_file_ = next_file_;
598   ++next_file_;
599   *has_current_file = TRUE;
600   return S_OK;
601 }
602 
RuntimeClassInitialize(IDWriteFactory * factory,IDWriteFontFileLoader * loader,std::vector<HANDLE> * files)603 HRESULT FontFileEnumerator::RuntimeClassInitialize(
604     IDWriteFactory* factory,
605     IDWriteFontFileLoader* loader,
606     std::vector<HANDLE>* files) {
607   factory_ = factory;
608   loader_ = loader;
609   files_.swap(*files);
610   return S_OK;
611 }
612 
613 FontFileStream::FontFileStream() = default;
614 
615 FontFileStream::~FontFileStream() = default;
616 
GetFileSize(UINT64 * file_size)617 HRESULT FontFileStream::GetFileSize(UINT64* file_size) {
618   *file_size = data_.length();
619   return S_OK;
620 }
621 
GetLastWriteTime(UINT64 * last_write_time)622 HRESULT FontFileStream::GetLastWriteTime(UINT64* last_write_time) {
623   *last_write_time = 0;
624   return S_OK;
625 }
626 
ReadFileFragment(const void ** fragment_start,UINT64 fragment_offset,UINT64 fragment_size,void ** fragment_context)627 HRESULT FontFileStream::ReadFileFragment(const void** fragment_start,
628                                          UINT64 fragment_offset,
629                                          UINT64 fragment_size,
630                                          void** fragment_context) {
631   if (fragment_offset + fragment_size < fragment_offset)
632     return E_FAIL;
633   if (fragment_offset + fragment_size > data_.length())
634     return E_FAIL;
635   *fragment_start = data_.data() + fragment_offset;
636   *fragment_context = nullptr;
637   return S_OK;
638 }
639 
RuntimeClassInitialize(HANDLE handle)640 HRESULT FontFileStream::RuntimeClassInitialize(HANDLE handle) {
641   // Duplicate the original handle so we can reopen the file after the memory
642   // mapped section closes it.
643   HANDLE duplicate_handle;
644   if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
645                        &duplicate_handle, 0 /* dwDesiredAccess */,
646                        false /* bInheritHandle */, DUPLICATE_SAME_ACCESS)) {
647     LogFontProxyError(DUPLICATE_HANDLE_FAILED);
648     return E_FAIL;
649   }
650 
651   if (!data_.Initialize(base::File(duplicate_handle))) {
652     LogFontProxyError(MAPPED_FILE_FAILED);
653     return E_FAIL;
654   }
655   return S_OK;
656 }
657 
658 }  // namespace content
659