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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/dwrite_font_proxy/font_fallback_win.h" 5 #include "content/child/dwrite_font_proxy/font_fallback_win.h"
6 6
7 #include <math.h>
8
9 #include <algorithm>
10
11 #include "base/metrics/histogram_macros.h"
7 #include "base/strings/string16.h" 12 #include "base/strings/string16.h"
8 13 #include "base/strings/utf_string_conversion_utils.h"
9 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h" 14 #include "content/child/dwrite_font_proxy/dwrite_font_proxy_win.h"
10 #include "content/common/dwrite_font_proxy_messages.h" 15 #include "content/common/dwrite_font_proxy_messages.h"
11 #include "content/public/child/child_thread.h" 16 #include "content/public/child/child_thread.h"
12 #include "ipc/ipc_sender.h" 17 #include "ipc/ipc_sender.h"
13 18
14 namespace mswr = Microsoft::WRL; 19 namespace mswr = Microsoft::WRL;
15 20
16 namespace content { 21 namespace content {
17 22
23 namespace {
24
25 const size_t kMaxFamilyCacheSize = 10;
26
27 // This enum is used to define the buckets for an enumerated UMA histogram.
28 // Hence,
29 // (a) existing enumerated constants should never be deleted or reordered, and
30 // (b) new constants should only be appended at the end of the enumeration.
31 enum DirectWriteFontFallbackResult {
32 FAILED_NO_FONT = 0,
33 SUCCESS_CACHE = 1,
34 SUCCESS_IPC = 2,
35
36 FONT_FALLBACK_RESULT_MAX_VALUE
37 };
38
39 void LogFallbackResult(DirectWriteFontFallbackResult fallback_result) {
40 UMA_HISTOGRAM_ENUMERATION("DirectWrite.Fonts.Proxy.FallbackResult",
41 fallback_result, FONT_FALLBACK_RESULT_MAX_VALUE);
42 }
43
44 } // namespace
45
18 FontFallback::FontFallback() = default; 46 FontFallback::FontFallback() = default;
19 FontFallback::~FontFallback() = default; 47 FontFallback::~FontFallback() = default;
20 48
21 HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source, 49 HRESULT FontFallback::MapCharacters(IDWriteTextAnalysisSource* source,
22 UINT32 text_position, 50 UINT32 text_position,
23 UINT32 text_length, 51 UINT32 text_length,
24 IDWriteFontCollection* base_font_collection, 52 IDWriteFontCollection* base_font_collection,
25 const wchar_t* base_family_name, 53 const wchar_t* base_family_name,
26 DWRITE_FONT_WEIGHT base_weight, 54 DWRITE_FONT_WEIGHT base_weight,
27 DWRITE_FONT_STYLE base_style, 55 DWRITE_FONT_STYLE base_style,
28 DWRITE_FONT_STRETCH base_stretch, 56 DWRITE_FONT_STRETCH base_stretch,
29 UINT32* mapped_length, 57 UINT32* mapped_length,
30 IDWriteFont** mapped_font, 58 IDWriteFont** mapped_font,
31 FLOAT* scale) { 59 FLOAT* scale) {
32 *mapped_font = nullptr; 60 *mapped_font = nullptr;
33 *mapped_length = 1; 61 *mapped_length = 1;
34 *scale = 1.0; 62 *scale = 1.0;
35 63
36 const WCHAR* text = nullptr; 64 const WCHAR* text = nullptr;
37 UINT32 chunk_length = 0; 65 UINT32 chunk_length = 0;
38 if (FAILED(source->GetTextAtPosition(text_position, &text, &chunk_length))) { 66 if (FAILED(source->GetTextAtPosition(text_position, &text, &chunk_length))) {
39 DCHECK(false); 67 DCHECK(false);
40 return E_FAIL; 68 return E_FAIL;
41 } 69 }
42 base::string16 text_chunk(text, chunk_length); 70 base::string16 text_chunk(text, std::min(chunk_length, text_length));
71
72 if (text_chunk.size() == 0) {
73 DCHECK(false);
74 return E_INVALIDARG;
75 }
76
77 base_family_name = base_family_name ? base_family_name : L"";
78
79 if (GetCachedFont(text_chunk, base_family_name, base_weight, base_style,
80 base_stretch, mapped_font, mapped_length)) {
81 DCHECK(*mapped_font);
82 DCHECK_GT(*mapped_length, 0u);
83 LogFallbackResult(SUCCESS_CACHE);
84 return S_OK;
85 }
86
87 TRACE_EVENT0("dwrite", "FontFallback::MapCharacters (IPC)");
43 88
44 const WCHAR* locale = nullptr; 89 const WCHAR* locale = nullptr;
45 // |locale_text_length| is actually the length of text with the locale, not 90 // |locale_text_length| is actually the length of text with the locale, not
46 // the length of the locale string itself. 91 // the length of the locale string itself.
47 UINT32 locale_text_length = 0; 92 UINT32 locale_text_length = 0;
48 source->GetLocaleName(text_position /*textPosition*/, &locale_text_length, 93 source->GetLocaleName(text_position /*textPosition*/, &locale_text_length,
49 &locale); 94 &locale);
50 95
51 if (locale == nullptr) 96 locale = locale ? locale : L"";
52 locale = L"";
53 97
54 DWriteFontStyle style; 98 DWriteFontStyle style;
55 style.font_weight = base_weight; 99 style.font_weight = base_weight;
56 style.font_slant = base_style; 100 style.font_slant = base_style;
57 style.font_stretch = base_stretch; 101 style.font_stretch = base_stretch;
58 102
59 MapCharactersResult result; 103 MapCharactersResult result;
60 104
61 IPC::Sender* sender = 105 IPC::Sender* sender =
62 sender_override_ ? sender_override_ : ChildThread::Get(); 106 sender_override_ ? sender_override_ : ChildThread::Get();
63 if (!sender->Send(new DWriteFontProxyMsg_MapCharacters( 107 if (!sender->Send(new DWriteFontProxyMsg_MapCharacters(
64 text_chunk, style, locale, source->GetParagraphReadingDirection(), 108 text_chunk, style, locale, source->GetParagraphReadingDirection(),
65 base_family_name ? base_family_name : L"", &result))) 109 base_family_name, &result))) {
110 DCHECK(false);
66 return E_FAIL; 111 return E_FAIL;
112 }
113
114 // We don't cache scale in the fallback cache, and Skia ignores scale anyway.
115 // If we ever get a result that's significantly different from 1 we may need
116 // to consider whether it's worth doing the work to plumb it through.
117 DCHECK(fabs(*scale - 1.0f) < 0.00001);
67 118
68 *mapped_length = result.mapped_length; 119 *mapped_length = result.mapped_length;
69 *scale = result.scale; 120 *scale = result.scale;
70 121
71 if (result.family_index == UINT32_MAX) 122 if (result.family_index == UINT32_MAX) {
123 LogFallbackResult(FAILED_NO_FONT);
72 return S_OK; 124 return S_OK;
125 }
73 126
74 mswr::ComPtr<IDWriteFontFamily> family; 127 mswr::ComPtr<IDWriteFontFamily> family;
75 // It would be nice to find a way to determine at runtime if |collection_| is 128 // It would be nice to find a way to determine at runtime if |collection_| is
76 // a proxy collection, or just a generic IDWriteFontCollection. Unfortunately 129 // a proxy collection, or just a generic IDWriteFontCollection. Unfortunately
77 // I can't find a way to get QueryInterface to return the actual class when 130 // I can't find a way to get QueryInterface to return the actual class when
78 // using mswr::RuntimeClass. If we could use QI, we can fallback on 131 // using mswr::RuntimeClass. If we could use QI, we can fallback on
79 // FindFontFamily if the proxy is not available. 132 // FindFontFamily if the proxy is not available.
80 if (!collection_->GetFontFamily(result.family_index, result.family_name, 133 if (!collection_->GetFontFamily(result.family_index, result.family_name,
81 &family)) { 134 &family)) {
82 DCHECK(false); 135 DCHECK(false);
83 return E_FAIL; 136 return E_FAIL;
84 } 137 }
85 138
86 if (FAILED(family->GetFirstMatchingFont( 139 if (FAILED(family->GetFirstMatchingFont(
87 static_cast<DWRITE_FONT_WEIGHT>(result.font_style.font_weight), 140 static_cast<DWRITE_FONT_WEIGHT>(result.font_style.font_weight),
88 static_cast<DWRITE_FONT_STRETCH>(result.font_style.font_stretch), 141 static_cast<DWRITE_FONT_STRETCH>(result.font_style.font_stretch),
89 static_cast<DWRITE_FONT_STYLE>(result.font_style.font_slant), 142 static_cast<DWRITE_FONT_STYLE>(result.font_style.font_slant),
90 mapped_font))) { 143 mapped_font))) {
91 DCHECK(false); 144 DCHECK(false);
92 return E_FAIL; 145 return E_FAIL;
93 } 146 }
94 147
95 DCHECK(*mapped_font); 148 DCHECK(*mapped_font);
96 149 AddCachedFamily(std::move(family), base_family_name);
150 LogFallbackResult(SUCCESS_IPC);
97 return S_OK; 151 return S_OK;
98 } 152 }
99 153
100 HRESULT STDMETHODCALLTYPE 154 HRESULT STDMETHODCALLTYPE
101 FontFallback::RuntimeClassInitialize(DWriteFontCollectionProxy* collection, 155 FontFallback::RuntimeClassInitialize(DWriteFontCollectionProxy* collection,
102 IPC::Sender* sender_override) { 156 IPC::Sender* sender_override) {
103 sender_override_ = sender_override; 157 sender_override_ = sender_override;
104 collection_ = collection; 158 collection_ = collection;
105 return S_OK; 159 return S_OK;
106 } 160 }
107 161
162 bool FontFallback::GetCachedFont(const base::string16& text,
163 const wchar_t* base_family_name,
164 DWRITE_FONT_WEIGHT base_weight,
165 DWRITE_FONT_STYLE base_style,
166 DWRITE_FONT_STRETCH base_stretch,
167 IDWriteFont** font,
168 uint32_t* mapped_length) {
169 std::map<base::string16, std::list<mswr::ComPtr<IDWriteFontFamily>>>::iterator
170 it = fallback_family_cache_.find(base_family_name);
171 if (it == fallback_family_cache_.end())
172 return false;
173
174 TRACE_EVENT0("dwrite", "FontFallback::GetCachedFont");
175
176 std::list<mswr::ComPtr<IDWriteFontFamily>>& family_list = it->second;
177 std::list<mswr::ComPtr<IDWriteFontFamily>>::iterator family_iterator;
178 for (family_iterator = family_list.begin();
179 family_iterator != family_list.end(); ++family_iterator) {
180 mswr::ComPtr<IDWriteFont> matched_font;
181 (*family_iterator)->GetFirstMatchingFont(base_weight, base_stretch,
182 base_style, &matched_font);
183
184 // |character_index| tracks how much of the string we have read. This is
185 // different from |mapped_length| because ReadUnicodeCharacter can advance
186 // |character_index| even if the character cannot be mapped (invalid
187 // surrogate pair or font does not contain a matching glyph).
188 int32_t character_index = 0;
189 uint32_t length = 0; // How much of the text can actually be mapped.
190 while (static_cast<uint32_t>(character_index) < text.length()) {
191 BOOL exists = false;
192 uint32_t character = 0;
193 if (!base::ReadUnicodeCharacter(text.c_str(), text.length(),
194 &character_index, &character))
195 break;
196 if (FAILED(matched_font->HasCharacter(character, &exists)) || !exists)
197 break;
198 character_index++;
199 length = character_index;
200 }
201
202 if (length > 0) {
203 // Move the current family to the front of the list
204 family_list.splice(family_list.begin(), family_list, family_iterator);
205
206 matched_font.CopyTo(font);
207 *mapped_length = length;
208 return true;
209 }
210 }
211
212 return false;
213 }
214
215 void FontFallback::AddCachedFamily(
216 Microsoft::WRL::ComPtr<IDWriteFontFamily> family,
217 const wchar_t* base_family_name) {
218 std::list<mswr::ComPtr<IDWriteFontFamily>>& family_list =
219 fallback_family_cache_[base_family_name];
220 family_list.push_front(std::move(family));
221
222 UMA_HISTOGRAM_COUNTS_100("DirectWrite.Fonts.Proxy.Fallback.CacheSize",
223 family_list.size());
224
225 while (family_list.size() > kMaxFamilyCacheSize)
226 family_list.pop_back();
227 }
228
108 } // namespace content 229 } // namespace content
OLDNEW
« 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