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

Side by Side Diff: ui/gfx/font_fallback_win.cc

Issue 2054273002: Font fallback for UI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Actually delete old TextAnalysisSource Created 4 years, 6 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "ui/gfx/font_fallback_win.h" 5 #include "ui/gfx/font_fallback_win.h"
6 6
7 #include <dwrite_2.h>
7 #include <usp10.h> 8 #include <usp10.h>
9 #include <wrl.h>
8 10
9 #include <map> 11 #include <map>
10 12
11 #include "base/macros.h" 13 #include "base/macros.h"
12 #include "base/memory/singleton.h" 14 #include "base/memory/singleton.h"
13 #include "base/profiler/scoped_tracker.h" 15 #include "base/profiler/scoped_tracker.h"
14 #include "base/strings/string_split.h" 16 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
17 #include "base/win/registry.h" 19 #include "base/win/registry.h"
20 #include "base/win/scoped_comptr.h"
18 #include "ui/gfx/font.h" 21 #include "ui/gfx/font.h"
19 #include "ui/gfx/font_fallback.h" 22 #include "ui/gfx/font_fallback.h"
23 #include "ui/gfx/platform_font_win.h"
msw 2016/06/23 20:59:37 q: what is this used for?
Ilya Kulshin 2016/06/24 20:48:24 This is needed for GetFamilyNameFromDirectWriteFon
msw 2016/06/27 20:45:36 Acknowledged.
24 #include "ui/gfx/win/direct_write.h"
25 #include "ui/gfx/win/dwrite_text_analysis_source.h"
20 26
21 namespace gfx { 27 namespace gfx {
22 28
23 namespace { 29 namespace {
24 30
25 // Queries the registry to get a mapping from font filenames to font names. 31 // Queries the registry to get a mapping from font filenames to font names.
26 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) { 32 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
27 const wchar_t* kFonts = 33 const wchar_t* kFonts =
28 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 34 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
29 35
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 int table_entries, 174 int table_entries,
169 LPARAM log_font) { 175 LPARAM log_font) {
170 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { 176 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
171 const EMREXTCREATEFONTINDIRECTW* create_font_record = 177 const EMREXTCREATEFONTINDIRECTW* create_font_record =
172 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); 178 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
173 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont; 179 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
174 } 180 }
175 return 1; 181 return 1;
176 } 182 }
177 183
184 bool GetUniscribeFallbackFont(const Font& font,
185 const wchar_t* text,
186 int text_length,
187 Font* result) {
188 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
189 // Uniscribe doesn't expose a method to query fallback fonts, so this works by
190 // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then
191 // inspecting the EMF object to figure out which font Uniscribe used.
192 //
193 // DirectWrite in Windows 8.1 provides a cleaner alternative:
194 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
195
196 static HDC hdc = CreateCompatibleDC(NULL);
197
198 // Use a meta file to intercept the fallback font chosen by Uniscribe.
199 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
200 if (!meta_file_dc)
201 return false;
202
203 SelectObject(meta_file_dc, font.GetNativeFont());
204
205 SCRIPT_STRING_ANALYSIS script_analysis;
206 HRESULT hresult =
207 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
208 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
209 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
210
211 if (SUCCEEDED(hresult)) {
212 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
213 ScriptStringFree(&script_analysis);
214 }
215
216 bool found_fallback = false;
217 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
218 if (SUCCEEDED(hresult)) {
219 LOGFONT log_font;
220 log_font.lfFaceName[0] = 0;
221 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
222 if (log_font.lfFaceName[0]) {
223 *result =
224 Font(base::UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
225 found_fallback = true;
226 }
227 }
228 DeleteEnhMetaFile(meta_file);
229
230 return found_fallback;
231 }
232
178 } // namespace 233 } // namespace
179 234
180 namespace internal { 235 namespace internal {
181 236
182 void ParseFontLinkEntry(const std::string& entry, 237 void ParseFontLinkEntry(const std::string& entry,
183 std::string* filename, 238 std::string* filename,
184 std::string* font_name) { 239 std::string* font_name) {
185 std::vector<std::string> parts = base::SplitString( 240 std::vector<std::string> parts = base::SplitString(
186 entry, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 241 entry, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
187 filename->clear(); 242 filename->clear();
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 330
276 // LinkedFontsIterator doesn't care about the font size, so we always pass 10. 331 // LinkedFontsIterator doesn't care about the font size, so we always pass 10.
277 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10)); 332 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10));
278 std::vector<Font> fallback_fonts; 333 std::vector<Font> fallback_fonts;
279 Font current; 334 Font current;
280 while (linked_fonts.NextFont(&current)) 335 while (linked_fonts.NextFont(&current))
281 fallback_fonts.push_back(current); 336 fallback_fonts.push_back(current);
282 return fallback_fonts; 337 return fallback_fonts;
283 } 338 }
284 339
285 bool GetUniscribeFallbackFont(const Font& font, 340 bool GetFallbackFont(const Font& font,
286 const wchar_t* text, 341 const wchar_t* text,
287 int text_length, 342 int text_length,
288 Font* result) { 343 Font* result) {
289 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. 344 // Creating a DirectWrite font fallback can be expensive. It's ok in the
290 // Uniscribe doesn't expose a method to query fallback fonts, so this works by 345 // browser process because we can use the shared system fallback, but in the
291 // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then 346 // renderer this can cause hangs. Code that needs font fallback in the
292 // inspecting the EMF object to figure out which font Uniscribe used. 347 // renderer should instead use the font proxy.
293 // 348 DCHECK(base::MessageLoopForUI::IsCurrent());
294 // DirectWrite in Windows 8.1 provides a cleaner alternative:
295 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
296 349
297 static HDC hdc = CreateCompatibleDC(NULL); 350 base::win::ScopedComPtr<IDWriteFactory> factory;
298 351 gfx::win::CreateDWriteFactory(factory.Receive());
msw 2016/06/23 20:59:38 Is it unreasonably expensive for every fallback at
Ilya Kulshin 2016/06/24 20:48:24 Now that we no longer need to support XP and Vista
msw 2016/06/27 20:45:36 Is it not easily feasible to cache an instance in
msw 2016/06/28 18:37:23 Ping?
Ilya Kulshin 2016/06/28 20:32:52 Sorry, didn't notice this comment. I did some meas
299 // Use a meta file to intercept the fallback font chosen by Uniscribe. 352 base::win::ScopedComPtr<IDWriteFactory2> factory2;
300 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); 353 factory.QueryInterface(factory2.Receive());
301 if (!meta_file_dc) 354 if (!factory2) {
302 return false; 355 // IDWriteFactory2 is not available before Win8.1
303 356 return GetUniscribeFallbackFont(font, text, text_length, result);
304 SelectObject(meta_file_dc, font.GetNativeFont());
305
306 SCRIPT_STRING_ANALYSIS script_analysis;
307 HRESULT hresult =
308 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
309 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
310 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
311
312 if (SUCCEEDED(hresult)) {
313 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
314 ScriptStringFree(&script_analysis);
315 } 357 }
316 358
317 bool found_fallback = false; 359 base::win::ScopedComPtr<IDWriteFontFallback> fallback;
318 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); 360 factory2->GetSystemFontFallback(fallback.Receive());
319 if (SUCCEEDED(hresult)) { 361
320 LOGFONT log_font; 362 base::win::ScopedComPtr<IDWriteNumberSubstitution> number_substitution;
321 log_font.lfFaceName[0] = 0; 363 factory2->CreateNumberSubstitution(
322 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); 364 DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, L"" /* locale */,
msw 2016/06/23 20:59:37 Can/should we use the actual locale from base::18n
Ilya Kulshin 2016/06/24 20:48:24 Done.
323 if (log_font.lfFaceName[0]) { 365 true /* ignoreUserOverride */, number_substitution.Receive());
324 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName), 366
325 font.GetFontSize()); 367 uint32_t mapped_length = 0;
326 found_fallback = true; 368 base::win::ScopedComPtr<IDWriteFont> mapped_font;
327 } 369 float scale = 0;
370 base::win::ScopedComPtr<IDWriteTextAnalysisSource> text_analysis;
371 Microsoft::WRL::MakeAndInitialize<gfx::win::TextAnalysisSource>(
msw 2016/06/23 20:59:38 This can fail; try uniscribe (or bail?) if it does
Ilya Kulshin 2016/06/24 20:48:24 This would only fail if we fail to alloc memory. I
msw 2016/06/27 20:45:36 Acknowledged.
372 text_analysis.Receive(), text, L"" /* locale */,
msw 2016/06/23 20:59:37 ditto locale q
Ilya Kulshin 2016/06/24 20:48:24 Done.
373 number_substitution.get(), DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
msw 2016/06/23 20:59:38 Can/should we use the actual text direction here?
Ilya Kulshin 2016/06/24 20:48:24 Done.
374 base::string16 original_name = base::UTF8ToUTF16(font.GetFontName());
375 fallback->MapCharacters(text_analysis.get(), 0, text_length, nullptr,
376 original_name.c_str(), DWRITE_FONT_WEIGHT_NORMAL,
msw 2016/06/23 20:59:37 Can/should we use the weight and style of the inpu
Ilya Kulshin 2016/06/24 20:48:24 Weight was fairly simple to pipe through. Style wa
msw 2016/06/27 20:45:36 Acknowledged.
377 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
378 &mapped_length, mapped_font.Receive(), &scale);
379
380 if (mapped_font) {
381 base::string16 family_name;
382 GetFamilyNameFromDirectWriteFont(mapped_font.get(), &family_name);
msw 2016/06/23 20:59:38 Check the result here (or remove the result and ju
Ilya Kulshin 2016/06/24 20:48:24 Done.
383 *result = Font(base::UTF16ToUTF8(family_name), font.GetFontSize() * scale);
384 return true;
328 } 385 }
329 DeleteEnhMetaFile(meta_file); 386 return false;
msw 2016/06/23 20:59:38 Fall back to uniscribe here?
Ilya Kulshin 2016/06/24 20:48:24 DirectWrite returns a null mapped_font if it canno
msw 2016/06/27 20:45:36 Acknowledged.
330
331 return found_fallback;
332 } 387 }
333 388
334 } // namespace gfx 389 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/font_fallback_win.h ('k') | ui/gfx/gfx.gyp » ('j') | ui/gfx/platform_font_win.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698