Chromium Code Reviews| Index: ui/gfx/font_fallback_win.cc |
| diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc |
| index 8b45b2e53b14bb654e603013490dc0547a649028..0f222c4e016dea2aa959578c3294ef75563d5683 100644 |
| --- a/ui/gfx/font_fallback_win.cc |
| +++ b/ui/gfx/font_fallback_win.cc |
| @@ -4,7 +4,9 @@ |
| #include "ui/gfx/font_fallback_win.h" |
| +#include <dwrite_2.h> |
| #include <usp10.h> |
| +#include <wrl.h> |
| #include <map> |
| @@ -15,8 +17,12 @@ |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/registry.h" |
| +#include "base/win/scoped_comptr.h" |
| #include "ui/gfx/font.h" |
| #include "ui/gfx/font_fallback.h" |
| +#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.
|
| +#include "ui/gfx/win/direct_write.h" |
| +#include "ui/gfx/win/dwrite_text_analysis_source.h" |
| namespace gfx { |
| @@ -175,6 +181,55 @@ int CALLBACK MetaFileEnumProc(HDC hdc, |
| return 1; |
| } |
| +bool GetUniscribeFallbackFont(const Font& font, |
| + const wchar_t* text, |
| + int text_length, |
| + Font* result) { |
| + // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. |
| + // Uniscribe doesn't expose a method to query fallback fonts, so this works by |
| + // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then |
| + // inspecting the EMF object to figure out which font Uniscribe used. |
| + // |
| + // DirectWrite in Windows 8.1 provides a cleaner alternative: |
| + // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx |
| + |
| + static HDC hdc = CreateCompatibleDC(NULL); |
| + |
| + // Use a meta file to intercept the fallback font chosen by Uniscribe. |
| + HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); |
| + if (!meta_file_dc) |
| + return false; |
| + |
| + SelectObject(meta_file_dc, font.GetNativeFont()); |
| + |
| + SCRIPT_STRING_ANALYSIS script_analysis; |
| + HRESULT hresult = |
| + ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1, |
| + SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, |
| + 0, NULL, NULL, NULL, NULL, NULL, &script_analysis); |
| + |
| + if (SUCCEEDED(hresult)) { |
| + hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE); |
| + ScriptStringFree(&script_analysis); |
| + } |
| + |
| + bool found_fallback = false; |
| + HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); |
| + if (SUCCEEDED(hresult)) { |
| + LOGFONT log_font; |
| + log_font.lfFaceName[0] = 0; |
| + EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); |
| + if (log_font.lfFaceName[0]) { |
| + *result = |
| + Font(base::UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize()); |
| + found_fallback = true; |
| + } |
| + } |
| + DeleteEnhMetaFile(meta_file); |
| + |
| + return found_fallback; |
| +} |
| + |
| } // namespace |
| namespace internal { |
| @@ -282,53 +337,53 @@ std::vector<Font> GetFallbackFonts(const Font& font) { |
| return fallback_fonts; |
| } |
| -bool GetUniscribeFallbackFont(const Font& font, |
| - const wchar_t* text, |
| - int text_length, |
| - Font* result) { |
| - // Adapted from WebKit's |FontCache::GetFontDataForCharacters()|. |
| - // Uniscribe doesn't expose a method to query fallback fonts, so this works by |
| - // drawing the text to an EMF object with Uniscribe's ScriptStringOut and then |
| - // inspecting the EMF object to figure out which font Uniscribe used. |
| - // |
| - // DirectWrite in Windows 8.1 provides a cleaner alternative: |
| - // http://msdn.microsoft.com/en-us/library/windows/desktop/dn280480.aspx |
| - |
| - static HDC hdc = CreateCompatibleDC(NULL); |
| - |
| - // Use a meta file to intercept the fallback font chosen by Uniscribe. |
| - HDC meta_file_dc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); |
| - if (!meta_file_dc) |
| - return false; |
| - |
| - SelectObject(meta_file_dc, font.GetNativeFont()); |
| - |
| - SCRIPT_STRING_ANALYSIS script_analysis; |
| - HRESULT hresult = |
| - ScriptStringAnalyse(meta_file_dc, text, text_length, 0, -1, |
| - SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, |
| - 0, NULL, NULL, NULL, NULL, NULL, &script_analysis); |
| - |
| - if (SUCCEEDED(hresult)) { |
| - hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE); |
| - ScriptStringFree(&script_analysis); |
| +bool GetFallbackFont(const Font& font, |
| + const wchar_t* text, |
| + int text_length, |
| + Font* result) { |
| + // Creating a DirectWrite font fallback can be expensive. It's ok in the |
| + // browser process because we can use the shared system fallback, but in the |
| + // renderer this can cause hangs. Code that needs font fallback in the |
| + // renderer should instead use the font proxy. |
| + DCHECK(base::MessageLoopForUI::IsCurrent()); |
| + |
| + base::win::ScopedComPtr<IDWriteFactory> factory; |
| + 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
|
| + base::win::ScopedComPtr<IDWriteFactory2> factory2; |
| + factory.QueryInterface(factory2.Receive()); |
| + if (!factory2) { |
| + // IDWriteFactory2 is not available before Win8.1 |
| + return GetUniscribeFallbackFont(font, text, text_length, result); |
| } |
| - bool found_fallback = false; |
| - HENHMETAFILE meta_file = CloseEnhMetaFile(meta_file_dc); |
| - if (SUCCEEDED(hresult)) { |
| - LOGFONT log_font; |
| - log_font.lfFaceName[0] = 0; |
| - EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL); |
| - if (log_font.lfFaceName[0]) { |
| - *result = Font(base::UTF16ToUTF8(log_font.lfFaceName), |
| - font.GetFontSize()); |
| - found_fallback = true; |
| - } |
| + base::win::ScopedComPtr<IDWriteFontFallback> fallback; |
| + factory2->GetSystemFontFallback(fallback.Receive()); |
| + |
| + base::win::ScopedComPtr<IDWriteNumberSubstitution> number_substitution; |
| + factory2->CreateNumberSubstitution( |
| + 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.
|
| + true /* ignoreUserOverride */, number_substitution.Receive()); |
| + |
| + uint32_t mapped_length = 0; |
| + base::win::ScopedComPtr<IDWriteFont> mapped_font; |
| + float scale = 0; |
| + base::win::ScopedComPtr<IDWriteTextAnalysisSource> text_analysis; |
| + 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.
|
| + 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.
|
| + 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.
|
| + base::string16 original_name = base::UTF8ToUTF16(font.GetFontName()); |
| + fallback->MapCharacters(text_analysis.get(), 0, text_length, nullptr, |
| + 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.
|
| + DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, |
| + &mapped_length, mapped_font.Receive(), &scale); |
| + |
| + if (mapped_font) { |
| + base::string16 family_name; |
| + 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.
|
| + *result = Font(base::UTF16ToUTF8(family_name), font.GetFontSize() * scale); |
| + return true; |
| } |
| - DeleteEnhMetaFile(meta_file); |
| - |
| - return found_fallback; |
| + 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.
|
| } |
| } // namespace gfx |