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

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

Issue 1906633003: Implement fallback cache (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@blinkfontfallback
Patch Set: Add some checks and comments Created 4 years, 8 months 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/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
« no previous file with comments | « content/child/dwrite_font_proxy/font_fallback_win.h ('k') | content/child/dwrite_font_proxy/font_fallback_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698