Commit c8dfb92a authored by Etienne Bergeron's avatar Etienne Bergeron Committed by Commit Bot

Remove the deprecated class PlatformFontWin

The PlatformFontWin is deprecated and was replaced
by the usage of PlatformFontSkia on Windows.

The feature PlatformFontSkiaOnWindows is activated by default.

This CL is removing the feature and the code.

Bug: 944227
Change-Id: I644321594b4ef6f33e29dfbc36d507d0c695a1ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1924979
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Reviewed-by: default avatarRobert Liao <robliao@chromium.org>
Reviewed-by: default avatarTrent Apted <tapted@chromium.org>
Cr-Commit-Position: refs/heads/master@{#722503}
parent 0e228573
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include "base/win/win_util.h" #include "base/win/win_util.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "ui/display/win/dpi.h" #include "ui/display/win/dpi.h"
#include "ui/gfx/platform_font_win.h"
#include "ui/gfx/system_fonts_win.h" #include "ui/gfx/system_fonts_win.h"
#endif #endif
...@@ -161,11 +160,7 @@ TEST_F(LayoutProviderTest, MAYBE_LegacyFontSizeConstants) { ...@@ -161,11 +160,7 @@ TEST_F(LayoutProviderTest, MAYBE_LegacyFontSizeConstants) {
#endif #endif
#if defined(OS_WIN) #if defined(OS_WIN)
if (base::FeatureList::IsEnabled(gfx::kPlatformFontSkiaOnWindows)) { EXPECT_EQ(7, title_font.GetExpectedTextWidth(1));
EXPECT_EQ(7, title_font.GetExpectedTextWidth(1));
} else {
EXPECT_EQ(8, title_font.GetExpectedTextWidth(1));
}
#else #else
EXPECT_EQ(8, title_font.GetExpectedTextWidth(1)); EXPECT_EQ(8, title_font.GetExpectedTextWidth(1));
#endif #endif
......
...@@ -196,8 +196,6 @@ jumbo_component("gfx") { ...@@ -196,8 +196,6 @@ jumbo_component("gfx") {
"font_render_params_win.cc", "font_render_params_win.cc",
"path_win.cc", "path_win.cc",
"path_win.h", "path_win.h",
"platform_font_win.cc",
"platform_font_win.h",
"system_fonts_win.cc", "system_fonts_win.cc",
"system_fonts_win.h", "system_fonts_win.h",
"win/crash_id_helper.cc", "win/crash_id_helper.cc",
...@@ -787,10 +785,7 @@ test("gfx_unittests") { ...@@ -787,10 +785,7 @@ test("gfx_unittests") {
} }
if (is_win) { if (is_win) {
sources += [ sources += [ "system_fonts_win_unittest.cc" ]
"platform_font_win_unittest.cc",
"system_fonts_win_unittest.cc",
]
} }
if (is_linux || is_android || is_fuchsia || is_win) { if (is_linux || is_android || is_fuchsia || is_win) {
......
...@@ -43,11 +43,9 @@ class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { ...@@ -43,11 +43,9 @@ class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> {
// Creates a PlatformFont instance from the provided SkTypeface, ideally by // Creates a PlatformFont instance from the provided SkTypeface, ideally by
// just wrapping it without triggering a new font match. Implemented for // just wrapping it without triggering a new font match. Implemented for
// PlatformFontWin and PlatformFontSkia, where only the latter provides true // PlatformFontSkia which provides true wrapping of the provided SkTypeface.
// wrapping of the provided SkTypeface, while PlatformFontWin creates a // The FontRenderParams can be provided or they will be determined by using
// PlatformFont object by extracting the family name and falls back to // gfx::GetFontRenderParams(...) otherwise.
// CreateFromNameAndSize(). The FontRenderParams can be provided or they
// will be determined by using gfx::GetFontRenderParams(...) otherwise.
static PlatformFont* CreateFromSkTypeface( static PlatformFont* CreateFromSkTypeface(
sk_sp<SkTypeface> typeface, sk_sp<SkTypeface> typeface,
int font_size, int font_size,
......
...@@ -443,7 +443,6 @@ void PlatformFontSkia::ComputeMetricsIfNecessary() { ...@@ -443,7 +443,6 @@ void PlatformFontSkia::ComputeMetricsIfNecessary() {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// PlatformFont, public: // PlatformFont, public:
#if !defined(OS_WIN)
// static // static
PlatformFont* PlatformFont::CreateDefault() { PlatformFont* PlatformFont::CreateDefault() {
return new PlatformFontSkia; return new PlatformFontSkia;
...@@ -464,6 +463,5 @@ PlatformFont* PlatformFont::CreateFromSkTypeface( ...@@ -464,6 +463,5 @@ PlatformFont* PlatformFont::CreateFromSkTypeface(
TRACE_EVENT0("fonts", "PlatformFont::CreateFromSkTypeface"); TRACE_EVENT0("fonts", "PlatformFont::CreateFromSkTypeface");
return new PlatformFontSkia(typeface, font_size_pixels, params); return new PlatformFontSkia(typeface, font_size_pixels, params);
} }
#endif // !defined(OS_WIN)
} // namespace gfx } // namespace gfx
...@@ -121,6 +121,17 @@ TEST_F(PlatformFontSkiaTest, DefaultFont) { ...@@ -121,6 +121,17 @@ TEST_F(PlatformFontSkiaTest, DefaultFont) {
EXPECT_EQ(gfx::Font::Weight::BOLD, font2->GetWeight()); EXPECT_EQ(gfx::Font::Weight::BOLD, font2->GetWeight());
} }
TEST(PlatformFontSkiaRenderParamsTest, DefaultFontRenderParams) {
scoped_refptr<PlatformFontSkia> default_font(new PlatformFontSkia());
scoped_refptr<PlatformFontSkia> named_font(new PlatformFontSkia(
default_font->GetFontName(), default_font->GetFontSize()));
// Ensures that both constructors are producing fonts with the same render
// params.
EXPECT_EQ(default_font->GetFontRenderParams(),
named_font->GetFontRenderParams());
}
#if defined(OS_WIN) #if defined(OS_WIN)
TEST(PlatformFontSkiaOnWindowsTest, SystemFont) { TEST(PlatformFontSkiaOnWindowsTest, SystemFont) {
// Ensures that the font styles are kept while creating the default font. // Ensures that the font styles are kept while creating the default font.
......
// Copyright (c) 2012 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/platform_font_win.h"
#include <dwrite.h>
#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <wchar.h>
#include <windows.h>
#include <wrl/client.h>
#include <algorithm>
#include <utility>
#include "base/containers/flat_map.h"
#include "base/debug/alias.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
#include "third_party/skia/include/core/SkFontLCDConfig.h"
#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/platform_font_skia.h"
#include "ui/gfx/system_fonts_win.h"
#include "ui/gfx/win/direct_write.h"
#include "ui/gfx/win/scoped_set_map_mode.h"
namespace {
// Sets style properties on |font_info| based on |font_style|.
void SetLogFontStyle(int font_style, LOGFONT* font_info) {
font_info->lfUnderline = (font_style & gfx::Font::UNDERLINE) != 0;
font_info->lfItalic = (font_style & gfx::Font::ITALIC) != 0;
}
gfx::Font::Weight ToGfxFontWeight(int weight) {
return static_cast<gfx::Font::Weight>(weight);
}
// Uses the GDI interop functionality exposed by DirectWrite to find a
// matching DirectWrite font for the LOGFONT passed in. If we fail to
// find a direct match then we try the DirectWrite font substitution
// route to find a match.
// The contents of the LOGFONT pointer |font_info| may be modified on
// return.
HRESULT FindDirectWriteFontForLOGFONT(IDWriteFactory* factory,
LOGFONT* font_info,
IDWriteFont** dwrite_font) {
TRACE_EVENT0("fonts", "gfx::FindDirectWriteFontForLOGFONT");
Microsoft::WRL::ComPtr<IDWriteGdiInterop> gdi_interop;
HRESULT hr = factory->GetGdiInterop(gdi_interop.GetAddressOf());
if (FAILED(hr)) {
CHECK(false);
return hr;
}
hr = gdi_interop->CreateFontFromLOGFONT(font_info, dwrite_font);
if (SUCCEEDED(hr))
return hr;
Microsoft::WRL::ComPtr<IDWriteFontCollection> font_collection;
hr = factory->GetSystemFontCollection(font_collection.GetAddressOf());
if (FAILED(hr))
return hr;
// We try to find a matching font by triggering DirectWrite to substitute the
// font passed in with a matching font (FontSubstitutes registry key)
// If this succeeds we return the matched font.
base::win::ScopedGDIObject<HFONT> font(::CreateFontIndirect(font_info));
base::win::ScopedGetDC screen_dc(NULL);
base::win::ScopedSelectObject scoped_font(screen_dc, font.get());
Microsoft::WRL::ComPtr<IDWriteFontFace> font_face;
hr = gdi_interop->CreateFontFaceFromHdc(screen_dc, font_face.GetAddressOf());
if (FAILED(hr))
return hr;
LOGFONT converted_font = {0};
hr = gdi_interop->ConvertFontFaceToLOGFONT(font_face.Get(), &converted_font);
if (SUCCEEDED(hr)) {
hr = font_collection->GetFontFromFontFace(font_face.Get(), dwrite_font);
if (SUCCEEDED(hr)) {
wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
converted_font.lfFaceName);
}
}
return hr;
}
// Returns a matching IDWriteFont for the |font_info| passed in. If we fail
// to find a matching font, then we return the IDWriteFont corresponding to
// the default font on the system.
// Returns S_OK on success.
// The contents of the LOGFONT pointer |font_info| may be modified on
// return.
HRESULT GetMatchingDirectWriteFont(LOGFONT* font_info,
bool italic,
IDWriteFactory* factory,
IDWriteFont** dwrite_font) {
TRACE_EVENT0("fonts", "gfx::GetMatchingDirectWriteFont");
// First try the GDI compat route to get a matching DirectWrite font.
// If that succeeds then we are good. If that fails then try and find a
// match from the DirectWrite font collection.
HRESULT hr = FindDirectWriteFontForLOGFONT(factory, font_info, dwrite_font);
if (SUCCEEDED(hr))
return hr;
// Get a matching font from the system font collection exposed by
// DirectWrite.
Microsoft::WRL::ComPtr<IDWriteFontCollection> font_collection;
hr = factory->GetSystemFontCollection(font_collection.GetAddressOf());
if (FAILED(hr)) {
// On some old windows, the call to GetSystemFontCollection may fail.
return hr;
}
// Steps as below:-
// This mirrors skia.
// 1. Attempt to find a DirectWrite font family based on the face name in the
// font. That may not work at all times, as the face name could be random
// GDI has its own font system where in it creates a font matching the
// characteristics in the LOGFONT structure passed into
// CreateFontIndirect. DirectWrite does not do that. If this succeeds then
// return the matching IDWriteFont from the family.
// 2. If step 1 fails then repeat with the default system font. This has the
// same limitations with the face name as mentioned above.
// 3. If step 2 fails then return the first family from the collection and
// use that.
Microsoft::WRL::ComPtr<IDWriteFontFamily> font_family;
BOOL exists = FALSE;
uint32_t index = 0;
hr = font_collection->FindFamilyName(font_info->lfFaceName, &index, &exists);
// If we fail to find a match then try fallback to the default font on the
// system. This is what skia does as well.
if (FAILED(hr) || (index == UINT_MAX) || !exists) {
NONCLIENTMETRICS metrics = {0};
metrics.cbSize = sizeof(metrics);
if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
sizeof(metrics),
&metrics,
0)) {
CHECK(false);
return E_FAIL;
}
if (wcsncmp(font_info->lfFaceName, metrics.lfMessageFont.lfFaceName,
base::size(font_info->lfFaceName))) {
// First try the GDI compat route to get a matching DirectWrite font. If
// that succeeds we are good. If not find a matching font from the font
// collection.
wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
metrics.lfMessageFont.lfFaceName);
hr = FindDirectWriteFontForLOGFONT(factory, font_info, dwrite_font);
if (SUCCEEDED(hr))
return hr;
// Best effort to find a matching font from the system font collection.
hr = font_collection->FindFamilyName(metrics.lfMessageFont.lfFaceName,
&index,
&exists);
}
}
if (index != UINT_MAX && exists) {
hr = font_collection->GetFontFamily(index, font_family.GetAddressOf());
} else {
// If we fail to find a matching font, then fallback to the first font in
// the list. This is what skia does as well.
hr = font_collection->GetFontFamily(0, font_family.GetAddressOf());
}
if (FAILED(hr)) {
CHECK(false);
return hr;
}
DWRITE_FONT_WEIGHT weight =
static_cast<DWRITE_FONT_WEIGHT>(font_info->lfWeight);
DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;
DWRITE_FONT_STYLE style =
(italic) ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
// The IDWriteFontFamily::GetFirstMatchingFont call fails on certain machines
// for fonts like MS UI Gothic, Segoe UI, etc. It is not clear why these
// fonts could be accessible to GDI and not to DirectWrite.
// The code below adds some debug fields to help track down these failures.
// 1. We get the matching font list for the font attributes passed in.
// 2. We get the font count in the family with a debug alias variable.
// 3. If GetFirstMatchingFont fails then we CHECK as before.
// Next step would be to remove the CHECKs in this function and fallback to
// GDI.
// http://crbug.com/434425
// TODO(ananta)
// Remove the GetMatchingFonts and related code here once we get to a stable
// state in canary.
Microsoft::WRL::ComPtr<IDWriteFontList> matching_font_list;
hr = font_family->GetMatchingFonts(weight, stretch, style,
matching_font_list.GetAddressOf());
uint32_t matching_font_count = 0;
if (SUCCEEDED(hr))
matching_font_count = matching_font_list->GetFontCount();
hr = font_family->GetFirstMatchingFont(weight, stretch, style, dwrite_font);
if (FAILED(hr)) {
base::debug::Alias(&matching_font_count);
CHECK(false);
}
base::string16 font_name;
gfx::GetFamilyNameFromDirectWriteFont(*dwrite_font, &font_name);
wcscpy_s(font_info->lfFaceName, base::size(font_info->lfFaceName),
font_name.c_str());
return hr;
}
} // namespace
namespace gfx {
// Enable the use of PlatformFontSkia instead of PlatformFontWin.
const base::Feature kPlatformFontSkiaOnWindows{
"PlatformFontSkiaOnWindows", base::FEATURE_ENABLED_BY_DEFAULT};
// static
PlatformFontWin::HFontRef* PlatformFontWin::base_font_ref_;
// TODO(ananta)
// Remove the CHECKs in this function once this stabilizes on the field.
HRESULT GetFamilyNameFromDirectWriteFont(IDWriteFont* dwrite_font,
base::string16* family_name) {
Microsoft::WRL::ComPtr<IDWriteFontFamily> font_family;
HRESULT hr = dwrite_font->GetFontFamily(font_family.GetAddressOf());
if (FAILED(hr))
CHECK(false);
Microsoft::WRL::ComPtr<IDWriteLocalizedStrings> family_names;
hr = font_family->GetFamilyNames(family_names.GetAddressOf());
if (FAILED(hr))
CHECK(false);
// TODO(ananta)
// Add support for retrieving the family for the current locale.
wchar_t family_name_for_locale[MAX_PATH] = {0};
hr = family_names->GetString(0, family_name_for_locale,
base::size(family_name_for_locale));
if (FAILED(hr))
CHECK(false);
*family_name = family_name_for_locale;
return hr;
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontWin, public
PlatformFontWin::PlatformFontWin() : font_ref_(GetBaseFontRef()) {
}
PlatformFontWin::PlatformFontWin(const std::string& font_name, int font_size) {
InitWithFontNameAndSize(font_name, font_size);
}
PlatformFontWin::PlatformFontWin(sk_sp<SkTypeface> typeface,
int font_size_pixels,
const base::Optional<FontRenderParams>& params)
: typeface_(std::move(typeface)) {
DCHECK(typeface_);
// TODO(http://crbug.com/944227): This is a transitional code path until we
// complete migrating to PlatformFontSkia on Windows. Being unable to wrap the
// SkTypeface into a PlatformFontSkia and performing a rematching by font
// family name instead loses platform font handles encapsulated in SkTypeface,
// and in turn leads to instantiating a different font than what was returned
// by font fallback, compare https://crbug.com/1003829.
SkString family_name;
typeface_->getFamilyName(&family_name);
InitWithFontNameAndSize(family_name.c_str(), font_size_pixels);
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontWin, PlatformFont implementation:
Font PlatformFontWin::DeriveFont(int size_delta,
int style,
Font::Weight weight) const {
LOGFONT font_info;
GetObject(GetNativeFont(), sizeof(LOGFONT), &font_info);
const int requested_font_size = font_ref_->requested_font_size();
font_info.lfHeight = win::AdjustFontSize(-requested_font_size, size_delta);
font_info.lfWeight = static_cast<LONG>(weight);
SetLogFontStyle(style, &font_info);
HFONT hfont = CreateFontIndirect(&font_info);
return Font(new PlatformFontWin(CreateHFontRef(hfont)));
}
int PlatformFontWin::GetHeight() {
return font_ref_->height();
}
Font::Weight PlatformFontWin::GetWeight() const {
return font_ref_->weight();
}
int PlatformFontWin::GetBaseline() {
return font_ref_->baseline();
}
int PlatformFontWin::GetCapHeight() {
return font_ref_->cap_height();
}
int PlatformFontWin::GetExpectedTextWidth(int length) {
return length * std::min(font_ref_->GetDluBaseX(),
font_ref_->ave_char_width());
}
int PlatformFontWin::GetStyle() const {
return font_ref_->style();
}
const std::string& PlatformFontWin::GetFontName() const {
return font_ref_->font_name();
}
std::string PlatformFontWin::GetActualFontName() const {
// With the current implementation on Windows, HFontRef::font_name() returns
// the font name taken from the HFONT handle, but it's not the name that comes
// from the font's metadata. See http://crbug.com/327287
return font_ref_->font_name();
}
std::string PlatformFontWin::GetLocalizedFontName() const {
base::win::ScopedCreateDC memory_dc(CreateCompatibleDC(NULL));
if (!memory_dc.Get())
return GetFontName();
// When a font has a localized name for a language matching the system
// locale, GetTextFace() returns the localized name.
base::win::ScopedSelectObject font(memory_dc.Get(), font_ref_->hfont());
wchar_t localized_font_name[LF_FACESIZE];
int length = GetTextFace(memory_dc.Get(), base::size(localized_font_name),
&localized_font_name[0]);
if (length <= 0)
return GetFontName();
return base::SysWideToUTF8(localized_font_name);
}
int PlatformFontWin::GetFontSize() const {
return font_ref_->font_size();
}
const FontRenderParams& PlatformFontWin::GetFontRenderParams() {
static const base::NoDestructor<FontRenderParams> params(
gfx::GetFontRenderParams(FontRenderParamsQuery(), nullptr));
return *params;
}
sk_sp<SkTypeface> PlatformFontWin::GetNativeSkTypefaceIfAvailable() const {
return sk_sp<SkTypeface>(typeface_);
}
NativeFont PlatformFontWin::GetNativeFont() const {
return font_ref_->hfont();
}
////////////////////////////////////////////////////////////////////////////////
// Font, private:
void PlatformFontWin::InitWithCopyOfHFONT(HFONT hfont) {
DCHECK(hfont);
LOGFONT font_info;
GetObject(hfont, sizeof(LOGFONT), &font_info);
font_ref_ = CreateHFontRef(CreateFontIndirect(&font_info));
}
void PlatformFontWin::InitWithFontNameAndSize(const std::string& font_name,
int font_size) {
HFONT hf = ::CreateFont(-font_size, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
base::UTF8ToUTF16(font_name).c_str());
font_ref_ = CreateHFontRef(hf);
}
// static
void PlatformFontWin::GetTextMetricsForFont(HDC hdc,
HFONT font,
TEXTMETRIC* text_metrics) {
base::win::ScopedSelectObject scoped_font(hdc, font);
GetTextMetrics(hdc, text_metrics);
}
// static
PlatformFontWin::HFontRef* PlatformFontWin::GetBaseFontRef() {
if (base_font_ref_ == nullptr) {
// We'll delegate to our SystemFonts instance to give us the default
// message font.
PlatformFontWin* message_font = static_cast<PlatformFontWin*>(
win::GetSystemFont(win::SystemFont::kMessage).platform_font());
base_font_ref_ = message_font->font_ref_.get();
}
return base_font_ref_;
}
PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRef(HFONT font) {
TRACE_EVENT0("fonts", "PlatformFont::CreateHFontRef");
TEXTMETRIC font_metrics;
{
base::win::ScopedGetDC screen_dc(NULL);
ScopedSetMapMode mode(screen_dc, MM_TEXT);
GetTextMetricsForFont(screen_dc, font, &font_metrics);
}
return CreateHFontRefFromSkia(font, font_metrics);
}
PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRefFromGDI(
HFONT font,
const TEXTMETRIC& font_metrics) {
TRACE_EVENT0("fonts", "PlatformFontWin::CreateHFontRefFromGDI");
const int height = std::max<int>(1, font_metrics.tmHeight);
const int baseline = std::max<int>(1, font_metrics.tmAscent);
const int cap_height =
std::max<int>(1, font_metrics.tmAscent - font_metrics.tmInternalLeading);
const int ave_char_width = std::max<int>(1, font_metrics.tmAveCharWidth);
const int font_size =
std::max<int>(1, font_metrics.tmHeight - font_metrics.tmInternalLeading);
int style = 0;
if (font_metrics.tmItalic)
style |= Font::ITALIC;
if (font_metrics.tmUnderlined)
style |= Font::UNDERLINE;
return new HFontRef(font, font_size, height, baseline, cap_height,
ave_char_width, ToGfxFontWeight(font_metrics.tmWeight),
style);
}
// static
PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRefFromSkia(
HFONT gdi_font,
const TEXTMETRIC& font_metrics) {
TRACE_EVENT0("fonts", "PlatformFontWin::CreateHFontRefFromSkia");
LOGFONT font_info = {0};
GetObject(gdi_font, sizeof(LOGFONT), &font_info);
// If the font height is passed in as 0, assume the height to be -1 to ensure
// that we return the metrics for a 1 point font.
// If the font height is positive it represents the rasterized font's cell
// height. Calculate the actual height accordingly.
if (font_info.lfHeight > 0) {
font_info.lfHeight =
font_metrics.tmInternalLeading - font_metrics.tmHeight;
} else if (font_info.lfHeight == 0) {
font_info.lfHeight = -1;
}
if (font_info.lfWeight == 0) {
font_info.lfWeight = static_cast<LONG>(Font::Weight::NORMAL);
}
const bool italic = font_info.lfItalic != 0;
// Skia does not return all values we need for font metrics. For e.g.
// the cap height which indicates the height of capital letters is not
// returned even though it is returned by DirectWrite.
// TODO(ananta)
// Fix SkScalerContext_win_dw.cpp to return all metrics we need from
// DirectWrite and remove the code here which retrieves metrics from
// DirectWrite to calculate the cap height.
Microsoft::WRL::ComPtr<IDWriteFont> dwrite_font;
HRESULT hr = GetMatchingDirectWriteFont(
&font_info, italic, win::GetDirectWriteFactory(), &dwrite_font);
if (FAILED(hr)) {
// If we are not able to find a font using Direct Write, fallback to
// the old GDI font.
return CreateHFontRefFromGDI(gdi_font, font_metrics);
}
DWRITE_FONT_METRICS dwrite_font_metrics = {0};
dwrite_font->GetMetrics(&dwrite_font_metrics);
SkFontStyle skia_font_style(font_info.lfWeight, SkFontStyle::kNormal_Width,
font_info.lfItalic ? SkFontStyle::kItalic_Slant
: SkFontStyle::kUpright_Slant);
sk_sp<SkTypeface> skia_face(
SkTypeface::MakeFromName(
base::SysWideToUTF8(font_info.lfFaceName).c_str(),
skia_font_style));
FontRenderParams font_params =
gfx::GetFontRenderParams(FontRenderParamsQuery(), nullptr);
SkFontLCDConfig::SetSubpixelOrder(
FontRenderParams::SubpixelRenderingToSkiaLCDOrder(
font_params.subpixel_rendering));
SkFontLCDConfig::SetSubpixelOrientation(
FontRenderParams::SubpixelRenderingToSkiaLCDOrientation(
font_params.subpixel_rendering));
SkFont font(std::move(skia_face), -font_info.lfHeight);
font.setEdging(font_params.antialiasing ? SkFont::Edging::kAntiAlias
: SkFont::Edging::kAlias);
SkFontMetrics skia_metrics;
font.getMetrics(&skia_metrics);
// The calculations below are similar to those in the CreateHFontRef
// function. The height, baseline and cap height are rounded up to ensure
// that they match up closely with GDI.
const int height = std::ceil(skia_metrics.fDescent - skia_metrics.fAscent);
const int baseline = std::max<int>(1, std::ceil(-skia_metrics.fAscent));
const int cap_height = std::ceil(
font.getSize() * static_cast<double>(dwrite_font_metrics.capHeight) /
dwrite_font_metrics.designUnitsPerEm);
// The metrics retrieved from skia don't have the average character width. In
// any case if we get the average character width from skia then use that or
// the average character width in the TEXTMETRIC structure.
// TODO(ananta): Investigate whether it is possible to retrieve this value
// from DirectWrite.
const int ave_char_width =
skia_metrics.fAvgCharWidth == 0 ? font_metrics.tmAveCharWidth
: skia_metrics.fAvgCharWidth;
int style = 0;
if (italic)
style |= Font::ITALIC;
if (font_info.lfUnderline)
style |= Font::UNDERLINE;
// DirectWrite may have substituted the GDI font name with a fallback
// font. Ensure that it is updated here.
DeleteObject(gdi_font);
gdi_font = ::CreateFontIndirect(&font_info);
return new HFontRef(gdi_font, -font_info.lfHeight, height, baseline,
cap_height, ave_char_width,
ToGfxFontWeight(font_info.lfWeight), style);
}
// static
Font PlatformFontWin::HFontToFont(HFONT hfont) {
return Font(new PlatformFontWin(CreateHFontRef(hfont)));
}
PlatformFontWin::PlatformFontWin(HFontRef* hfont_ref) : font_ref_(hfont_ref) {
}
PlatformFontWin::PlatformFontWin(NativeFont native_font) {
InitWithCopyOfHFONT(native_font);
}
PlatformFontWin::~PlatformFontWin() {
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontWin::HFontRef:
PlatformFontWin::HFontRef::HFontRef(HFONT hfont,
int font_size,
int height,
int baseline,
int cap_height,
int ave_char_width,
Font::Weight weight,
int style)
: hfont_(hfont),
font_size_(font_size),
height_(height),
baseline_(baseline),
cap_height_(cap_height),
ave_char_width_(ave_char_width),
weight_(weight),
style_(style),
dlu_base_x_(-1),
requested_font_size_(font_size) {
DLOG_ASSERT(hfont);
LOGFONT font_info;
GetObject(hfont_, sizeof(LOGFONT), &font_info);
font_name_ = base::UTF16ToUTF8(base::string16(font_info.lfFaceName));
// Retrieve the font size from the GetTextMetrics API instead of referencing
// it from the LOGFONT structure. This is because the height as reported by
// the LOGFONT structure is not always correct. For small fonts with size 1
// the LOGFONT structure reports the height as -1, while the actual font size
// is different. (2 on my XP machine).
base::win::ScopedGetDC screen_dc(NULL);
TEXTMETRIC font_metrics = {0};
PlatformFontWin::GetTextMetricsForFont(screen_dc, hfont_, &font_metrics);
requested_font_size_ = font_metrics.tmHeight - font_metrics.tmInternalLeading;
}
int PlatformFontWin::HFontRef::GetDluBaseX() {
if (dlu_base_x_ != -1)
return dlu_base_x_;
dlu_base_x_ = GetAverageCharWidthInDialogUnits(hfont_);
return dlu_base_x_;
}
// static
int PlatformFontWin::HFontRef::GetAverageCharWidthInDialogUnits(
HFONT gdi_font) {
base::win::ScopedGetDC screen_dc(NULL);
base::win::ScopedSelectObject font(screen_dc, gdi_font);
ScopedSetMapMode mode(screen_dc, MM_TEXT);
// Yes, this is how Microsoft recommends calculating the dialog unit
// conversions. See: http://support.microsoft.com/kb/125681
SIZE ave_text_size;
GetTextExtentPoint32(screen_dc,
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
52, &ave_text_size);
int dlu_base_x = (ave_text_size.cx / 26 + 1) / 2;
DCHECK_NE(dlu_base_x, -1);
return dlu_base_x;
}
PlatformFontWin::HFontRef::~HFontRef() {
DeleteObject(hfont_);
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFont, public:
// static
PlatformFont* PlatformFont::CreateDefault() {
if (base::FeatureList::IsEnabled(kPlatformFontSkiaOnWindows))
return new PlatformFontSkia;
return new PlatformFontWin;
}
// static
PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
int font_size) {
TRACE_EVENT0("fonts", "PlatformFont::CreateFromNameAndSize");
if (base::FeatureList::IsEnabled(kPlatformFontSkiaOnWindows))
return new PlatformFontSkia(font_name, font_size);
return new PlatformFontWin(font_name, font_size);
}
// static
PlatformFont* PlatformFont::CreateFromSkTypeface(
sk_sp<SkTypeface> typeface,
int font_size,
const base::Optional<FontRenderParams>& params) {
TRACE_EVENT0("fonts", "PlatformFont::CreateFromSkTypeface");
if (base::FeatureList::IsEnabled(kPlatformFontSkiaOnWindows))
return new PlatformFontSkia(typeface, font_size, params);
return new PlatformFontWin(typeface, font_size, params);
}
} // namespace gfx
// Copyright (c) 2012 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.
#ifndef UI_GFX_PLATFORM_FONT_WIN_H_
#define UI_GFX_PLATFORM_FONT_WIN_H_
#include <windows.h>
#include <string>
#include "base/compiler_specific.h"
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/platform_font.h"
struct IDWriteFactory;
struct IDWriteFont;
namespace gfx {
// Deprecation of PlatformFontWin (See http://crbug.com/944227).
extern GFX_EXPORT const base::Feature kPlatformFontSkiaOnWindows;
class GFX_EXPORT PlatformFontWin : public PlatformFont {
public:
PlatformFontWin();
PlatformFontWin(const std::string& font_name, int font_size);
// Wraps the provided SkTypeface without triggering a font rematch.
PlatformFontWin(sk_sp<SkTypeface> typeface,
int font_size_pixels,
const base::Optional<FontRenderParams>& params);
// Dialog units to pixels conversion.
// See http://support.microsoft.com/kb/145994 for details.
int horizontal_dlus_to_pixels(int dlus) const {
return dlus * font_ref_->GetDluBaseX() / 4;
}
int vertical_dlus_to_pixels(int dlus) const {
return dlus * font_ref_->height() / 8;
}
// Returns the font name for the system locale. Some fonts, particularly
// East Asian fonts, have different names per locale. If the localized font
// name could not be retrieved, returns GetFontName().
std::string GetLocalizedFontName() const;
// Overridden from PlatformFont:
Font DeriveFont(int size_delta,
int style,
Font::Weight weight) const override;
int GetHeight() override;
Font::Weight GetWeight() const override;
int GetBaseline() override;
int GetCapHeight() override;
int GetExpectedTextWidth(int length) override;
int GetStyle() const override;
const std::string& GetFontName() const override;
std::string GetActualFontName() const override;
int GetFontSize() const override;
const FontRenderParams& GetFontRenderParams() override;
sk_sp<SkTypeface> GetNativeSkTypefaceIfAvailable() const override;
NativeFont GetNativeFont() const;
// Called once during initialization if we should be retrieving font metrics
// from skia and DirectWrite.
static void SetDirectWriteFactory(IDWriteFactory* factory);
private:
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, Metrics_SkiaVersusGDI);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, DirectWriteFontSubstitution);
explicit PlatformFontWin(NativeFont native_font);
~PlatformFontWin() override;
// Chrome text drawing bottoms out in the Windows GDI functions that take an
// HFONT (an opaque handle into Windows). To avoid lots of GDI object
// allocation and destruction, Font indirectly refers to the HFONT by way of
// an HFontRef. That is, every Font has an HFontRef, which has an HFONT.
//
// HFontRef is reference counted. Upon deletion, it deletes the HFONT.
// By making HFontRef maintain the reference to the HFONT, multiple
// HFontRefs can share the same HFONT, and Font can provide value semantics.
class GFX_EXPORT HFontRef : public base::RefCounted<HFontRef> {
public:
// This constructor takes control of the HFONT, and will delete it when
// the HFontRef is deleted.
HFontRef(HFONT hfont,
int font_size,
int height,
int baseline,
int cap_height,
int ave_char_width,
Font::Weight weight,
int style);
// Accessors
HFONT hfont() const { return hfont_; }
int height() const { return height_; }
int baseline() const { return baseline_; }
int cap_height() const { return cap_height_; }
int ave_char_width() const { return ave_char_width_; }
Font::Weight weight() const { return weight_; }
int style() const { return style_; }
const std::string& font_name() const { return font_name_; }
int font_size() const { return font_size_; }
int requested_font_size() const { return requested_font_size_; }
// Returns the average character width in dialog units.
int GetDluBaseX();
// Helper to return the average character width using the text extent
// technique mentioned here. http://support.microsoft.com/kb/125681.
static int GetAverageCharWidthInDialogUnits(HFONT gdi_font);
private:
friend class base::RefCounted<HFontRef>;
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, Metrics_SkiaVersusGDI);
FRIEND_TEST_ALL_PREFIXES(PlatformFontWinTest, DirectWriteFontSubstitution);
~HFontRef();
const HFONT hfont_;
const int font_size_;
const int height_;
const int baseline_;
const int cap_height_;
const int ave_char_width_;
const Font::Weight weight_;
const int style_;
// Average character width in dialog units. This is queried lazily from the
// system, with an initial value of -1 meaning it hasn't yet been queried.
int dlu_base_x_;
std::string font_name_;
// If the requested font size is not possible for the font, |font_size_|
// will be different than |requested_font_size_|. This is stored separately
// so that code that increases the font size in a loop will not cause the
// loop to get stuck on the same size.
int requested_font_size_;
DISALLOW_COPY_AND_ASSIGN(HFontRef);
};
// Initializes this object with a copy of the specified HFONT.
void InitWithCopyOfHFONT(HFONT hfont);
// Initializes this object with the specified font name and size.
void InitWithFontNameAndSize(const std::string& font_name,
int font_size);
// Returns the GDI metrics for the font passed in.
static void GetTextMetricsForFont(HDC hdc,
HFONT font,
TEXTMETRIC* text_metrics);
// Returns the base font ref. This should ONLY be invoked on the
// UI thread.
static HFontRef* GetBaseFontRef();
// Creates and returns a new HFontRef from the specified HFONT.
static HFontRef* CreateHFontRef(HFONT font);
// Creates and returns a new HFontRef from the specified HFONT. Uses provided
// |font_metrics| instead of calculating new one.
static HFontRef* CreateHFontRefFromGDI(HFONT font,
const TEXTMETRIC& font_metrics);
// Creates and returns a new HFontRef from the specified HFONT using metrics
// from skia. Currently this is only used if we use DirectWrite for font
// metrics.
// |gdi_font| : Handle to the GDI font created via CreateFontIndirect.
// |font_metrics| : The GDI font metrics retrieved via the GetTextMetrics
// API. This is currently used to calculate the correct height of the font
// in case we get a font created with a positive height.
// A positive height represents the cell height (ascent + descent).
// A negative height represents the character Em height which is cell
// height minus the internal leading value.
static PlatformFontWin::HFontRef* CreateHFontRefFromSkia(
HFONT gdi_font,
const TEXTMETRIC& font_metrics);
// Takes control of a native font (e.g. from CreateFontIndirect()) and wraps
// it in a Font object to manage its lifespan. Note that |hfont| may not be
// valid after the call; use the returned Font object instead.
static Font HFontToFont(HFONT hfont);
// Creates a new PlatformFontWin with the specified HFontRef. Used when
// constructing a Font from a HFONT we don't want to copy.
explicit PlatformFontWin(HFontRef* hfont_ref);
// Reference to the base font all fonts are derived from.
static HFontRef* base_font_ref_;
// Indirect reference to the HFontRef, which references the underlying HFONT.
scoped_refptr<HFontRef> font_ref_;
// An optional typeface when the font is constructed from a typeface.
sk_sp<SkTypeface> typeface_;
DISALLOW_COPY_AND_ASSIGN(PlatformFontWin);
};
// Returns the family name for the |IDWriteFont| interface passed in.
// The family name is returned in the |family_name| parameter.
// Returns S_OK on success.
HRESULT GetFamilyNameFromDirectWriteFont(IDWriteFont* dwrite_font,
base::string16* family_name);
} // namespace gfx
#endif // UI_GFX_PLATFORM_FONT_WIN_H_
// Copyright (c) 2012 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/platform_font_win.h"
#include <memory.h>
#include <string.h>
#include <windows.h>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/platform_font_skia.h"
#include "ui/gfx/win/scoped_set_map_mode.h"
namespace gfx {
// Test whether font metrics retrieved by DirectWrite (skia) and GDI match as
// per assumptions mentioned below:-
// 1. Font size is the same
// 2. The difference between GDI and DirectWrite for font height, baseline,
// and cap height is at most 1. For smaller font sizes under 12, GDI
// font heights/baselines/cap height are equal/larger by 1 point. For larger
// font sizes DirectWrite font heights/baselines/cap height are equal/larger
// by 1 point.
TEST(PlatformFontWinTest, Metrics_SkiaVersusGDI) {
// Describes the font being tested.
struct FontInfo {
base::string16 font_name;
int font_size;
};
FontInfo fonts[] = {
{base::ASCIIToUTF16("Arial"), 6},
{base::ASCIIToUTF16("Arial"), 8},
{base::ASCIIToUTF16("Arial"), 10},
{base::ASCIIToUTF16("Arial"), 12},
{base::ASCIIToUTF16("Arial"), 16},
{base::ASCIIToUTF16("Symbol"), 6},
{base::ASCIIToUTF16("Symbol"), 10},
{base::ASCIIToUTF16("Symbol"), 12},
{base::ASCIIToUTF16("Tahoma"), 10},
{base::ASCIIToUTF16("Tahoma"), 16},
{base::ASCIIToUTF16("Segoe UI"), 6},
{base::ASCIIToUTF16("Segoe UI"), 8},
{base::ASCIIToUTF16("Segoe UI"), 20},
};
base::win::ScopedGetDC screen_dc(NULL);
gfx::ScopedSetMapMode mode(screen_dc, MM_TEXT);
for (const FontInfo& font : fonts) {
LOGFONT font_info = {0};
font_info.lfHeight = -font.font_size;
font_info.lfWeight = FW_NORMAL;
wcscpy_s(font_info.lfFaceName, font.font_name.length() + 1,
font.font_name.c_str());
HFONT hFont = CreateFontIndirect(&font_info);
TEXTMETRIC font_metrics;
PlatformFontWin::GetTextMetricsForFont(screen_dc, hFont, &font_metrics);
scoped_refptr<PlatformFontWin::HFontRef> h_font_gdi(
PlatformFontWin::CreateHFontRefFromGDI(hFont, font_metrics));
scoped_refptr<PlatformFontWin::HFontRef> h_font_skia(
PlatformFontWin::CreateHFontRefFromSkia(hFont, font_metrics));
EXPECT_EQ(h_font_gdi->font_size(), h_font_skia->font_size());
EXPECT_EQ(h_font_gdi->style(), h_font_skia->style());
EXPECT_EQ(h_font_gdi->font_name(), h_font_skia->font_name());
EXPECT_EQ(h_font_gdi->ave_char_width(), h_font_skia->ave_char_width());
EXPECT_LE(abs(h_font_gdi->cap_height() - h_font_skia->cap_height()), 1);
EXPECT_LE(abs(h_font_gdi->baseline() - h_font_skia->baseline()), 1);
EXPECT_LE(abs(h_font_gdi->height() - h_font_skia->height()), 1);
}
}
// Test if DirectWrite font fallback works correctly, i.e. whether DirectWrite
// fonts handle the font names in the
// HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes key
// correctly. The expectation is that the actual font created should be the
// one specified by the value for the substituted font. For e.g. MS Shell Dlg
// should create Microsoft Sans Serif, etc.
// For random fonts which are not substitutes, DirectWrite should fallback
// to Arial on a properly configured machine.
TEST(PlatformFontWinTest, DirectWriteFontSubstitution) {
// Describes the font being tested.
struct FontInfo {
base::string16 font_name;
std::string expected_font_name;
};
FontInfo fonts[] = {
{base::ASCIIToUTF16("MS Shell Dlg"), "Microsoft Sans Serif"},
{base::ASCIIToUTF16("MS Shell Dlg 2"), "Tahoma"},
{base::ASCIIToUTF16("FooBar"), "Arial"},
};
base::win::ScopedGetDC screen_dc(NULL);
gfx::ScopedSetMapMode mode(screen_dc, MM_TEXT);
for (const FontInfo& font : fonts) {
LOGFONT font_info = {0};
font_info.lfHeight = -10;
font_info.lfWeight = FW_NORMAL;
wcscpy_s(font_info.lfFaceName, font.font_name.length() + 1,
font.font_name.c_str());
HFONT hFont = CreateFontIndirect(&font_info);
TEXTMETRIC font_metrics;
PlatformFontWin::GetTextMetricsForFont(screen_dc, hFont, &font_metrics);
scoped_refptr<PlatformFontWin::HFontRef> h_font_skia(
PlatformFontWin::CreateHFontRefFromSkia(hFont, font_metrics));
EXPECT_EQ(font.expected_font_name, h_font_skia->font_name());
}
}
// TODO(etienneb): Move this test to platform_font_skia_unittest when the
// font migration to skia font is completed.
TEST(PlatformFontWinTest, DefaultFontRenderParams) {
scoped_refptr<PlatformFontSkia> default_font(new PlatformFontSkia());
scoped_refptr<PlatformFontSkia> named_font(new PlatformFontSkia(
default_font->GetFontName(), default_font->GetFontSize()));
// Ensures that both constructors are producing fonts with the same render
// params.
EXPECT_EQ(default_font->GetFontRenderParams(),
named_font->GetFontRenderParams());
}
TEST(PlatformFontWinTest, SkiaTypefaceConstructor) {
gfx::Font default_font;
// The PlatformFontWin constructor doesn't create a skia typeface.
if (!base::FeatureList::IsEnabled(kPlatformFontSkiaOnWindows)) {
EXPECT_EQ(default_font.platform_font()->GetNativeSkTypefaceIfAvailable(),
nullptr);
}
sk_sp<SkFontMgr> font_mgr = SkFontMgr::RefDefault();
sk_sp<SkTypeface> typeface(
font_mgr->matchFamilyStyle("Segoe UI", SkFontStyle()));
ASSERT_TRUE(typeface);
gfx::Font fallback_font(new PlatformFontWin(typeface, 13, base::nullopt));
EXPECT_EQ(fallback_font.platform_font()->GetNativeSkTypefaceIfAvailable(),
typeface);
}
} // namespace gfx
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