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

Unified Diff: content/child/dwrite_font_proxy/dwrite_font_proxy_win.cc

Issue 1378353006: Implementation of dwrite font proxy and removal of dwrite font cache (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renaming histograms 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 side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698