Commit 326e11b2 authored by Etienne Bergeron's avatar Etienne Bergeron Committed by Commit Bot

Implement the GetFontList using DWrite instead of GDI API.

This CL is modifying the font-settings API on Windows.

The goal of this CL is to remove the
gfx::PlatformFontWin::GetLocalizedFontName(...) calls since
the gfx::PlatformFontWin will be replaced by
gfx::PlatformFontSkia.

The GDI API was listing the system fonts by using the system
locale which means the font-name was the localized name.
The DWrite API allows the caller to specify the locale and is
not forced to be the system one.

The font-settings API is shipping a list of pair of string to
extensions when the GetList is called
(e.g fontId and displayName).

The fontId is used as an identifier for other font-settings API.
The DisplayName is the name that is displayed to the user.

On windows, both string were used to be the Localized name since
the GDI API was returning the localized name. A extra conversion
was needed when an other windows API returns a non-localized name
to be sure it will be the same FontID.

By enforcing fontId to be non-localized, these extra conversion
are now useless. And only the displayName is localized.

Bug: 944227

Change-Id: Iab1bff832504fbf9abc8860ece31357148c01cee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1606661
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: default avatarEtienne Bergeron <etienneb@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarKoji Ishii <kojii@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662886}
parent d9af410f
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system.h"
#include "extensions/common/error_utils.h" #include "extensions/common/error_utils.h"
#if defined(OS_WIN)
#include "ui/gfx/win/direct_write.h"
#endif // defined(OS_WIN)
namespace extensions { namespace extensions {
namespace fonts = api::font_settings; namespace fonts = api::font_settings;
...@@ -78,6 +82,20 @@ std::string GetFontNamePrefPath(fonts::GenericFamily generic_family_enum, ...@@ -78,6 +82,20 @@ std::string GetFontNamePrefPath(fonts::GenericFamily generic_family_enum,
return result; return result;
} }
void MaybeUnlocalizeFontName(std::string* font_name) {
#if defined(OS_WIN)
// Try to get the 'us-en' font name. If it is failing, use the first name
// available.
base::Optional<std::string> localized_font_name =
gfx::win::RetrieveLocalizedFontName(*font_name, "us-en");
if (!localized_font_name)
localized_font_name = gfx::win::RetrieveLocalizedFontName(*font_name, "");
if (localized_font_name)
*font_name = std::move(localized_font_name.value());
#endif // defined(OS_WIN)
}
} // namespace } // namespace
FontSettingsEventRouter::FontSettingsEventRouter(Profile* profile) FontSettingsEventRouter::FontSettingsEventRouter(Profile* profile)
...@@ -144,7 +162,6 @@ void FontSettingsEventRouter::OnFontNamePrefChanged( ...@@ -144,7 +162,6 @@ void FontSettingsEventRouter::OnFontNamePrefChanged(
NOTREACHED(); NOTREACHED();
return; return;
} }
font_name = settings_utils::MaybeGetLocalizedFontName(font_name);
base::ListValue args; base::ListValue args;
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
...@@ -230,7 +247,11 @@ ExtensionFunction::ResponseAction FontSettingsGetFontFunction::Run() { ...@@ -230,7 +247,11 @@ ExtensionFunction::ResponseAction FontSettingsGetFontFunction::Run() {
std::string font_name; std::string font_name;
EXTENSION_FUNCTION_VALIDATE( EXTENSION_FUNCTION_VALIDATE(
pref && pref->GetValue()->GetAsString(&font_name)); pref && pref->GetValue()->GetAsString(&font_name));
font_name = settings_utils::MaybeGetLocalizedFontName(font_name);
// Legacy code was using the localized font name for fontId. These values may
// have been stored in prefs. For backward compatibility, we are converting
// the font name to the unlocalized name.
MaybeUnlocalizeFontName(&font_name);
// We don't support incognito-specific font prefs, so don't consider them when // We don't support incognito-specific font prefs, so don't consider them when
// getting level of control. // getting level of control.
......
...@@ -48,12 +48,6 @@ void ValidateSavedFonts(PrefService* prefs); ...@@ -48,12 +48,6 @@ void ValidateSavedFonts(PrefService* prefs);
// fallback is handled in CSS. // fallback is handled in CSS.
std::string ResolveFontList(const std::string& font_name_or_list); std::string ResolveFontList(const std::string& font_name_or_list);
// Returns the localized name of a font so that settings can find it within
// the list of system fonts. On Windows, the list of system fonts has names
// only for the system locale, but the pref value may be in the English name.
// For example, "MS Gothic" becomes "MS ゴシック" on localized Windows.
std::string MaybeGetLocalizedFontName(const std::string& font_name_or_list);
} // namespace settings_utils } // namespace settings_utils
#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_UTILS_H_ #endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_UTILS_H_
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "chrome/browser/ui/cryptuiapi_shim.h" #include "chrome/browser/ui/cryptuiapi_shim.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "ui/gfx/font.h" #include "ui/gfx/font.h"
#include "ui/gfx/platform_font_win.h"
#include "ui/shell_dialogs/base_shell_dialog_win.h" #include "ui/shell_dialogs/base_shell_dialog_win.h"
#include "ui/views/win/hwnd_util.h" #include "ui/views/win/hwnd_util.h"
...@@ -115,13 +114,4 @@ void ShowManageSSLCertificates(content::WebContents* web_contents) { ...@@ -115,13 +114,4 @@ void ShowManageSSLCertificates(content::WebContents* web_contents) {
base::Bind(&base::DeletePointer<ManageCertificatesDialog>, dialog)); base::Bind(&base::DeletePointer<ManageCertificatesDialog>, dialog));
} }
std::string MaybeGetLocalizedFontName(const std::string& font_name_or_list) {
std::string font_name = ResolveFontList(font_name_or_list);
if (font_name.empty())
return font_name;
gfx::Font font(font_name, 12); // dummy font size
return static_cast<gfx::PlatformFontWin*>(font.platform_font())
->GetLocalizedFontName();
}
} // namespace settings_utils } // namespace settings_utils
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "content/common/content_export.h"
namespace base { namespace base {
class ListValue; class ListValue;
...@@ -18,7 +19,7 @@ namespace content { ...@@ -18,7 +19,7 @@ namespace content {
// GetFontList_SlowBlocking() must only be called from the SequencedTaskRunner // GetFontList_SlowBlocking() must only be called from the SequencedTaskRunner
// returned by this function because it is non-threadsafe on Linux for versions // returned by this function because it is non-threadsafe on Linux for versions
// of Pango predating 2013. // of Pango predating 2013.
scoped_refptr<base::SequencedTaskRunner> GetFontListTaskRunner(); CONTENT_EXPORT scoped_refptr<base::SequencedTaskRunner> GetFontListTaskRunner();
// Retrieves the fonts available on the current platform and returns them. // Retrieves the fonts available on the current platform and returns them.
// The caller will own the returned pointer. Each entry will be a list of // The caller will own the returned pointer. Each entry will be a list of
...@@ -29,7 +30,7 @@ scoped_refptr<base::SequencedTaskRunner> GetFontListTaskRunner(); ...@@ -29,7 +30,7 @@ scoped_refptr<base::SequencedTaskRunner> GetFontListTaskRunner();
// GetFontListTaskRunner(). Most callers will want to use the GetFontListAsync // GetFontListTaskRunner(). Most callers will want to use the GetFontListAsync
// function in content/browser/font_list_async.h which does an asynchronous // function in content/browser/font_list_async.h which does an asynchronous
// call. // call.
std::unique_ptr<base::ListValue> GetFontList_SlowBlocking(); CONTENT_EXPORT std::unique_ptr<base::ListValue> GetFontList_SlowBlocking();
} // namespace content } // namespace content
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/common/font_list.h"
#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_piece.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/values.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
bool HasFontWithName(const base::ListValue& list,
base::StringPiece expected_font_id,
base::StringPiece expected_display_name) {
for (const auto& font : list.GetList()) {
const auto& font_names = font.GetList();
std::string font_id = font_names[0].GetString();
std::string display_name = font_names[1].GetString();
if (font_id == expected_font_id && display_name == expected_display_name)
return true;
}
return false;
}
#endif // !defined(OS_ANDROID) && !defined(OS_FUCHSI
} // namespace
#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
// GetFontList is not implemented on Android and Fuchsia.
TEST(FontList, GetFontList) {
base::test::ScopedTaskEnvironment scoped_task_environment;
content::GetFontListTaskRunner()->PostTask(
FROM_HERE, base::BindOnce([] {
std::unique_ptr<base::ListValue> fonts =
content::GetFontList_SlowBlocking();
ASSERT_TRUE(fonts);
#if defined(OS_WIN)
EXPECT_TRUE(HasFontWithName(*fonts, "MS Gothic", "MS Gothic"));
EXPECT_TRUE(HasFontWithName(*fonts, "Segoe UI", "Segoe UI"));
EXPECT_TRUE(HasFontWithName(*fonts, "Verdana", "Verdana"));
#elif defined(OS_LINUX)
EXPECT_TRUE(HasFontWithName(*fonts, "Arimo", "Arimo"));
#else
EXPECT_TRUE(HasFontWithName(*fonts, "Arial", "Arial"));
#endif
}));
scoped_task_environment.RunUntilIdle();
}
#endif // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
#if defined(OS_WIN)
TEST(FontList, GetFontListLocalized) {
base::i18n::SetICUDefaultLocale("ja-JP");
std::unique_ptr<base::ListValue> ja_fonts =
content::GetFontList_SlowBlocking();
ASSERT_TRUE(ja_fonts);
EXPECT_TRUE(HasFontWithName(*ja_fonts, "MS Gothic", "MS ゴシック"));
base::i18n::SetICUDefaultLocale("ko-KR");
std::unique_ptr<base::ListValue> ko_fonts =
content::GetFontList_SlowBlocking();
ASSERT_TRUE(ko_fonts);
EXPECT_TRUE(HasFontWithName(*ko_fonts, "Malgun Gothic", "맑은 고딕"));
}
#endif // defined(OS_WIN)
...@@ -4,55 +4,67 @@ ...@@ -4,55 +4,67 @@
#include "content/common/font_list.h" #include "content/common/font_list.h"
#include <dwrite.h>
#include <windows.h> #include <windows.h>
#include <string.h> #include <wrl/client.h>
#include <set>
#include <utility>
#include "base/i18n/rtl.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "base/values.h" #include "base/values.h"
#include "ui/gfx/win/direct_write.h"
namespace content { namespace content {
static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW* logical_font,
NEWTEXTMETRICEXW* physical_font,
DWORD font_type,
LPARAM lparam) {
std::set<base::string16>* font_names =
reinterpret_cast<std::set<base::string16>*>(lparam);
if (font_names) {
const LOGFONTW& lf = logical_font->elfLogFont;
if (lf.lfFaceName[0] && lf.lfFaceName[0] != '@') {
base::string16 face_name(lf.lfFaceName);
font_names->insert(face_name);
}
}
return 1;
}
std::unique_ptr<base::ListValue> GetFontList_SlowBlocking() { std::unique_ptr<base::ListValue> GetFontList_SlowBlocking() {
TRACE_EVENT0("fonts", "GetFontList_SlowBlocking"); TRACE_EVENT0("fonts", "GetFontList_SlowBlocking");
std::set<base::string16> font_names;
LOGFONTW logfont; std::unique_ptr<base::ListValue> font_list(new base::ListValue);
memset(&logfont, 0, sizeof(logfont));
logfont.lfCharSet = DEFAULT_CHARSET; Microsoft::WRL::ComPtr<IDWriteFactory> factory;
gfx::win::CreateDWriteFactory(&factory);
if (!factory)
return font_list;
HDC hdc = ::GetDC(NULL); Microsoft::WRL::ComPtr<IDWriteFontCollection> collection;
::EnumFontFamiliesExW(hdc, &logfont, (FONTENUMPROCW)&EnumFontFamExProc, if (FAILED(factory->GetSystemFontCollection(&collection)))
(LPARAM)&font_names, 0); return font_list;
::ReleaseDC(NULL, hdc);
// Retrieve the localized font family name. If there is no localized name,
// used the native name instead.
std::string locale = base::i18n::GetConfiguredLocale();
const UINT32 family_count = collection->GetFontFamilyCount();
for (UINT32 family_index = 0; family_index < family_count; ++family_index) {
Microsoft::WRL::ComPtr<IDWriteFontFamily> font_family;
Microsoft::WRL::ComPtr<IDWriteLocalizedStrings> family_names;
if (FAILED(collection->GetFontFamily(family_index, &font_family)) ||
FAILED(font_family->GetFamilyNames(&family_names))) {
continue;
}
// Retrieve the native font family name. Try the "en-us" locale and if it's
// not present, used the first available localized name.
base::Optional<std::string> native_name =
gfx::win::RetrieveLocalizedString(family_names.Get(), "en-us");
if (!native_name) {
native_name = gfx::win::RetrieveLocalizedString(family_names.Get(), "");
if (!native_name)
continue;
}
base::Optional<std::string> localized_name =
gfx::win::RetrieveLocalizedString(family_names.Get(), locale);
if (!localized_name)
localized_name = native_name;
std::unique_ptr<base::ListValue> font_list(new base::ListValue);
std::set<base::string16>::iterator iter;
for (iter = font_names.begin(); iter != font_names.end(); ++iter) {
auto font_item = std::make_unique<base::ListValue>(); auto font_item = std::make_unique<base::ListValue>();
font_item->AppendString(*iter); font_item->AppendString(native_name.value());
font_item->AppendString(*iter); font_item->AppendString(localized_name.value());
font_list->Append(std::move(font_item)); font_list->Append(std::move(font_item));
} }
return font_list; return font_list;
} }
......
...@@ -1763,6 +1763,7 @@ test("content_unittests") { ...@@ -1763,6 +1763,7 @@ test("content_unittests") {
"../common/content_switches_internal_unittest.cc", "../common/content_switches_internal_unittest.cc",
"../common/cursors/webcursor_unittest.cc", "../common/cursors/webcursor_unittest.cc",
"../common/dom_storage/dom_storage_map_unittest.cc", "../common/dom_storage/dom_storage_map_unittest.cc",
"../common/font_list_unittest.cc",
"../common/input/actions_parser_unittest.cc", "../common/input/actions_parser_unittest.cc",
"../common/input/event_with_latency_info_unittest.cc", "../common/input/event_with_latency_info_unittest.cc",
"../common/input/gesture_event_stream_validator_unittest.cc", "../common/input/gesture_event_stream_validator_unittest.cc",
......
...@@ -780,6 +780,7 @@ test("gfx_unittests") { ...@@ -780,6 +780,7 @@ test("gfx_unittests") {
"path_win_unittest.cc", "path_win_unittest.cc",
"platform_font_win_unittest.cc", "platform_font_win_unittest.cc",
"system_fonts_win_unittest.cc", "system_fonts_win_unittest.cc",
"win/direct_write_unittest.cc",
"win/text_analysis_source_unittest.cc", "win/text_analysis_source_unittest.cc",
] ]
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_functions.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "skia/ext/fontmgr_default.h" #include "skia/ext/fontmgr_default.h"
...@@ -103,5 +105,68 @@ IDWriteFactory* GetDirectWriteFactory() { ...@@ -103,5 +105,68 @@ IDWriteFactory* GetDirectWriteFactory() {
return g_direct_write_factory; return g_direct_write_factory;
} }
base::Optional<std::string> RetrieveLocalizedString(
IDWriteLocalizedStrings* names,
const std::string& locale) {
base::string16 locale_wide = base::UTF8ToUTF16(locale);
// If locale is empty, index 0 will be used. Otherwise, the locale name must
// be found and must exist.
UINT32 index = 0;
BOOL exists = false;
if (!locale.empty() &&
(FAILED(names->FindLocaleName(locale_wide.c_str(), &index, &exists)) ||
!exists)) {
return base::nullopt;
}
// Get the string length.
UINT32 length = 0;
if (FAILED(names->GetStringLength(index, &length)))
return base::nullopt;
// The output buffer length needs to be one larger to receive the NUL
// character.
base::string16 buffer;
buffer.resize(length + 1);
if (FAILED(names->GetString(index, &buffer[0], buffer.size())))
return base::nullopt;
// Shrink the string to fit the actual length.
buffer.resize(length);
return base::UTF16ToUTF8(buffer);
}
base::Optional<std::string> RetrieveLocalizedFontName(
base::StringPiece font_name,
const std::string& locale) {
Microsoft::WRL::ComPtr<IDWriteFactory> factory;
CreateDWriteFactory(&factory);
Microsoft::WRL::ComPtr<IDWriteFontCollection> font_collection;
if (FAILED(factory->GetSystemFontCollection(&font_collection))) {
return base::nullopt;
}
UINT32 index = 0;
BOOL exists;
base::string16 font_name_wide = base::UTF8ToUTF16(font_name);
if (FAILED(font_collection->FindFamilyName(font_name_wide.c_str(), &index,
&exists)) ||
!exists) {
return base::nullopt;
}
Microsoft::WRL::ComPtr<IDWriteFontFamily> font_family;
Microsoft::WRL::ComPtr<IDWriteLocalizedStrings> family_names;
if (FAILED(font_collection->GetFontFamily(index, &font_family)) ||
FAILED(font_family->GetFamilyNames(&family_names))) {
return base::nullopt;
}
return RetrieveLocalizedString(family_names.Get(), locale);
}
} // namespace win } // namespace win
} // namespace gfx } // namespace gfx
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <dwrite.h> #include <dwrite.h>
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "ui/gfx/gfx_export.h" #include "ui/gfx/gfx_export.h"
namespace gfx { namespace gfx {
...@@ -20,6 +22,18 @@ GFX_EXPORT void CreateDWriteFactory(IDWriteFactory** factory); ...@@ -20,6 +22,18 @@ GFX_EXPORT void CreateDWriteFactory(IDWriteFactory** factory);
// Returns the global DirectWrite factory. // Returns the global DirectWrite factory.
GFX_EXPORT IDWriteFactory* GetDirectWriteFactory(); GFX_EXPORT IDWriteFactory* GetDirectWriteFactory();
// Retrieves the localized string for a given locale. If locale is empty,
// retrieves the first element of |names|.
GFX_EXPORT base::Optional<std::string> RetrieveLocalizedString(
IDWriteLocalizedStrings* names,
const std::string& locale);
// Retrieves the localized font name for a given locale. If locale is empty,
// retrieves the default native font name.
GFX_EXPORT base::Optional<std::string> RetrieveLocalizedFontName(
base::StringPiece font_name,
const std::string& locale);
} // namespace win } // namespace win
} // namespace gfx } // namespace gfx
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/win/direct_write.h"
#include "base/i18n/rtl.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(DirectWrite, RetrieveLocalizedFontName) {
// Retrieve the en-US localized names.
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("MS Gothic", "en-US"),
"MS Gothic");
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("Malgun Gothic", "en-US"),
"Malgun Gothic");
// Retrieve the localized names.
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("MS Gothic", "ja-JP"),
"MS ゴシック");
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("Malgun Gothic", "ko-KR"),
"맑은 고딕");
// Retrieve the default font name.
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("MS ゴシック", ""),
"MS Gothic");
EXPECT_EQ(gfx::win::RetrieveLocalizedFontName("맑은 고딕", ""),
"Malgun Gothic");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment