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

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

Powered by Google App Engine
This is Rietveld 408576698