| 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..e3e89dffee6326e5d1d1260acb7e9a317195ac9d 100644
|
| --- a/ui/gfx/font_fallback_win.cc
|
| +++ b/ui/gfx/font_fallback_win.cc
|
| @@ -4,10 +4,13 @@
|
|
|
| #include "ui/gfx/font_fallback_win.h"
|
|
|
| +#include <dwrite_2.h>
|
| #include <usp10.h>
|
| +#include <wrl.h>
|
|
|
| #include <map>
|
|
|
| +#include "base/i18n/rtl.h"
|
| #include "base/macros.h"
|
| #include "base/memory/singleton.h"
|
| #include "base/profiler/scoped_tracker.h"
|
| @@ -15,13 +18,19 @@
|
| #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"
|
| +#include "ui/gfx/win/direct_write.h"
|
| +#include "ui/gfx/win/text_analysis_source.h"
|
|
|
| namespace gfx {
|
|
|
| namespace {
|
|
|
| +IDWriteFactory* g_factory = nullptr;
|
| +
|
| // Queries the registry to get a mapping from font filenames to font names.
|
| void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
|
| const wchar_t* kFonts =
|
| @@ -175,6 +184,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 +340,71 @@ 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);
|
| +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());
|
| +
|
| + if (g_factory == nullptr) {
|
| + gfx::win::CreateDWriteFactory(&g_factory);
|
| + }
|
| + base::win::ScopedComPtr<IDWriteFactory2> factory2;
|
| + g_factory->QueryInterface(factory2.Receive());
|
| + if (!factory2) {
|
| + // IDWriteFactory2 is not available before Win8.1
|
| + return GetUniscribeFallbackFont(font, text, text_length, result);
|
| + }
|
|
|
| - // 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)
|
| + base::win::ScopedComPtr<IDWriteFontFallback> fallback;
|
| + if (FAILED(factory2->GetSystemFontFallback(fallback.Receive())))
|
| 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);
|
| + base::string16 locale = base::UTF8ToUTF16(base::i18n::GetConfiguredLocale());
|
|
|
| - if (SUCCEEDED(hresult)) {
|
| - hresult = ScriptStringOut(script_analysis, 0, 0, 0, NULL, 0, 0, FALSE);
|
| - ScriptStringFree(&script_analysis);
|
| + base::win::ScopedComPtr<IDWriteNumberSubstitution> number_substitution;
|
| + if (FAILED(factory2->CreateNumberSubstitution(
|
| + DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, locale.c_str(),
|
| + true /* ignoreUserOverride */, number_substitution.Receive()))) {
|
| + return false;
|
| }
|
|
|
| - 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;
|
| - }
|
| + uint32_t mapped_length = 0;
|
| + base::win::ScopedComPtr<IDWriteFont> mapped_font;
|
| + float scale = 0;
|
| + base::win::ScopedComPtr<IDWriteTextAnalysisSource> text_analysis;
|
| + DWRITE_READING_DIRECTION reading_direction =
|
| + base::i18n::IsRTL() ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
|
| + : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
| + if (FAILED(Microsoft::WRL::MakeAndInitialize<gfx::win::TextAnalysisSource>(
|
| + text_analysis.Receive(), text, locale.c_str(),
|
| + number_substitution.get(), reading_direction))) {
|
| + return false;
|
| + }
|
| + base::string16 original_name = base::UTF8ToUTF16(font.GetFontName());
|
| + DWRITE_FONT_STYLE font_style = DWRITE_FONT_STYLE_NORMAL;
|
| + if (font.GetStyle() & Font::ITALIC)
|
| + font_style = DWRITE_FONT_STYLE_ITALIC;
|
| + if (FAILED(fallback->MapCharacters(
|
| + text_analysis.get(), 0, text_length, nullptr, original_name.c_str(),
|
| + static_cast<DWRITE_FONT_WEIGHT>(font.GetWeight()), font_style,
|
| + DWRITE_FONT_STRETCH_NORMAL, &mapped_length, mapped_font.Receive(),
|
| + &scale))) {
|
| + return false;
|
| }
|
| - DeleteEnhMetaFile(meta_file);
|
|
|
| - return found_fallback;
|
| + if (mapped_font) {
|
| + base::string16 name;
|
| + if (FAILED(GetFamilyNameFromDirectWriteFont(mapped_font.get(), &name)))
|
| + return false;
|
| + *result = Font(base::UTF16ToUTF8(name), font.GetFontSize() * scale);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| } // namespace gfx
|
|
|