OLD | NEW |
| (Empty) |
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 <utility> | |
8 | |
9 #include "base/debug/crash_logging.h" | |
10 #include "base/logging.h" | |
11 #include "base/metrics/histogram_macros.h" | |
12 #include "base/strings/utf_string_conversions.h" | |
13 #include "base/win/scoped_handle.h" | |
14 #include "content/child/dwrite_font_proxy/dwrite_localized_strings_win.h" | |
15 #include "content/common/dwrite_font_proxy_messages.h" | |
16 #include "ipc/ipc_sender.h" | |
17 | |
18 namespace mswr = Microsoft::WRL; | |
19 | |
20 namespace content { | |
21 | |
22 namespace { | |
23 | |
24 // This enum is used to define the buckets for an enumerated UMA histogram. | |
25 // Hence, | |
26 // (a) existing enumerated constants should never be deleted or reordered, and | |
27 // (b) new constants should only be appended at the end of the enumeration. | |
28 enum DirectWriteLoadFamilyResult { | |
29 LOAD_FAMILY_SUCCESS_SINGLE_FAMILY = 0, | |
30 LOAD_FAMILY_SUCCESS_MATCHED_FAMILY = 1, | |
31 LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES = 2, | |
32 LOAD_FAMILY_ERROR_NO_FAMILIES = 3, | |
33 LOAD_FAMILY_ERROR_NO_COLLECTION = 4, | |
34 | |
35 LOAD_FAMILY_MAX_VALUE | |
36 }; | |
37 | |
38 const char kFontKeyName[] = "font_key_name"; | |
39 | |
40 void LogLoadFamilyResult(DirectWriteLoadFamilyResult result) { | |
41 UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamily", result, | |
42 LOAD_FAMILY_MAX_VALUE); | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 DWriteFontCollectionProxy::DWriteFontCollectionProxy() = default; | |
48 | |
49 DWriteFontCollectionProxy::~DWriteFontCollectionProxy() = default; | |
50 | |
51 HRESULT DWriteFontCollectionProxy::FindFamilyName(const WCHAR* family_name, | |
52 UINT32* index, | |
53 BOOL* exists) { | |
54 DCHECK(family_name); | |
55 DCHECK(index); | |
56 DCHECK(exists); | |
57 TRACE_EVENT0("dwrite", "FontProxy::FindFamilyName"); | |
58 | |
59 uint32_t family_index = 0; | |
60 base::string16 name(family_name); | |
61 | |
62 auto iter = family_names_.find(name); | |
63 if (iter != family_names_.end()) { | |
64 *index = iter->second; | |
65 *exists = iter->second != UINT_MAX; | |
66 return S_OK; | |
67 } | |
68 | |
69 if (!sender_.Run()->Send( | |
70 new DWriteFontProxyMsg_FindFamily(name, &family_index))) { | |
71 return E_FAIL; | |
72 } | |
73 | |
74 if (family_index != UINT32_MAX) { | |
75 if (!CreateFamily(family_index)) | |
76 return E_FAIL; | |
77 *exists = TRUE; | |
78 *index = family_index; | |
79 families_[family_index]->SetName(name); | |
80 } else { | |
81 *exists = FALSE; | |
82 *index = UINT32_MAX; | |
83 } | |
84 | |
85 family_names_[name] = *index; | |
86 return S_OK; | |
87 } | |
88 | |
89 HRESULT DWriteFontCollectionProxy::GetFontFamily( | |
90 UINT32 index, | |
91 IDWriteFontFamily** font_family) { | |
92 DCHECK(font_family); | |
93 | |
94 if (index < families_.size() && families_[index]) { | |
95 families_[index].CopyTo(font_family); | |
96 return S_OK; | |
97 } | |
98 | |
99 if (!CreateFamily(index)) | |
100 return E_FAIL; | |
101 | |
102 families_[index].CopyTo(font_family); | |
103 return S_OK; | |
104 } | |
105 | |
106 UINT32 DWriteFontCollectionProxy::GetFontFamilyCount() { | |
107 if (family_count_ != UINT_MAX) | |
108 return family_count_; | |
109 | |
110 TRACE_EVENT0("dwrite", "FontProxy::GetFontFamilyCount"); | |
111 | |
112 uint32_t family_count = 0; | |
113 if (!sender_.Run()->Send( | |
114 new DWriteFontProxyMsg_GetFamilyCount(&family_count))) { | |
115 return 0; | |
116 } | |
117 family_count_ = family_count; | |
118 return family_count; | |
119 } | |
120 | |
121 HRESULT DWriteFontCollectionProxy::GetFontFromFontFace( | |
122 IDWriteFontFace* font_face, | |
123 IDWriteFont** font) { | |
124 DCHECK(font_face); | |
125 DCHECK(font); | |
126 | |
127 for (const auto& family : families_) { | |
128 if (family && family->GetFontFromFontFace(font_face, font)) | |
129 return S_OK; | |
130 } | |
131 return E_FAIL; | |
132 } | |
133 | |
134 HRESULT DWriteFontCollectionProxy::CreateEnumeratorFromKey( | |
135 IDWriteFactory* factory, | |
136 const void* collection_key, | |
137 UINT32 collection_key_size, | |
138 IDWriteFontFileEnumerator** font_file_enumerator) { | |
139 if (!collection_key || collection_key_size != sizeof(uint32_t)) | |
140 return E_INVALIDARG; | |
141 | |
142 TRACE_EVENT0("dwrite", "FontProxy::LoadingFontFiles"); | |
143 | |
144 const uint32_t* family_index = | |
145 reinterpret_cast<const uint32_t*>(collection_key); | |
146 | |
147 if (*family_index >= GetFontFamilyCount()) | |
148 return E_INVALIDARG; | |
149 | |
150 // If we already loaded the family we should reuse the existing collection. | |
151 DCHECK(!families_[*family_index]->IsLoaded()); | |
152 | |
153 std::vector<base::string16> file_names; | |
154 if (!sender_.Run()->Send( | |
155 new DWriteFontProxyMsg_GetFontFiles(*family_index, &file_names))) { | |
156 return E_FAIL; | |
157 } | |
158 | |
159 HRESULT hr = mswr::MakeAndInitialize<FontFileEnumerator>( | |
160 font_file_enumerator, factory, this, &file_names); | |
161 | |
162 if (!SUCCEEDED(hr)) | |
163 return E_FAIL; | |
164 | |
165 return S_OK; | |
166 } | |
167 | |
168 HRESULT DWriteFontCollectionProxy::CreateStreamFromKey( | |
169 const void* font_file_reference_key, | |
170 UINT32 font_file_reference_key_size, | |
171 IDWriteFontFileStream** font_file_stream) { | |
172 if (!font_file_reference_key) | |
173 return E_FAIL; | |
174 | |
175 const base::char16* file_name = | |
176 reinterpret_cast<const base::char16*>(font_file_reference_key); | |
177 DCHECK_EQ(font_file_reference_key_size % sizeof(base::char16), 0u); | |
178 size_t file_name_size = | |
179 static_cast<size_t>(font_file_reference_key_size) / sizeof(base::char16); | |
180 | |
181 if (file_name_size == 0 || file_name[file_name_size - 1] != L'\0') | |
182 return E_FAIL; | |
183 | |
184 TRACE_EVENT0("dwrite", "FontFileEnumerator::CreateStreamFromKey"); | |
185 | |
186 mswr::ComPtr<IDWriteFontFileStream> stream; | |
187 if (!SUCCEEDED(mswr::MakeAndInitialize<FontFileStream>(&stream, file_name))) | |
188 return E_FAIL; | |
189 *font_file_stream = stream.Detach(); | |
190 return S_OK; | |
191 } | |
192 | |
193 HRESULT DWriteFontCollectionProxy::RuntimeClassInitialize( | |
194 IDWriteFactory* factory, | |
195 const base::Callback<IPC::Sender*(void)>& sender) { | |
196 DCHECK(factory); | |
197 | |
198 factory_ = factory; | |
199 sender_ = sender; | |
200 | |
201 HRESULT hr = factory->RegisterFontCollectionLoader(this); | |
202 DCHECK(SUCCEEDED(hr)); | |
203 hr = factory_->RegisterFontFileLoader(this); | |
204 DCHECK(SUCCEEDED(hr)); | |
205 return S_OK; | |
206 } | |
207 | |
208 void DWriteFontCollectionProxy::Unregister() { | |
209 factory_->UnregisterFontCollectionLoader(this); | |
210 factory_->UnregisterFontFileLoader(this); | |
211 } | |
212 | |
213 bool DWriteFontCollectionProxy::LoadFamily( | |
214 UINT32 family_index, | |
215 IDWriteFontCollection** containing_collection) { | |
216 TRACE_EVENT0("dwrite", "FontProxy::LoadFamily"); | |
217 | |
218 uint32_t index = family_index; | |
219 // CreateCustomFontCollection ends up calling | |
220 // DWriteFontCollectionProxy::CreateEnumeratorFromKey. | |
221 HRESULT hr = factory_->CreateCustomFontCollection( | |
222 this /*collectionLoader*/, reinterpret_cast<const void*>(&index), | |
223 sizeof(index), containing_collection); | |
224 | |
225 return SUCCEEDED(hr); | |
226 } | |
227 | |
228 bool DWriteFontCollectionProxy::LoadFamilyNames( | |
229 UINT32 family_index, | |
230 IDWriteLocalizedStrings** localized_strings) { | |
231 TRACE_EVENT0("dwrite", "FontProxy::LoadFamilyNames"); | |
232 | |
233 std::vector<std::pair<base::string16, base::string16>> strings; | |
234 if (!sender_.Run()->Send( | |
235 new DWriteFontProxyMsg_GetFamilyNames(family_index, &strings))) { | |
236 return false; | |
237 } | |
238 | |
239 HRESULT hr = mswr::MakeAndInitialize<DWriteLocalizedStrings>( | |
240 localized_strings, &strings); | |
241 | |
242 return SUCCEEDED(hr); | |
243 } | |
244 | |
245 bool DWriteFontCollectionProxy::CreateFamily(UINT32 family_index) { | |
246 if (family_index < families_.size() && families_[family_index]) | |
247 return true; | |
248 | |
249 UINT32 family_count = GetFontFamilyCount(); | |
250 if (family_index >= family_count) | |
251 return false; | |
252 | |
253 if (families_.size() < family_count) | |
254 families_.resize(family_count); | |
255 | |
256 mswr::ComPtr<DWriteFontFamilyProxy> family; | |
257 HRESULT hr = mswr::MakeAndInitialize<DWriteFontFamilyProxy>(&family, this, | |
258 family_index); | |
259 DCHECK(SUCCEEDED(hr)); | |
260 DCHECK_LT(family_index, families_.size()); | |
261 | |
262 families_[family_index] = family; | |
263 return true; | |
264 } | |
265 | |
266 DWriteFontFamilyProxy::DWriteFontFamilyProxy() = default; | |
267 | |
268 DWriteFontFamilyProxy::~DWriteFontFamilyProxy() = default; | |
269 | |
270 HRESULT DWriteFontFamilyProxy::GetFontCollection( | |
271 IDWriteFontCollection** font_collection) { | |
272 DCHECK(font_collection); | |
273 | |
274 proxy_collection_.CopyTo(font_collection); | |
275 return S_OK; | |
276 } | |
277 | |
278 UINT32 DWriteFontFamilyProxy::GetFontCount() { | |
279 // We could conceivably proxy just the font count. However, calling | |
280 // GetFontCount is almost certain to be followed by a series of GetFont | |
281 // calls which will need to load all the fonts anyway, so we might as | |
282 // well save an IPC here. | |
283 if (!LoadFamily()) | |
284 return 0; | |
285 | |
286 return family_->GetFontCount(); | |
287 } | |
288 | |
289 HRESULT DWriteFontFamilyProxy::GetFont(UINT32 index, IDWriteFont** font) { | |
290 DCHECK(font); | |
291 | |
292 if (index >= GetFontCount()) | |
293 return E_INVALIDARG; | |
294 if (!LoadFamily()) | |
295 return E_FAIL; | |
296 | |
297 return family_->GetFont(index, font); | |
298 } | |
299 | |
300 HRESULT DWriteFontFamilyProxy::GetFamilyNames(IDWriteLocalizedStrings** names) { | |
301 DCHECK(names); | |
302 | |
303 // Prefer the real thing, if available. | |
304 if (family_) { | |
305 family_names_.Reset(); // Release cached data. | |
306 return family_->GetFamilyNames(names); | |
307 } | |
308 | |
309 // If already cached, use the cache. | |
310 if (family_names_) { | |
311 family_names_.CopyTo(names); | |
312 return S_OK; | |
313 } | |
314 | |
315 TRACE_EVENT0("dwrite", "FontProxy::GetFamilyNames"); | |
316 | |
317 // Otherwise, do the IPC. | |
318 if (!proxy_collection_->LoadFamilyNames(family_index_, &family_names_)) | |
319 return E_FAIL; | |
320 | |
321 family_names_.CopyTo(names); | |
322 return S_OK; | |
323 } | |
324 | |
325 HRESULT DWriteFontFamilyProxy::GetFirstMatchingFont( | |
326 DWRITE_FONT_WEIGHT weight, | |
327 DWRITE_FONT_STRETCH stretch, | |
328 DWRITE_FONT_STYLE style, | |
329 IDWriteFont** matching_font) { | |
330 DCHECK(matching_font); | |
331 | |
332 if (!LoadFamily()) | |
333 return E_FAIL; | |
334 | |
335 return family_->GetFirstMatchingFont(weight, stretch, style, matching_font); | |
336 } | |
337 | |
338 HRESULT DWriteFontFamilyProxy::GetMatchingFonts( | |
339 DWRITE_FONT_WEIGHT weight, | |
340 DWRITE_FONT_STRETCH stretch, | |
341 DWRITE_FONT_STYLE style, | |
342 IDWriteFontList** matching_fonts) { | |
343 DCHECK(matching_fonts); | |
344 | |
345 if (!LoadFamily()) | |
346 return E_FAIL; | |
347 | |
348 return family_->GetMatchingFonts(weight, stretch, style, matching_fonts); | |
349 } | |
350 | |
351 HRESULT DWriteFontFamilyProxy::RuntimeClassInitialize( | |
352 DWriteFontCollectionProxy* collection, | |
353 UINT32 index) { | |
354 DCHECK(collection); | |
355 | |
356 proxy_collection_ = collection; | |
357 family_index_ = index; | |
358 return S_OK; | |
359 } | |
360 | |
361 bool DWriteFontFamilyProxy::GetFontFromFontFace(IDWriteFontFace* font_face, | |
362 IDWriteFont** font) { | |
363 DCHECK(font_face); | |
364 DCHECK(font); | |
365 | |
366 if (!family_) | |
367 return false; | |
368 | |
369 mswr::ComPtr<IDWriteFontCollection> collection; | |
370 HRESULT hr = family_->GetFontCollection(&collection); | |
371 DCHECK(SUCCEEDED(hr)); | |
372 hr = collection->GetFontFromFontFace(font_face, font); | |
373 | |
374 return SUCCEEDED(hr); | |
375 } | |
376 | |
377 void DWriteFontFamilyProxy::SetName(const base::string16& family_name) { | |
378 family_name_.assign(family_name); | |
379 } | |
380 | |
381 bool DWriteFontFamilyProxy::IsLoaded() { | |
382 return family_ != nullptr; | |
383 } | |
384 | |
385 bool DWriteFontFamilyProxy::LoadFamily() { | |
386 if (family_) | |
387 return true; | |
388 | |
389 SCOPED_UMA_HISTOGRAM_TIMER("DirectWrite.Fonts.Proxy.LoadFamilyTime"); | |
390 | |
391 base::debug::ScopedCrashKey crash_key(kFontKeyName, | |
392 base::WideToUTF8(family_name_)); | |
393 | |
394 mswr::ComPtr<IDWriteFontCollection> collection; | |
395 if (!proxy_collection_->LoadFamily(family_index_, &collection)) { | |
396 LogLoadFamilyResult(LOAD_FAMILY_ERROR_NO_COLLECTION); | |
397 return false; | |
398 } | |
399 | |
400 UINT32 family_count = collection->GetFontFamilyCount(); | |
401 | |
402 HRESULT hr; | |
403 if (family_count > 1) { | |
404 // Some fonts are packaged in a single file containing multiple families. In | |
405 // such a case we can find the right family by family name. | |
406 DCHECK(!family_name_.empty()); | |
407 UINT32 family_index = 0; | |
408 BOOL found = FALSE; | |
409 hr = | |
410 collection->FindFamilyName(family_name_.c_str(), &family_index, &found); | |
411 if (SUCCEEDED(hr) && found) { | |
412 hr = collection->GetFontFamily(family_index, &family_); | |
413 LogLoadFamilyResult(LOAD_FAMILY_SUCCESS_MATCHED_FAMILY); | |
414 return SUCCEEDED(hr); | |
415 } | |
416 } | |
417 | |
418 DCHECK_LE(family_count, 1u); | |
419 | |
420 if (family_count == 0) { | |
421 // This is really strange, we successfully loaded no fonts?! | |
422 LogLoadFamilyResult(LOAD_FAMILY_ERROR_NO_FAMILIES); | |
423 return false; | |
424 } | |
425 | |
426 LogLoadFamilyResult(family_count == 1 ? LOAD_FAMILY_SUCCESS_SINGLE_FAMILY | |
427 : LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES); | |
428 | |
429 hr = collection->GetFontFamily(0, &family_); | |
430 | |
431 return SUCCEEDED(hr); | |
432 } | |
433 | |
434 FontFileEnumerator::FontFileEnumerator() = default; | |
435 | |
436 FontFileEnumerator::~FontFileEnumerator() = default; | |
437 | |
438 HRESULT FontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** file) { | |
439 DCHECK(file); | |
440 if (current_file_ >= file_names_.size()) | |
441 return E_FAIL; | |
442 | |
443 TRACE_EVENT0("dwrite", "FontFileEnumerator::GetCurrentFontFile (memmap)"); | |
444 // CreateCustomFontFileReference ends up calling | |
445 // DWriteFontCollectionProxy::CreateStreamFromKey. | |
446 return factory_->CreateCustomFontFileReference( | |
447 reinterpret_cast<const void*>(file_names_[current_file_].c_str()), | |
448 (file_names_[current_file_].length() + 1) * sizeof(base::char16), | |
449 loader_.Get() /*IDWriteFontFileLoader*/, file); | |
450 } | |
451 | |
452 HRESULT FontFileEnumerator::MoveNext(BOOL* has_current_file) { | |
453 DCHECK(has_current_file); | |
454 | |
455 TRACE_EVENT0("dwrite", "FontFileEnumerator::MoveNext"); | |
456 if (next_file_ >= file_names_.size()) { | |
457 *has_current_file = FALSE; | |
458 current_file_ = UINT_MAX; | |
459 return S_OK; | |
460 } | |
461 | |
462 current_file_ = next_file_; | |
463 ++next_file_; | |
464 *has_current_file = TRUE; | |
465 return S_OK; | |
466 } | |
467 | |
468 HRESULT FontFileEnumerator::RuntimeClassInitialize( | |
469 IDWriteFactory* factory, | |
470 IDWriteFontFileLoader* loader, | |
471 std::vector<base::string16>* file_names) { | |
472 factory_ = factory; | |
473 loader_ = loader; | |
474 file_names_.swap(*file_names); | |
475 file_streams_.resize(file_names_.size()); | |
476 return S_OK; | |
477 } | |
478 | |
479 FontFileStream::FontFileStream() = default; | |
480 | |
481 FontFileStream::~FontFileStream() = default; | |
482 | |
483 HRESULT FontFileStream::GetFileSize(UINT64* file_size) { | |
484 *file_size = data_.length(); | |
485 return S_OK; | |
486 } | |
487 | |
488 HRESULT FontFileStream::GetLastWriteTime(UINT64* last_write_time) { | |
489 *last_write_time = 0; | |
490 return S_OK; | |
491 } | |
492 | |
493 HRESULT FontFileStream::ReadFileFragment(const void** fragment_start, | |
494 UINT64 fragment_offset, | |
495 UINT64 fragment_size, | |
496 void** fragment_context) { | |
497 if (fragment_offset + fragment_size < fragment_offset) | |
498 return E_FAIL; | |
499 if (fragment_offset + fragment_size > data_.length()) | |
500 return E_FAIL; | |
501 *fragment_start = data_.data() + fragment_offset; | |
502 *fragment_context = nullptr; | |
503 return S_OK; | |
504 } | |
505 | |
506 HRESULT FontFileStream::RuntimeClassInitialize( | |
507 const base::string16& file_name) { | |
508 data_.Initialize(base::FilePath(file_name)); | |
509 if (!data_.IsValid()) | |
510 return E_FAIL; | |
511 return S_OK; | |
512 } | |
513 | |
514 } // namespace content | |
OLD | NEW |