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