| Index: content/common/dwrite_font_proxy_win.cc
|
| diff --git a/content/common/dwrite_font_proxy_win.cc b/content/common/dwrite_font_proxy_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..331a8ced159c59bc7e672f8222bae050950e7264
|
| --- /dev/null
|
| +++ b/content/common/dwrite_font_proxy_win.cc
|
| @@ -0,0 +1,476 @@
|
| +// 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/common/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/common/dwrite_font_proxy_messages.h"
|
| +#include "content/common/dwrite_localized_strings_win.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 DWriteLoadFamilyResult {
|
| + kLoadFamilySuccessSingleFamily = 0,
|
| + kLoadFamilySuccessMatchedFamily = 1,
|
| + kLoadFamilyErrorMultipleFamilies = 2,
|
| + kLoadFamilyErrorNoFamilies = 3,
|
| + kLoadFamilyErrorNoCollection = 4,
|
| +
|
| + kLoadFamilyMaxValue
|
| +};
|
| +
|
| +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 familyIndex = 0;
|
| + base::string16 name;
|
| + base::WideToUTF16(familyName, wcslen(familyName), &name);
|
| +
|
| + auto iter = familyNames_.find(name);
|
| + if (iter != familyNames_.end()) {
|
| + *index = iter->second;
|
| + *exists = iter->second != UINT_MAX;
|
| + return S_OK;
|
| + }
|
| +
|
| + if (!getSender_.Run()->Send(
|
| + new DWriteFontProxyMsg_FindFamily(name, &familyIndex))) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (familyIndex != UINT32_MAX) {
|
| + if (!CreateFamily(familyIndex))
|
| + return E_FAIL;
|
| + *exists = TRUE;
|
| + *index = familyIndex;
|
| + families_[familyIndex]->SetName(name);
|
| + } else {
|
| + *exists = FALSE;
|
| + *index = UINT32_MAX;
|
| + }
|
| +
|
| + familyNames_[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 (familyCount_ != UINT_MAX)
|
| + return familyCount_;
|
| +
|
| + TRACE_EVENT0("dwrite", "FontProxy::GetFontFamilyCount");
|
| +
|
| + uint32 familyCount = 0;
|
| + if (!getSender_.Run()->Send(
|
| + new DWriteFontProxyMsg_GetFamilyCount(&familyCount))) {
|
| + return 0;
|
| + }
|
| + familyCount_ = familyCount;
|
| + return familyCount;
|
| +}
|
| +
|
| +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* familyIndex = reinterpret_cast<const uint32*>(collectionKey);
|
| +
|
| + if (*familyIndex >= GetFontFamilyCount()) {
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + // If we already loaded the family we should reuse the existing collection.
|
| + DCHECK(!families_[*familyIndex]->IsLoaded());
|
| +
|
| + std::vector<base::string16> fileNames;
|
| + if (!getSender_.Run()->Send(
|
| + new DWriteFontProxyMsg_GetFontFiles(*familyIndex, &fileNames))) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + HRESULT hr = mswr::MakeAndInitialize<FontFileEnumerator>(
|
| + fontFileEnumerator, factory, this, &fileNames);
|
| +
|
| + 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* fileName =
|
| + reinterpret_cast<const base::char16*>(fontFileReferenceKey);
|
| + DCHECK_EQ(fontFileReferenceKeySize % sizeof(base::char16), 0u);
|
| + uint32 fileNameLength = fontFileReferenceKeySize / sizeof(base::char16);
|
| + fileNameLength--; // Don't count the terminating null.
|
| +
|
| + if (fileName[fileNameLength] != L'\0')
|
| + return E_FAIL;
|
| +
|
| + TRACE_EVENT0("dwrite", "FontFileEnumerator::CreateStreamFromKey");
|
| +
|
| + mswr::ComPtr<IDWriteFontFileStream> stream;
|
| + if (!SUCCEEDED(mswr::MakeAndInitialize<FontFileStream>(&stream, fileName)))
|
| + return E_FAIL;
|
| + *fontFileStream = stream.Detach();
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT DWriteFontCollectionProxy::RuntimeClassInitialize(
|
| + IDWriteFactory* factory,
|
| + const base::Callback<IPC::Sender*(void)>& getSender) {
|
| + DCHECK(factory != nullptr);
|
| +
|
| + factory_ = factory;
|
| + getSender_ = getSender;
|
| +
|
| + 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 familyIndex,
|
| + IDWriteFontCollection** containingCollection) {
|
| + TRACE_EVENT0("dwrite", "FontProxy::LoadFamily");
|
| +
|
| + uint32 index = familyIndex;
|
| + HRESULT hr = factory_->CreateCustomFontCollection(
|
| + this /*collectonLoader*/, reinterpret_cast<const void*>(&index),
|
| + sizeof(index), containingCollection);
|
| +
|
| + return SUCCEEDED(hr);
|
| +}
|
| +
|
| +bool DWriteFontCollectionProxy::LoadFamilyNames(
|
| + unsigned int familyIndex,
|
| + IDWriteLocalizedStrings** localizedStrings) {
|
| + TRACE_EVENT0("dwrite", "FontProxy::LoadFamilyNames");
|
| +
|
| + std::vector<std::pair<base::string16, base::string16>> strings;
|
| + if (!getSender_.Run()->Send(
|
| + new DWriteFontProxyMsg_GetFamilyNames(familyIndex, &strings))) {
|
| + return false;
|
| + }
|
| +
|
| + HRESULT hr = mswr::MakeAndInitialize<DWriteLocalizedStrings>(localizedStrings,
|
| + &strings);
|
| +
|
| + return SUCCEEDED(hr);
|
| +}
|
| +
|
| +bool DWriteFontCollectionProxy::CreateFamily(unsigned int familyIndex) {
|
| + if (familyIndex < families_.size() && families_[familyIndex] != nullptr)
|
| + return true;
|
| +
|
| + uint32 familyCount = GetFontFamilyCount();
|
| + if (familyIndex >= familyCount)
|
| + return false;
|
| +
|
| + if (families_.size() < familyCount)
|
| + families_.resize(familyCount);
|
| +
|
| + mswr::ComPtr<DWriteFontFamilyProxy> family;
|
| + HRESULT hr = mswr::MakeAndInitialize<DWriteFontFamilyProxy>(&family, this,
|
| + familyIndex);
|
| + DCHECK(SUCCEEDED(hr));
|
| + DCHECK(familyIndex < families_.size());
|
| +
|
| + families_[familyIndex] = family;
|
| + return true;
|
| +}
|
| +
|
| +HRESULT DWriteFontFamilyProxy::GetFontCollection(
|
| + IDWriteFontCollection** fontCollection) {
|
| + DCHECK(fontCollection != nullptr);
|
| +
|
| + proxyCollection_.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) {
|
| + familyNames_ = nullptr; // Release cached data.
|
| + return family_->GetFamilyNames(names);
|
| + }
|
| +
|
| + // If already cached, use the cache.
|
| + if (familyNames_ != nullptr) {
|
| + familyNames_.CopyTo(names);
|
| + return S_OK;
|
| + }
|
| +
|
| + TRACE_EVENT0("dwrite", "FontProxy::GetFamilyNames");
|
| +
|
| + // Otherwise, do the IPC.
|
| + if (!proxyCollection_->LoadFamilyNames(familyIndex_, &familyNames_)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + familyNames_.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);
|
| +
|
| + proxyCollection_ = collection;
|
| + familyIndex_ = index;
|
| + return S_OK;
|
| +}
|
| +
|
| +bool DWriteFontFamilyProxy::GetFontFromFontFace(IDWriteFontFace* fontFace,
|
| + IDWriteFont** font) {
|
| + DCHECK(fontFace != nullptr);
|
| + DCHECK(font != nullptr);
|
| +
|
| + if (family_ == nullptr)
|
| + return false;
|
| +
|
| + mswr::ComPtr<IDWriteFontCollection> collection;
|
| + HRESULT hr = family_->GetFontCollection(&collection);
|
| + DCHECK(SUCCEEDED(hr));
|
| + hr = collection->GetFontFromFontFace(fontFace, font);
|
| +
|
| + return SUCCEEDED(hr);
|
| +}
|
| +
|
| +bool DWriteFontFamilyProxy::LoadFamily() {
|
| + if (family_ != nullptr)
|
| + return true;
|
| +
|
| + mswr::ComPtr<IDWriteFontCollection> collection;
|
| + if (!proxyCollection_->LoadFamily(familyIndex_, &collection)) {
|
| + UMA_HISTOGRAM_ENUMERATION("DWriteFontProxy.LoadFamily",
|
| + kLoadFamilyErrorNoCollection,
|
| + kLoadFamilyMaxValue);
|
| + return false;
|
| + }
|
| +
|
| + UINT32 familyCount = collection->GetFontFamilyCount();
|
| +
|
| + HRESULT hr;
|
| + if (familyCount > 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(!familyName_.empty());
|
| + uint32 familyIndex = 0;
|
| + BOOL found = FALSE;
|
| + hr = collection->FindFamilyName(familyName_.c_str(), &familyIndex, &found);
|
| + if (SUCCEEDED(hr) && found) {
|
| + hr = collection->GetFontFamily(familyIndex, &family_);
|
| + UMA_HISTOGRAM_ENUMERATION("DWriteFontProxy.LoadFamily",
|
| + kLoadFamilySuccessMatchedFamily,
|
| + kLoadFamilyMaxValue);
|
| + return SUCCEEDED(hr);
|
| + }
|
| + }
|
| +
|
| + DCHECK(familyCount <= 1);
|
| +
|
| + if (familyCount == 0) {
|
| + // This is really strange, we successfully loaded no fonts?!
|
| + UMA_HISTOGRAM_ENUMERATION("DWriteFontProxy.LoadFamily",
|
| + kLoadFamilyErrorNoFamilies, kLoadFamilyMaxValue);
|
| + return false;
|
| + }
|
| +
|
| + UMA_HISTOGRAM_ENUMERATION("DWriteFontProxy.LoadFamily",
|
| + familyCount == 1 ? kLoadFamilySuccessSingleFamily
|
| + : kLoadFamilyErrorMultipleFamilies,
|
| + kLoadFamilyMaxValue);
|
| +
|
| + hr = collection->GetFontFamily(0, &family_);
|
| +
|
| + return SUCCEEDED(hr);
|
| +}
|
| +
|
| +HRESULT FontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** file) {
|
| + DCHECK(file != nullptr);
|
| + if (currentFile_ >= fileNames_.size()) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + TRACE_EVENT0("dwrite", "FontFileEnumerator::GetCurrentFontFile (memmap)");
|
| + return factory_->CreateCustomFontFileReference(
|
| + reinterpret_cast<const void*>(fileNames_[currentFile_].c_str()),
|
| + (fileNames_[currentFile_].size() + 1) * sizeof(base::char16),
|
| + loader_.Get() /*IDWriteFontFileLoader*/, file);
|
| +}
|
| +
|
| +HRESULT FontFileEnumerator::MoveNext(BOOL* hasCurrentFile) {
|
| + DCHECK(hasCurrentFile);
|
| +
|
| + TRACE_EVENT0("dwrite", "FontFileEnumerator::MoveNext");
|
| + if (nextFile_ >= fileNames_.size()) {
|
| + *hasCurrentFile = FALSE;
|
| + currentFile_ = UINT_MAX;
|
| + return S_OK;
|
| + }
|
| +
|
| + currentFile_ = nextFile_;
|
| + nextFile_++;
|
| + *hasCurrentFile = TRUE;
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT FontFileEnumerator::RuntimeClassInitialize(
|
| + IDWriteFactory* factory,
|
| + IDWriteFontFileLoader* loader,
|
| + std::vector<base::string16>* fileNames) {
|
| + factory_ = factory;
|
| + loader_ = loader;
|
| + fileNames_.swap(*fileNames);
|
| + fileStreams_.resize(fileNames_.size());
|
| + return S_OK;
|
| +}
|
| +
|
| +HRESULT FontFileStream::GetFileSize(UINT64* fileSize) {
|
| + *fileSize = data_.length();
|
| + return S_OK;
|
| +}
|
| +HRESULT FontFileStream::GetLastWriteTime(UINT64* lastWriteTime) {
|
| + return S_OK;
|
| +}
|
| +HRESULT FontFileStream::ReadFileFragment(const void** fragmentStart,
|
| + UINT64 fileOffset,
|
| + UINT64 fragmentSize,
|
| + void** fragmentContext) {
|
| + 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
|
|
|