| Index: content/child/dwrite_font_proxy/font_fallback_win.cc
|
| diff --git a/content/child/dwrite_font_proxy/font_fallback_win.cc b/content/child/dwrite_font_proxy/font_fallback_win.cc
|
| index 46588c7066a5c89efb61887c0eff125bd4e97b02..4bf78d2804f04dac61795a100917cf8ed740fe6d 100644
|
| --- a/content/child/dwrite_font_proxy/font_fallback_win.cc
|
| +++ b/content/child/dwrite_font_proxy/font_fallback_win.cc
|
| @@ -4,8 +4,13 @@
|
|
|
| #include "content/child/dwrite_font_proxy/font_fallback_win.h"
|
|
|
| -#include "base/strings/string16.h"
|
| +#include <math.h>
|
| +
|
| +#include <algorithm>
|
|
|
| +#include "base/metrics/histogram_macros.h"
|
| +#include "base/strings/string16.h"
|
| +#include "base/strings/utf_string_conversion_utils.h"
|
| #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
|
| #include "content/common/dwrite_font_proxy_messages.h"
|
| #include "content/public/child/child_thread.h"
|
| @@ -15,6 +20,29 @@ namespace mswr = Microsoft::WRL;
|
|
|
| namespace content {
|
|
|
| +namespace {
|
| +
|
| +const size_t kMaxFamilyCacheSize = 10;
|
| +
|
| +// 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 DirectWriteFontFallbackResult {
|
| + FAILED_NO_FONT = 0,
|
| + SUCCESS_CACHE = 1,
|
| + SUCCESS_IPC = 2,
|
| +
|
| + FONT_FALLBACK_RESULT_MAX_VALUE
|
| +};
|
| +
|
| +void LogFallbackResult(DirectWriteFontFallbackResult fallback_result) {
|
| + UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.FallbackResult",
|
| + fallback_result, FONT_FALLBACK_RESULT_MAX_VALUE);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| FontFallback::FontFallback() = default;
|
| FontFallback::~FontFallback() = default;
|
|
|
| @@ -39,7 +67,24 @@ HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source,
|
| DCHECK(false);
|
| return E_FAIL;
|
| }
|
| - base::string16 text_chunk(text, chunk_length);
|
| + base::string16 text_chunk(text, std::min(chunk_length, text_length));
|
| +
|
| + if (text_chunk.size() == 0) {
|
| + DCHECK(false);
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + base_family_name = base_family_name ? base_family_name : L"";
|
| +
|
| + if (GetCachedFont(text_chunk, base_family_name, base_weight, base_style,
|
| + base_stretch, mapped_font, mapped_length)) {
|
| + DCHECK(*mapped_font);
|
| + DCHECK_GT(*mapped_length, 0u);
|
| + LogFallbackResult(SUCCESS_CACHE);
|
| + return S_OK;
|
| + }
|
| +
|
| + TRACE_EVENT0("dwrite", "FontFallback::MapCharacters (IPC)");
|
|
|
| const WCHAR* locale = nullptr;
|
| // |locale_text_length| is actually the length of text with the locale, not
|
| @@ -48,8 +93,7 @@ HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source,
|
| source->GetLocaleName(text_position /*textPosition*/, &locale_text_length,
|
| &locale);
|
|
|
| - if (locale == nullptr)
|
| - locale = L"";
|
| + locale = locale ? locale : L"";
|
|
|
| DWriteFontStyle style;
|
| style.font_weight = base_weight;
|
| @@ -62,14 +106,23 @@ HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source,
|
| sender_override_ ? sender_override_ : ChildThread::Get();
|
| if (!sender->Send(new DWriteFontProxyMsg_MapCharacters(
|
| text_chunk, style, locale, source->GetParagraphReadingDirection(),
|
| - base_family_name ? base_family_name : L"", &result)))
|
| + base_family_name, &result))) {
|
| + DCHECK(false);
|
| return E_FAIL;
|
| + }
|
| +
|
| + // We don't cache scale in the fallback cache, and Skia ignores scale anyway.
|
| + // If we ever get a result that's significantly different from 1 we may need
|
| + // to consider whether it's worth doing the work to plumb it through.
|
| + DCHECK(fabs(*scale - 1.0f) < 0.00001);
|
|
|
| *mapped_length = result.mapped_length;
|
| *scale = result.scale;
|
|
|
| - if (result.family_index == UINT32_MAX)
|
| + if (result.family_index == UINT32_MAX) {
|
| + LogFallbackResult(FAILED_NO_FONT);
|
| return S_OK;
|
| + }
|
|
|
| mswr::ComPtr<IDWriteFontFamily> family;
|
| // It would be nice to find a way to determine at runtime if |collection_| is
|
| @@ -93,7 +146,8 @@ HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source,
|
| }
|
|
|
| DCHECK(*mapped_font);
|
| -
|
| + AddCachedFamily(std::move(family), base_family_name);
|
| + LogFallbackResult(SUCCESS_IPC);
|
| return S_OK;
|
| }
|
|
|
| @@ -105,4 +159,71 @@ FontFallback::RuntimeClassInitialize(DWriteFontCollectionProxy* collection,
|
| return S_OK;
|
| }
|
|
|
| +bool FontFallback::GetCachedFont(const base::string16& text,
|
| + const wchar_t* base_family_name,
|
| + DWRITE_FONT_WEIGHT base_weight,
|
| + DWRITE_FONT_STYLE base_style,
|
| + DWRITE_FONT_STRETCH base_stretch,
|
| + IDWriteFont** font,
|
| + uint32_t* mapped_length) {
|
| + std::map<base::string16, std::list<mswr::ComPtr<IDWriteFontFamily>>>::iterator
|
| + it = fallback_family_cache_.find(base_family_name);
|
| + if (it == fallback_family_cache_.end())
|
| + return false;
|
| +
|
| + TRACE_EVENT0("dwrite", "FontFallback::GetCachedFont");
|
| +
|
| + std::list<mswr::ComPtr<IDWriteFontFamily>>& family_list = it->second;
|
| + std::list<mswr::ComPtr<IDWriteFontFamily>>::iterator family_iterator;
|
| + for (family_iterator = family_list.begin();
|
| + family_iterator != family_list.end(); ++family_iterator) {
|
| + mswr::ComPtr<IDWriteFont> matched_font;
|
| + (*family_iterator)->GetFirstMatchingFont(base_weight, base_stretch,
|
| + base_style, &matched_font);
|
| +
|
| + // |character_index| tracks how much of the string we have read. This is
|
| + // different from |mapped_length| because ReadUnicodeCharacter can advance
|
| + // |character_index| even if the character cannot be mapped (invalid
|
| + // surrogate pair or font does not contain a matching glyph).
|
| + int32_t character_index = 0;
|
| + uint32_t length = 0; // How much of the text can actually be mapped.
|
| + while (static_cast<uint32_t>(character_index) < text.length()) {
|
| + BOOL exists = false;
|
| + uint32_t character = 0;
|
| + if (!base::ReadUnicodeCharacter(text.c_str(), text.length(),
|
| + &character_index, &character))
|
| + break;
|
| + if (FAILED(matched_font->HasCharacter(character, &exists)) || !exists)
|
| + break;
|
| + character_index++;
|
| + length = character_index;
|
| + }
|
| +
|
| + if (length > 0) {
|
| + // Move the current family to the front of the list
|
| + family_list.splice(family_list.begin(), family_list, family_iterator);
|
| +
|
| + matched_font.CopyTo(font);
|
| + *mapped_length = length;
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void FontFallback::AddCachedFamily(
|
| + Microsoft::WRL::ComPtr<IDWriteFontFamily> family,
|
| + const wchar_t* base_family_name) {
|
| + std::list<mswr::ComPtr<IDWriteFontFamily>>& family_list =
|
| + fallback_family_cache_[base_family_name];
|
| + family_list.push_front(std::move(family));
|
| +
|
| + UMA_HISTOGRAM_COUNTS_100("DirectWrite.Fonts.Proxy.Fallback.CacheSize",
|
| + family_list.size());
|
| +
|
| + while (family_list.size() > kMaxFamilyCacheSize)
|
| + family_list.pop_back();
|
| +}
|
| +
|
| } // namespace content
|
|
|