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