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