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

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

Powered by Google App Engine
This is Rietveld 408576698