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

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: Merge to origin/master 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 } // 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698