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

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: Fix clang build error due to signed-unsigned comparison Created 4 years, 5 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
13 #include "base/i18n/rtl.h"
11 #include "base/macros.h" 14 #include "base/macros.h"
12 #include "base/memory/singleton.h" 15 #include "base/memory/singleton.h"
13 #include "base/profiler/scoped_tracker.h" 16 #include "base/profiler/scoped_tracker.h"
14 #include "base/strings/string_split.h" 17 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
17 #include "base/win/registry.h" 20 #include "base/win/registry.h"
21 #include "base/win/scoped_comptr.h"
18 #include "ui/gfx/font.h" 22 #include "ui/gfx/font.h"
19 #include "ui/gfx/font_fallback.h" 23 #include "ui/gfx/font_fallback.h"
24 #include "ui/gfx/platform_font_win.h"
25 #include "ui/gfx/win/direct_write.h"
26 #include "ui/gfx/win/text_analysis_source.h"
20 27
21 namespace gfx { 28 namespace gfx {
22 29
23 namespace { 30 namespace {
24 31
25 // Queries the registry to get a mapping from font filenames to font names. 32 // Queries the registry to get a mapping from font filenames to font names.
26 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) { 33 void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
27 const wchar_t* kFonts = 34 const wchar_t* kFonts =
28 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; 35 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
29 36
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 int table_entries, 175 int table_entries,
169 LPARAM log_font) { 176 LPARAM log_font) {
170 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { 177 if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
171 const EMREXTCREATEFONTINDIRECTW* create_font_record = 178 const EMREXTCREATEFONTINDIRECTW* create_font_record =
172 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); 179 reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
173 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont; 180 *reinterpret_cast<LOGFONT*>(log_font) = create_font_record->elfw.elfLogFont;
174 } 181 }
175 return 1; 182 return 1;
176 } 183 }
177 184
185 bool GetUniscribeFallbackFont(const Font& font,
186 const wchar_t* text,
187 int text_length,
188 Font* result) {
189 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|.
190 // Uniscribe doesn't expose a method to query fallback fonts, so this works by
191 // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then
192 // inspecting the EMF object to figure out which font Uniscribe used.
193 //
194 // DirectWrite in Windows 8.1 provides a cleaner alternative:
195 // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx
196
197 static HDC hdc = CreateCompatibleDC(NULL);
198
199 // Use a meta file to intercept the fallback font chosen by Uniscribe.
200 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
201 if (!meta_file_dc)
202 return false;
203
204 SelectObject(meta_file_dc, font.GetNativeFont());
205
206 SCRIPT_STRING_ANALYSIS script_analysis;
207 HRESULT hresult =
208 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1,
209 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
210 0, NULL, NULL, NULL, NULL, NULL, &script_analysis);
211
212 if (SUCCEEDED(hresult)) {
213 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
214 ScriptStringFree(&script_analysis);
215 }
216
217 bool found_fallback = false;
218 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc);
219 if (SUCCEEDED(hresult)) {
220 LOGFONT log_font;
221 log_font.lfFaceName[0] = 0;
222 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
223 if (log_font.lfFaceName[0]) {
224 *result =
225 Font(base::UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
226 found_fallback = true;
227 }
228 }
229 DeleteEnhMetaFile(meta_file);
230
231 return found_fallback;
232 }
233
178 } // namespace 234 } // namespace
179 235
180 namespace internal { 236 namespace internal {
181 237
182 void ParseFontLinkEntry(const std::string& entry, 238 void ParseFontLinkEntry(const std::string& entry,
183 std::string* filename, 239 std::string* filename,
184 std::string* font_name) { 240 std::string* font_name) {
185 std::vector<std::string> parts = base::SplitString( 241 std::vector<std::string> parts = base::SplitString(
186 entry, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 242 entry, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
187 filename->clear(); 243 filename->clear();
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 331
276 // LinkedFontsIterator doesn't care about the font size, so we always pass 10. 332 // LinkedFontsIterator doesn't care about the font size, so we always pass 10.
277 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10)); 333 internal::LinkedFontsIterator linked_fonts(Font(font_family, 10));
278 std::vector<Font> fallback_fonts; 334 std::vector<Font> fallback_fonts;
279 Font current; 335 Font current;
280 while (linked_fonts.NextFont(&current)) 336 while (linked_fonts.NextFont(&current))
281 fallback_fonts.push_back(current); 337 fallback_fonts.push_back(current);
282 return fallback_fonts; 338 return fallback_fonts;
283 } 339 }
284 340
285 bool GetUniscribeFallbackFont(const Font& font, 341 bool GetFallbackFont(const Font& font,
286 const wchar_t* text, 342 const wchar_t* text,
287 int text_length, 343 int text_length,
288 Font* result) { 344 Font* result) {
289 // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. 345 // 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 346 // 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 347 // renderer this can cause hangs. Code that needs font fallback in the
292 // inspecting the EMF object to figure out which font Uniscribe used. 348 // renderer should instead use the font proxy.
293 // 349 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 350
297 static HDC hdc = CreateCompatibleDC(NULL); 351 base::win::ScopedComPtr<IDWriteFactory> factory;
352 gfx::win::CreateDWriteFactory(factory.Receive());
353 base::win::ScopedComPtr<IDWriteFactory2> factory2;
354 factory.QueryInterface(factory2.Receive());
355 if (!factory2) {
356 // IDWriteFactory2 is not available before Win8.1
357 return GetUniscribeFallbackFont(font, text, text_length, result);
358 }
298 359
299 // Use a meta file to intercept the fallback font chosen by Uniscribe. 360 base::win::ScopedComPtr<IDWriteFontFallback> fallback;
300 HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); 361 if (FAILED(factory2->GetSystemFontFallback(fallback.Receive())))
301 if (!meta_file_dc)
302 return false; 362 return false;
303 363
304 SelectObject(meta_file_dc, font.GetNativeFont()); 364 base::string16 locale = base::UTF8ToUTF16(base::i18n::GetConfiguredLocale());
305 365
306 SCRIPT_STRING_ANALYSIS script_analysis; 366 base::win::ScopedComPtr<IDWriteNumberSubstitution> number_substitution;
307 HRESULT hresult = 367 if (FAILED(factory2->CreateNumberSubstitution(
308 ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1, 368 DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, locale.c_str(),
309 SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, 369 true /* ignoreUserOverride */, number_substitution.Receive()))) {
310 0, NULL, NULL, NULL, NULL, NULL, &script_analysis); 370 return false;
311
312 if (SUCCEEDED(hresult)) {
313 hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
314 ScriptStringFree(&script_analysis);
315 } 371 }
316 372
317 bool found_fallback = false; 373 uint32_t mapped_length = 0;
318 HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); 374 base::win::ScopedComPtr<IDWriteFont> mapped_font;
319 if (SUCCEEDED(hresult)) { 375 float scale = 0;
320 LOGFONT log_font; 376 base::win::ScopedComPtr<IDWriteTextAnalysisSource> text_analysis;
321 log_font.lfFaceName[0] = 0; 377 DWRITE_READING_DIRECTION reading_direction =
322 EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); 378 base::i18n::IsRTL() ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
msw 2016/06/27 20:45:36 I think this should actually use GetFirstStrongCha
Ilya Kulshin 2016/06/28 18:08:01 Using GetFirstStrongCharacterDirection might give
msw 2016/06/28 18:37:23 Hmm, perhaps; we've had bugs in the past about tab
323 if (log_font.lfFaceName[0]) { 379 : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
324 *result = Font(base::UTF16ToUTF8(log_font.lfFaceName), 380 if (FAILED(Microsoft::WRL::MakeAndInitialize<gfx::win::TextAnalysisSource>(
325 font.GetFontSize()); 381 text_analysis.Receive(), text, locale.c_str(),
326 found_fallback = true; 382 number_substitution.get(), reading_direction))) {
327 } 383 return false;
328 } 384 }
329 DeleteEnhMetaFile(meta_file); 385 base::string16 original_name = base::UTF8ToUTF16(font.GetFontName());
386 DWRITE_FONT_STYLE font_style = DWRITE_FONT_STYLE_NORMAL;
387 if (font.GetStyle() & Font::ITALIC)
388 font_style = DWRITE_FONT_STYLE_ITALIC;
389 if (FAILED(fallback->MapCharacters(
390 text_analysis.get(), 0, text_length, nullptr, original_name.c_str(),
391 static_cast<DWRITE_FONT_WEIGHT>(font.GetWeight()), font_style,
392 DWRITE_FONT_STRETCH_NORMAL, &mapped_length, mapped_font.Receive(),
393 &scale))) {
394 return false;
395 }
330 396
331 return found_fallback; 397 if (mapped_font) {
398 base::string16 name;
399 if (FAILED(GetFamilyNameFromDirectWriteFont(mapped_font.get(), &name)))
400 return false;
401 *result = Font(base::UTF16ToUTF8(name), font.GetFontSize() * scale);
402 return true;
403 }
404 return false;
332 } 405 }
333 406
334 } // namespace gfx 407 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698