Index: content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc |
diff --git a/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..da3b9b17dce470676191bb2ebdec3ee944450f90 |
--- /dev/null |
+++ b/content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc |
@@ -0,0 +1,479 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h" |
+ |
+#include <utility> |
+ |
+#include "base/logging.h" |
+#include "base/metrics/histogram_macros.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "base/win/scoped_handle.h" |
+#include "content/child/dwrite_font_proxy/dwrite_localized_strings_win.h" |
+#include "content/common/dwrite_font_proxy_messages.h" |
+#include "ipc/ipc_sender.h" |
+ |
+namespace content { |
+ |
+// This enum is used to define the buckets for an enumerated UMA histogram. |
+// Hence, |
+// (a) existing enumerated constants should never be deleted or reordered, and |
+// (b) new constants should only be appended at the end of the enumeration. |
+enum DirectWriteLoadFamilyResult { |
+ LOAD_FAMILY_SUCCESS_SINGLE_FAMILY = 0, |
+ LOAD_FAMILY_SUCCESS_MATCHED_FAMILY = 1, |
+ LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES = 2, |
+ LOAD_FAMILY_ERROR_NO_FAMILIES = 3, |
+ LOAD_FAMILY_ERROR_NO_COLLECTION = 4, |
+ |
+ LOAD_FAMILY_MAX_VALUE |
+}; |
+ |
+HRESULT DWriteFontCollectionProxy::FindFamilyName(const WCHAR* familyName, |
+ UINT32* index, |
+ BOOL* exists) { |
+ DCHECK(familyName != nullptr); |
+ DCHECK(index != nullptr); |
+ DCHECK(exists != nullptr); |
+ TRACE_EVENT0("dwrite", "FontProxy::FindFamilyName"); |
+ |
+ uint32 family_index = 0; |
+ base::string16 name; |
+ base::WideToUTF16(familyName, wcslen(familyName), &name); |
+ |
+ auto iter = family_names_.find(name); |
+ if (iter != family_names_.end()) { |
+ *index = iter->second; |
+ *exists = iter->second != UINT_MAX; |
+ return S_OK; |
+ } |
+ |
+ if (!sender_.Run()->Send( |
+ new DWriteFontProxyMsg_FindFamily(name, &family_index))) { |
+ return E_FAIL; |
+ } |
+ |
+ if (family_index != UINT32_MAX) { |
+ if (!CreateFamily(family_index)) |
+ return E_FAIL; |
+ *exists = TRUE; |
+ *index = family_index; |
+ families_[family_index]->SetName(name); |
+ } else { |
+ *exists = FALSE; |
+ *index = UINT32_MAX; |
+ } |
+ |
+ family_names_[name] = *index; |
+ return S_OK; |
+} |
+ |
+HRESULT DWriteFontCollectionProxy::GetFontFamily( |
+ UINT32 index, |
+ IDWriteFontFamily** fontFamily) { |
+ DCHECK(fontFamily != nullptr); |
+ |
+ if (index < families_.size() && families_[index] != nullptr) { |
+ families_[index].CopyTo(fontFamily); |
+ return S_OK; |
+ } |
+ |
+ if (!CreateFamily(index)) |
+ return E_FAIL; |
+ |
+ families_[index].CopyTo(fontFamily); |
+ return S_OK; |
+} |
+ |
+UINT32 DWriteFontCollectionProxy::GetFontFamilyCount() { |
+ if (family_count_ != UINT_MAX) |
+ return family_count_; |
+ |
+ TRACE_EVENT0("dwrite", "FontProxy::GetFontFamilyCount"); |
+ |
+ uint32 family_count = 0; |
+ if (!sender_.Run()->Send( |
+ new DWriteFontProxyMsg_GetFamilyCount(&family_count))) { |
+ return 0; |
+ } |
+ family_count_ = family_count; |
+ return family_count; |
+} |
+ |
+HRESULT DWriteFontCollectionProxy::GetFontFromFontFace( |
+ IDWriteFontFace* fontFace, |
+ IDWriteFont** font) { |
+ DCHECK(fontFace != nullptr); |
+ DCHECK(font != nullptr); |
+ |
+ for (auto& family : families_) { |
+ if (family != nullptr && family->GetFontFromFontFace(fontFace, font)) |
+ return S_OK; |
+ } |
+ return E_FAIL; |
+} |
+ |
+HRESULT DWriteFontCollectionProxy::CreateEnumeratorFromKey( |
+ IDWriteFactory* factory, |
+ const void* collectionKey, |
+ UINT32 collectionKeySize, |
+ IDWriteFontFileEnumerator** fontFileEnumerator) { |
+ if (collectionKey == nullptr || collectionKeySize != sizeof(uint32)) { |
+ return E_INVALIDARG; |
+ } |
+ |
+ TRACE_EVENT0("dwrite", "FontProxy::LoadingFontFiles"); |
+ |
+ const uint32* family_index = reinterpret_cast<const uint32*>(collectionKey); |
+ |
+ if (*family_index >= GetFontFamilyCount()) { |
+ return E_INVALIDARG; |
+ } |
+ |
+ // If we already loaded the family we should reuse the existing collection. |
+ DCHECK(!families_[*family_index]->IsLoaded()); |
+ |
+ std::vector<base::string16> file_names; |
+ if (!sender_.Run()->Send( |
+ new DWriteFontProxyMsg_GetFontFiles(*family_index, &file_names))) { |
+ return E_FAIL; |
+ } |
+ |
+ HRESULT hr = mswr::MakeAndInitialize<FontFileEnumerator>( |
+ fontFileEnumerator, factory, this, &file_names); |
+ |
+ if (!SUCCEEDED(hr)) |
+ return E_FAIL; |
+ |
+ return S_OK; |
+} |
+ |
+HRESULT DWriteFontCollectionProxy::CreateStreamFromKey( |
+ const void* fontFileReferenceKey, |
+ uint32 fontFileReferenceKeySize, |
+ IDWriteFontFileStream** fontFileStream) { |
+ if (fontFileReferenceKey == nullptr) |
+ return E_FAIL; |
+ |
+ const base::char16* file_name = |
+ reinterpret_cast<const base::char16*>(fontFileReferenceKey); |
+ DCHECK_EQ(fontFileReferenceKeySize % sizeof(base::char16), 0u); |
+ uint32 file_name_length = fontFileReferenceKeySize / sizeof(base::char16); |
+ file_name_length--; // Don't count the terminating null. |
+ |
+ if (file_name[file_name_length] != L'\0') |
+ return E_FAIL; |
+ |
+ TRACE_EVENT0("dwrite", "FontFileEnumerator::CreateStreamFromKey"); |
+ |
+ mswr::ComPtr<IDWriteFontFileStream> stream; |
+ if (!SUCCEEDED(mswr::MakeAndInitialize<FontFileStream>(&stream, file_name))) |
+ return E_FAIL; |
+ *fontFileStream = stream.Detach(); |
+ return S_OK; |
+} |
+ |
+HRESULT DWriteFontCollectionProxy::RuntimeClassInitialize( |
+ IDWriteFactory* factory, |
+ const base::Callback<IPC::Sender*(void)>& sender) { |
+ DCHECK(factory != nullptr); |
+ |
+ factory_ = factory; |
+ sender_ = sender; |
+ |
+ HRESULT hr = factory->RegisterFontCollectionLoader(this); |
+ DCHECK(SUCCEEDED(hr)); |
+ hr = factory_->RegisterFontFileLoader(this); |
+ DCHECK(SUCCEEDED(hr)); |
+ return S_OK; |
+} |
+ |
+void DWriteFontCollectionProxy::Unregister() { |
+ factory_->UnregisterFontCollectionLoader(this); |
+ factory_->UnregisterFontFileLoader(this); |
+} |
+ |
+bool DWriteFontCollectionProxy::LoadFamily( |
+ unsigned int family_index, |
+ IDWriteFontCollection** containing_collection) { |
+ TRACE_EVENT0("dwrite", "FontProxy::LoadFamily"); |
+ |
+ uint32 index = family_index; |
+ HRESULT hr = factory_->CreateCustomFontCollection( |
+ this /*collectonLoader*/, reinterpret_cast<const void*>(&index), |
+ sizeof(index), containing_collection); |
+ |
+ return SUCCEEDED(hr); |
+} |
+ |
+bool DWriteFontCollectionProxy::LoadFamilyNames( |
+ unsigned int family_index, |
+ IDWriteLocalizedStrings** localized_strings) { |
+ TRACE_EVENT0("dwrite", "FontProxy::LoadFamilyNames"); |
+ |
+ std::vector<std::pair<base::string16, base::string16>> strings; |
+ if (!sender_.Run()->Send( |
+ new DWriteFontProxyMsg_GetFamilyNames(family_index, &strings))) { |
+ return false; |
+ } |
+ |
+ HRESULT hr = mswr::MakeAndInitialize<DWriteLocalizedStrings>( |
+ localized_strings, &strings); |
+ |
+ return SUCCEEDED(hr); |
+} |
+ |
+bool DWriteFontCollectionProxy::CreateFamily(unsigned int family_index) { |
+ if (family_index < families_.size() && families_[family_index] != nullptr) |
+ return true; |
+ |
+ uint32 family_count = GetFontFamilyCount(); |
+ if (family_index >= family_count) |
+ return false; |
+ |
+ if (families_.size() < family_count) |
+ families_.resize(family_count); |
+ |
+ mswr::ComPtr<DWriteFontFamilyProxy> family; |
+ HRESULT hr = mswr::MakeAndInitialize<DWriteFontFamilyProxy>(&family, this, |
+ family_index); |
+ DCHECK(SUCCEEDED(hr)); |
+ DCHECK(family_index < families_.size()); |
+ |
+ families_[family_index] = family; |
+ return true; |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::GetFontCollection( |
+ IDWriteFontCollection** fontCollection) { |
+ DCHECK(fontCollection != nullptr); |
+ |
+ proxy_collection_.CopyTo(fontCollection); |
+ return S_OK; |
+} |
+ |
+UINT32 DWriteFontFamilyProxy::GetFontCount() { |
+ // We could conceivably proxy just the font count. However, calling |
+ // GetFontCount is almost certain to be followed by a series of GetFont |
+ // calls which will need to load all the fonts anyway, so we might as |
+ // well save an IPC here. |
+ if (!LoadFamily()) |
+ return 0; |
+ |
+ return family_->GetFontCount(); |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::GetFont(UINT32 index, IDWriteFont** font) { |
+ DCHECK(font != nullptr); |
+ |
+ if (index >= GetFontCount()) { |
+ return E_INVALIDARG; |
+ } |
+ if (!LoadFamily()) { |
+ return E_FAIL; |
+ } |
+ |
+ return family_->GetFont(index, font); |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::GetFamilyNames(IDWriteLocalizedStrings** names) { |
+ DCHECK(names != nullptr); |
+ |
+ // Prefer the real thing, if available. |
+ if (family_ != nullptr) { |
+ family_names_ = nullptr; // Release cached data. |
+ return family_->GetFamilyNames(names); |
+ } |
+ |
+ // If already cached, use the cache. |
+ if (family_names_ != nullptr) { |
+ family_names_.CopyTo(names); |
+ return S_OK; |
+ } |
+ |
+ TRACE_EVENT0("dwrite", "FontProxy::GetFamilyNames"); |
+ |
+ // Otherwise, do the IPC. |
+ if (!proxy_collection_->LoadFamilyNames(family_index_, &family_names_)) { |
+ return E_FAIL; |
+ } |
+ |
+ family_names_.CopyTo(names); |
+ return S_OK; |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::GetFirstMatchingFont( |
+ DWRITE_FONT_WEIGHT weight, |
+ DWRITE_FONT_STRETCH stretch, |
+ DWRITE_FONT_STYLE style, |
+ IDWriteFont** matchingFont) { |
+ DCHECK(matchingFont != nullptr); |
+ |
+ if (!LoadFamily()) { |
+ return E_FAIL; |
+ } |
+ |
+ return family_->GetFirstMatchingFont(weight, stretch, style, matchingFont); |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::GetMatchingFonts( |
+ DWRITE_FONT_WEIGHT weight, |
+ DWRITE_FONT_STRETCH stretch, |
+ DWRITE_FONT_STYLE style, |
+ IDWriteFontList** matchingFonts) { |
+ DCHECK(matchingFonts != nullptr); |
+ |
+ if (!LoadFamily()) { |
+ return E_FAIL; |
+ } |
+ |
+ return family_->GetMatchingFonts(weight, stretch, style, matchingFonts); |
+} |
+ |
+HRESULT DWriteFontFamilyProxy::RuntimeClassInitialize( |
+ DWriteFontCollectionProxy* collection, |
+ unsigned int index) { |
+ DCHECK(collection != nullptr); |
+ |
+ proxy_collection_ = collection; |
+ family_index_ = index; |
+ return S_OK; |
+} |
+ |
+bool DWriteFontFamilyProxy::GetFontFromFontFace(IDWriteFontFace* font_face, |
+ IDWriteFont** font) { |
+ DCHECK(font_face != nullptr); |
+ DCHECK(font != nullptr); |
+ |
+ if (family_ == nullptr) |
+ return false; |
+ |
+ mswr::ComPtr<IDWriteFontCollection> collection; |
+ HRESULT hr = family_->GetFontCollection(&collection); |
+ DCHECK(SUCCEEDED(hr)); |
+ hr = collection->GetFontFromFontFace(font_face, font); |
+ |
+ return SUCCEEDED(hr); |
+} |
+ |
+bool DWriteFontFamilyProxy::LoadFamily() { |
+ if (family_ != nullptr) |
+ return true; |
+ |
+ mswr::ComPtr<IDWriteFontCollection> collection; |
+ if (!proxy_collection_->LoadFamily(family_index_, &collection)) { |
+ UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamily", |
Alexei Svitkine (slow)
2015/11/06 22:11:46
Make a helper function for this histogram.
Ilya Kulshin
2015/11/11 01:22:11
Done.
|
+ LOAD_FAMILY_ERROR_NO_COLLECTION, |
+ LOAD_FAMILY_MAX_VALUE); |
+ return false; |
+ } |
+ |
+ UINT32 family_count = collection->GetFontFamilyCount(); |
+ |
+ HRESULT hr; |
+ if (family_count > 1) { |
+ // Some fonts are packaged in a single file containing multiple families. In |
+ // such a case we can find the right family by family name. |
+ DCHECK(!family_name_.empty()); |
+ uint32 family_index = 0; |
+ BOOL found = FALSE; |
+ hr = |
+ collection->FindFamilyName(family_name_.c_str(), &family_index, &found); |
+ if (SUCCEEDED(hr) && found) { |
+ hr = collection->GetFontFamily(family_index, &family_); |
+ UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamily", |
+ LOAD_FAMILY_SUCCESS_MATCHED_FAMILY, |
+ LOAD_FAMILY_MAX_VALUE); |
+ return SUCCEEDED(hr); |
+ } |
+ } |
+ |
+ DCHECK(family_count <= 1); |
Alexei Svitkine (slow)
2015/11/06 22:11:46
DCHECK_LE
Ilya Kulshin
2015/11/11 01:22:11
Done.
|
+ |
+ if (family_count == 0) { |
+ // This is really strange, we successfully loaded no fonts?! |
+ UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamily", |
+ LOAD_FAMILY_ERROR_NO_FAMILIES, |
+ LOAD_FAMILY_MAX_VALUE); |
+ return false; |
+ } |
+ |
+ UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.LoadFamily", |
+ family_count == 1 |
+ ? LOAD_FAMILY_SUCCESS_SINGLE_FAMILY |
+ : LOAD_FAMILY_ERROR_MULTIPLE_FAMILIES, |
+ LOAD_FAMILY_MAX_VALUE); |
+ |
+ hr = collection->GetFontFamily(0, &family_); |
+ |
+ return SUCCEEDED(hr); |
+} |
+ |
+HRESULT FontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** file) { |
+ DCHECK(file != nullptr); |
+ if (current_file_ >= file_names_.size()) { |
+ return E_FAIL; |
+ } |
+ |
+ TRACE_EVENT0("dwrite", "FontFileEnumerator::GetCurrentFontFile (memmap)"); |
+ return factory_->CreateCustomFontFileReference( |
+ reinterpret_cast<const void*>(file_names_[current_file_].c_str()), |
+ (file_names_[current_file_].size() + 1) * sizeof(base::char16), |
+ loader_.Get() /*IDWriteFontFileLoader*/, file); |
+} |
+ |
+HRESULT FontFileEnumerator::MoveNext(BOOL* hasCurrentFile) { |
+ DCHECK(hasCurrentFile); |
+ |
+ TRACE_EVENT0("dwrite", "FontFileEnumerator::MoveNext"); |
+ if (next_file_ >= file_names_.size()) { |
+ *hasCurrentFile = FALSE; |
+ current_file_ = UINT_MAX; |
+ return S_OK; |
+ } |
+ |
+ current_file_ = next_file_; |
+ next_file_++; |
+ *hasCurrentFile = TRUE; |
+ return S_OK; |
+} |
+ |
+HRESULT FontFileEnumerator::RuntimeClassInitialize( |
+ IDWriteFactory* factory, |
+ IDWriteFontFileLoader* loader, |
+ std::vector<base::string16>* file_names) { |
+ factory_ = factory; |
+ loader_ = loader; |
+ file_names_.swap(*file_names); |
+ file_streams_.resize(file_names_.size()); |
+ return S_OK; |
+} |
+ |
+HRESULT FontFileStream::GetFileSize(UINT64* fileSize) { |
+ *fileSize = data_.length(); |
+ return S_OK; |
+} |
Alexei Svitkine (slow)
2015/11/06 22:11:46
Please add missing empty lines here and below.
Ilya Kulshin
2015/11/11 01:22:11
Done.
|
+HRESULT FontFileStream::GetLastWriteTime(UINT64* lastWriteTime) { |
+ return S_OK; |
+} |
+HRESULT FontFileStream::ReadFileFragment(const void** fragmentStart, |
+ UINT64 fileOffset, |
+ UINT64 fragmentSize, |
+ void** fragmentContext) { |
Alexei Svitkine (slow)
2015/11/06 22:11:45
Use hacker_style names. Please fix throughout.
Ilya Kulshin
2015/11/11 01:22:11
Done.
|
+ if (fileOffset + fragmentSize < fileOffset) |
+ return E_FAIL; |
+ if (fileOffset + fragmentSize > data_.length()) |
+ return E_FAIL; |
+ *fragmentStart = data_.data() + fileOffset; |
+ *fragmentContext = nullptr; |
+ return S_OK; |
+} |
+HRESULT FontFileStream::RuntimeClassInitialize(const base::string16& fileName) { |
+ data_.Initialize(base::FilePath(fileName)); |
+ if (!data_.IsValid()) |
+ return E_FAIL; |
+ return S_OK; |
+} |
+ |
+} // namespace content |