Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc

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

Powered by Google App Engine
This is Rietveld 408576698