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