| 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 |