Commit e32cbb07 authored by Dominik Röttsches's avatar Dominik Röttsches Committed by Commit Bot

Extend FontService to handle FontConfig Sandbox IPC methods

In order to turn OOP FontConfig queries from Sandbox IPC filedescriptor
based messages to Mojo messages, we need FontService to handle
additional queries for font fallback, retrieving render style and
performing font matching in a PPAPI context. These methods are moving
from sandbox_ipc_linux.cc as well as font_utils_linux.h and will be
temporarily duplicated until the methods will be removed from
where they were duplicated from.

For the design doc, please refer to crbug.com/839344.

Bug: 849923
Change-Id: If0197eae2c9bba8495c065d641b3fef39e403a83
Reviewed-on: https://chromium-review.googlesource.com/1087951
Commit-Queue: Dominik Röttsches <drott@chromium.org>
Reviewed-by: default avatarBill Budge <bbudge@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569974}
parent bb1059e5
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//build/config/features.gni")
import("//build/config/features.gni")
import("//ppapi/buildflags/buildflags.gni")
import("//ppapi/buildflags/buildflags.gni")
import("//services/service_manager/public/cpp/service.gni") import("//services/service_manager/public/cpp/service.gni")
import("//services/service_manager/public/service_manifest.gni") import("//services/service_manager/public/service_manifest.gni")
import("//services/service_manager/public/tools/test/service_test.gni") import("//services/service_manager/public/tools/test/service_test.gni")
...@@ -19,12 +23,38 @@ source_set("lib") { ...@@ -19,12 +23,38 @@ source_set("lib") {
"//components/services/font/public/interfaces", "//components/services/font/public/interfaces",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//mojo/public/cpp/system", "//mojo/public/cpp/system",
"//ppapi/buildflags:buildflags",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//ui/gfx",
] ]
public_deps = [ public_deps = [
"//skia", "//skia",
] ]
if (is_linux && enable_plugins) {
deps += [ ":ppapi_fontconfig_matching" ]
}
if (is_linux) {
deps += [ "//base/test:fontconfig_util_linux" ]
}
}
if (is_linux && enable_plugins) {
source_set("ppapi_fontconfig_matching") {
sources = [
"ppapi_fontconfig_matching.cc",
"ppapi_fontconfig_matching.h",
]
deps = [
"//base:base",
"//ppapi/buildflags:buildflags",
"//ppapi/c",
"//third_party/fontconfig",
]
}
} }
service("font_service") { service("font_service") {
...@@ -60,11 +90,19 @@ service_test("font_service_unittests") { ...@@ -60,11 +90,19 @@ service_test("font_service_unittests") {
"//components/services/font/public/interfaces", "//components/services/font/public/interfaces",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//mojo/public/cpp/system", "//mojo/public/cpp/system",
"//ppapi/buildflags:buildflags",
"//services/service_manager/public/cpp", "//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support", "//services/service_manager/public/cpp:service_test_support",
"//skia", "//skia",
] ]
if (enable_plugins) {
deps += [
"//ppapi/c",
"//third_party:freetype_harfbuzz",
]
}
data_deps = [ data_deps = [
":font_service", ":font_service",
] ]
......
include_rules = [ include_rules = [
"+services/service_manager", "+services/service_manager",
"+mojo/public", "+mojo/public",
"+ppapi/buildflags",
"+ppapi/c",
"+skia", "+skia",
"+third_party/skia/include", "+third_party/skia/include",
"+ui/gfx"
] ]
...@@ -10,14 +10,46 @@ ...@@ -10,14 +10,46 @@
#include "base/test/fontconfig_util_linux.h" #include "base/test/fontconfig_util_linux.h"
#include "components/services/font/public/interfaces/constants.mojom.h" #include "components/services/font/public/interfaces/constants.mojom.h"
#include "components/services/font/public/interfaces/font_service.mojom.h" #include "components/services/font/public/interfaces/font_service.mojom.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
#include "third_party/skia/include/core/SkFontStyle.h" #include "third_party/skia/include/core/SkFontStyle.h"
#if BUILDFLAG(ENABLE_PLUGINS)
#include <ft2build.h>
#include <freetype/freetype.h>
#include "ppapi/c/private/pp_private_font_charset.h" // nogncheck
#endif
namespace { namespace {
bool IsInTestFontDirectory(const char* path) { bool IsInTestFontDirectory(const char* path) {
const char kTestFontsDir[] = "test_fonts"; const char kTestFontsDir[] = "test_fonts";
return std::string(path).find(kTestFontsDir) != std::string::npos; return std::string(path).find(kTestFontsDir) != std::string::npos;
} }
#if BUILDFLAG(ENABLE_PLUGINS)
std::string GetPostscriptNameFromFile(base::File& font_file) {
int64_t file_size = font_file.GetLength();
if (!file_size)
return "";
std::vector<char> file_contents;
file_contents.reserve(file_size);
CHECK_EQ(file_size, font_file.Read(0, file_contents.data(), file_size));
std::string font_family_name;
FT_Library library;
FT_Init_FreeType(&library);
FT_Face font_face;
FT_Open_Args open_args = {FT_OPEN_MEMORY,
reinterpret_cast<FT_Byte*>(file_contents.data()),
file_size};
CHECK_EQ(FT_Err_Ok, FT_Open_Face(library, &open_args, 0, &font_face));
font_family_name = FT_Get_Postscript_Name(font_face);
FT_Done_Face(font_face);
FT_Done_FreeType(library);
return font_family_name;
}
#endif
} // namespace } // namespace
namespace font_service { namespace font_service {
...@@ -90,4 +122,115 @@ TEST_F(FontLoaderTest, EmptyFontName) { ...@@ -90,4 +122,115 @@ TEST_F(FontLoaderTest, EmptyFontName) {
EXPECT_TRUE(IsInTestFontDirectory(font_identity.fString.c_str())); EXPECT_TRUE(IsInTestFontDirectory(font_identity.fString.c_str()));
} }
TEST_F(FontLoaderTest, CharacterFallback) {
std::pair<uint32_t, std::string> fallback_characters_families[] = {
// A selection of character hitting fonts from the third_party/test_fonts
// portfolio.
{0x662F /* CJK UNIFIED IDEOGRAPH-662F */, "Noto Sans CJK JP"},
{0x1780 /* KHMER LETTER KA */, "Noto Sans Khmer"},
{0xA05 /* GURMUKHI LETTER A */, "Lohit Gurmukhi"},
{0xB85 /* TAMIL LETTER A */, "Lohit Tamil"},
{0x904 /* DEVANAGARI LETTER SHORT A */, "Lohit Devanagari"},
{0x985 /* BENGALI LETTER A */, "Mukti Narrow"},
// Tests for not finding fallback:
{0x13170 /* EGYPTIAN HIEROGLYPH G042 */, ""},
{0x1817 /* MONGOLIAN DIGIT SEVEN */, ""}};
for (auto& character_family : fallback_characters_families) {
mojom::FontIdentityPtr font_identity;
std::string result_family_name;
bool is_bold;
bool is_italic;
font_loader()->FallbackFontForCharacter(
std::move(character_family.first), "en_US", &font_identity,
&result_family_name, &is_bold, &is_italic);
EXPECT_EQ(result_family_name, character_family.second);
EXPECT_FALSE(is_bold);
EXPECT_FALSE(is_italic);
if (character_family.second.size()) {
EXPECT_TRUE(
IsInTestFontDirectory(font_identity->str_representation.c_str()));
} else {
EXPECT_EQ(font_identity->str_representation.size(), 0u);
EXPECT_EQ(result_family_name, "");
}
}
}
TEST_F(FontLoaderTest, RenderStyleForStrike) {
// Use FontConfig configured test font aliases from kFontsConfTemplate in
// fontconfig_util_linux.cc.
std::pair<std::string, mojom::FontRenderStylePtr> families_styles[] = {
{"NonAntiAliasedSans",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::ON, 3, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"SlightHintedGeorgia",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::ON, 1, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"NonHintedSans",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::OFF, 0, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"AutohintedSerif",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::ON, 2, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"HintedSerif",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::ON, 2, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"FullAndAutoHintedSerif",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::ON, 3, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)},
{"SubpixelEnabledArial",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::ON, 3, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF)},
{"SubpixelDisabledArial",
mojom::FontRenderStyle::New(
mojom::RenderStyleSwitch::ON, mojom::RenderStyleSwitch::OFF,
mojom::RenderStyleSwitch::ON, 3, mojom::RenderStyleSwitch::ON,
mojom::RenderStyleSwitch::OFF, mojom::RenderStyleSwitch::OFF)}};
for (auto& family_style : families_styles) {
mojom::FontRenderStylePtr result_style;
font_loader()->FontRenderStyleForStrike(std::move(family_style.first), 16,
false, false, 1.0, &result_style);
EXPECT_TRUE(result_style.Equals(family_style.second));
}
}
TEST_F(FontLoaderTest, PPAPIFallback) {
#if BUILDFLAG(ENABLE_PLUGINS)
std::tuple<std::string, uint32_t, std::string> family_charset_expectations[] =
{
{"", PP_PRIVATEFONTCHARSET_SHIFTJIS, "DejaVuSans"},
{"", PP_PRIVATEFONTCHARSET_THAI, "Garuda"},
{"", PP_PRIVATEFONTCHARSET_GB2312, "DejaVuSans"},
{"", PP_PRIVATEFONTCHARSET_GREEK, "DejaVuSans"},
{"Arial", PP_PRIVATEFONTCHARSET_DEFAULT, "Arimo-Regular"},
{"Times New Roman", PP_PRIVATEFONTCHARSET_DEFAULT, "Tinos-Regular"},
{"Courier New", PP_PRIVATEFONTCHARSET_DEFAULT, "Cousine-Regular"},
};
for (auto& family_charset_expectation : family_charset_expectations) {
base::File result_file;
font_loader()->MatchFontWithFallback(
std::move(std::get<0>(family_charset_expectation)), false, false,
std::move(std::get<1>(family_charset_expectation)), 0, &result_file);
EXPECT_TRUE(result_file.IsValid());
EXPECT_EQ(GetPostscriptNameFromFile(result_file),
std::get<2>(family_charset_expectation));
}
#endif
}
} // namespace font_service } // namespace font_service
...@@ -10,8 +10,20 @@ ...@@ -10,8 +10,20 @@
#include "base/files/file.h" #include "base/files/file.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/test/fontconfig_util_linux.h" #include "base/test/fontconfig_util_linux.h"
#include "build/build_config.h"
#include "mojo/public/cpp/system/platform_handle.h" #include "mojo/public/cpp/system/platform_handle.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/service_manager/public/cpp/service_context.h" #include "services/service_manager/public/cpp/service_context.h"
#include "ui/gfx/font_fallback_linux.h"
#include "ui/gfx/font_render_params.h"
#if BUILDFLAG(ENABLE_PLUGINS)
#include "components/services/font/ppapi_fontconfig_matching.h" // nogncheck
#endif
#if defined(OS_LINUX)
#include "base/test/fontconfig_util_linux.h"
#endif
static_assert( static_assert(
static_cast<uint32_t>(SkFontStyle::kUpright_Slant) == static_cast<uint32_t>(SkFontStyle::kUpright_Slant) ==
...@@ -42,10 +54,44 @@ bool FontConfigTestingEnvironmentEnabled() { ...@@ -42,10 +54,44 @@ bool FontConfigTestingEnvironmentEnabled() {
switches::kFontConfigTestingEnvironment); switches::kFontConfigTestingEnvironment);
} }
int ConvertHinting(gfx::FontRenderParams::Hinting hinting) {
switch (hinting) {
case gfx::FontRenderParams::HINTING_NONE:
return 0;
case gfx::FontRenderParams::HINTING_SLIGHT:
return 1;
case gfx::FontRenderParams::HINTING_MEDIUM:
return 2;
case gfx::FontRenderParams::HINTING_FULL:
return 3;
}
NOTREACHED() << "Unexpected hinting value " << hinting;
return 0;
}
font_service::mojom::RenderStyleSwitch ConvertSubpixelRendering(
gfx::FontRenderParams::SubpixelRendering rendering) {
switch (rendering) {
case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
return font_service::mojom::RenderStyleSwitch::OFF;
case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
return font_service::mojom::RenderStyleSwitch::ON;
}
NOTREACHED() << "Unexpected subpixel rendering value " << rendering;
return font_service::mojom::RenderStyleSwitch::NO_PREFERENCE;
}
} // namespace } // namespace
namespace font_service { namespace font_service {
std::unique_ptr<service_manager::Service> FontServiceApp::CreateService() {
return std::make_unique<FontServiceApp>();
}
FontServiceApp::FontServiceApp() { FontServiceApp::FontServiceApp() {
// TODO(thomasanderson) https://crbug.com/831146: Remove this once a reland of // TODO(thomasanderson) https://crbug.com/831146: Remove this once a reland of
// CL https://chromium-review.googlesource.com/c/chromium/src/+/1009071 lands, // CL https://chromium-review.googlesource.com/c/chromium/src/+/1009071 lands,
...@@ -55,7 +101,7 @@ FontServiceApp::FontServiceApp() { ...@@ -55,7 +101,7 @@ FontServiceApp::FontServiceApp() {
if (FontConfigTestingEnvironmentEnabled()) if (FontConfigTestingEnvironmentEnabled())
base::SetUpFontconfig(); base::SetUpFontconfig();
registry_.AddInterface( registry_.AddInterface(
base::Bind(&FontServiceApp::Create, base::Unretained(this))); base::BindRepeating(&FontServiceApp::CreateSelf, base::Unretained(this)));
} }
FontServiceApp::~FontServiceApp() { FontServiceApp::~FontServiceApp() {
...@@ -115,6 +161,7 @@ void FontServiceApp::MatchFamilyName(const std::string& family_name, ...@@ -115,6 +161,7 @@ void FontServiceApp::MatchFamilyName(const std::string& family_name,
void FontServiceApp::OpenStream(uint32_t id_number, void FontServiceApp::OpenStream(uint32_t id_number,
OpenStreamCallback callback) { OpenStreamCallback callback) {
DCHECK_LT(id_number, static_cast<uint32_t>(paths_.size()));
base::File file; base::File file;
if (id_number < static_cast<uint32_t>(paths_.size())) { if (id_number < static_cast<uint32_t>(paths_.size())) {
file = GetFileForPath(base::FilePath(paths_[id_number].c_str())); file = GetFileForPath(base::FilePath(paths_[id_number].c_str()));
...@@ -123,7 +170,76 @@ void FontServiceApp::OpenStream(uint32_t id_number, ...@@ -123,7 +170,76 @@ void FontServiceApp::OpenStream(uint32_t id_number,
std::move(callback).Run(std::move(file)); std::move(callback).Run(std::move(file));
} }
void FontServiceApp::Create(mojom::FontServiceRequest request) { void FontServiceApp::FallbackFontForCharacter(
uint32_t character,
const std::string& locale,
FallbackFontForCharacterCallback callback) {
auto fallback_font = gfx::GetFallbackFontForChar(character, locale);
int index = FindOrAddPath(SkString(fallback_font.filename.data()));
mojom::FontIdentityPtr identity(mojom::FontIdentity::New());
identity->id = static_cast<uint32_t>(index);
identity->ttc_index = fallback_font.ttc_index;
identity->str_representation = fallback_font.filename;
std::move(callback).Run(std::move(identity), fallback_font.name,
fallback_font.is_bold, fallback_font.is_italic);
}
void FontServiceApp::FontRenderStyleForStrike(
const std::string& family,
uint32_t size,
bool is_bold,
bool is_italic,
float device_scale_factor,
FontRenderStyleForStrikeCallback callback) {
gfx::FontRenderParamsQuery query;
query.device_scale_factor = device_scale_factor;
query.families.push_back(family);
query.pixel_size = size;
query.style = is_italic ? gfx::Font::ITALIC : 0;
query.weight = is_bold ? gfx::Font::Weight::BOLD : gfx::Font::Weight::NORMAL;
const gfx::FontRenderParams params = gfx::GetFontRenderParams(query, nullptr);
mojom::FontRenderStylePtr font_render_style(mojom::FontRenderStyle::New(
params.use_bitmaps ? mojom::RenderStyleSwitch::ON
: mojom::RenderStyleSwitch::OFF,
params.autohinter ? mojom::RenderStyleSwitch::ON
: mojom::RenderStyleSwitch::OFF,
params.hinting != gfx::FontRenderParams::HINTING_NONE
? mojom::RenderStyleSwitch::ON
: mojom::RenderStyleSwitch::OFF,
ConvertHinting(params.hinting),
params.antialiasing ? mojom::RenderStyleSwitch::ON
: mojom::RenderStyleSwitch::OFF,
ConvertSubpixelRendering(params.subpixel_rendering),
params.subpixel_positioning ? mojom::RenderStyleSwitch::ON
: mojom::RenderStyleSwitch::OFF));
std::move(callback).Run(std::move(font_render_style));
}
void FontServiceApp::MatchFontWithFallback(
const std::string& family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallbackFamilyType,
MatchFontWithFallbackCallback callback) {
#if BUILDFLAG(ENABLE_PLUGINS)
base::File matched_font_file;
int font_file_descriptor = MatchFontFaceWithFallback(
family, is_bold, is_italic, charset, fallbackFamilyType);
matched_font_file = base::File(font_file_descriptor);
if (!matched_font_file.IsValid())
matched_font_file = base::File();
std::move(callback).Run(std::move(matched_font_file));
#else
NOTREACHED();
#endif
}
void FontServiceApp::CreateSelf(mojom::FontServiceRequest request) {
bindings_.AddBinding(this, std::move(request)); bindings_.AddBinding(this, std::move(request));
} }
......
...@@ -23,6 +23,10 @@ class FontServiceApp : public service_manager::Service, ...@@ -23,6 +23,10 @@ class FontServiceApp : public service_manager::Service,
FontServiceApp(); FontServiceApp();
~FontServiceApp() override; ~FontServiceApp() override;
static std::unique_ptr<service_manager::Service> CreateService();
void CreateSelf(mojom::FontServiceRequest request);
private: private:
// service_manager::Service: // service_manager::Service:
void OnStart() override; void OnStart() override;
...@@ -35,9 +39,23 @@ class FontServiceApp : public service_manager::Service, ...@@ -35,9 +39,23 @@ class FontServiceApp : public service_manager::Service,
mojom::TypefaceStylePtr requested_style, mojom::TypefaceStylePtr requested_style,
MatchFamilyNameCallback callback) override; MatchFamilyNameCallback callback) override;
void OpenStream(uint32_t id_number, OpenStreamCallback callback) override; void OpenStream(uint32_t id_number, OpenStreamCallback callback) override;
void FallbackFontForCharacter(
void Create(mojom::FontServiceRequest request); uint32_t character,
const std::string& locale,
FallbackFontForCharacterCallback callback) override;
void FontRenderStyleForStrike(
const std::string& family,
uint32_t size,
bool italic,
bool bold,
float device_scale_factor,
FontRenderStyleForStrikeCallback callback) override;
void MatchFontWithFallback(const std::string& family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallbackFamilyType,
MatchFontWithFallbackCallback callback) override;
int FindOrAddPath(const SkString& path); int FindOrAddPath(const SkString& path);
service_manager::BinderRegistry registry_; service_manager::BinderRegistry registry_;
......
// Copyright 2018 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 "components/services/font/ppapi_fontconfig_matching.h"
#include <fcntl.h>
#include <fontconfig/fontconfig.h>
#include <stddef.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h"
#include "ppapi/c/private/pp_private_font_charset.h"
#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
namespace {
// MSCharSetToFontconfig translates a Microsoft charset identifier to a
// fontconfig language set by appending to |langset|.
// Returns true if |langset| is Latin/Greek/Cyrillic.
bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
// We have need to translate raw fdwCharSet values into terms that
// fontconfig can understand. (See the description of fdwCharSet in the MSDN
// documentation for CreateFont:
// http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx )
//
// Although the argument is /called/ 'charset', the actual values conflate
// character sets (which are sets of Unicode code points) and character
// encodings (which are algorithms for turning a series of bits into a
// series of code points.) Sometimes the values will name a language,
// sometimes they'll name an encoding. In the latter case I'm assuming that
// they mean the set of code points in the domain of that encoding.
//
// fontconfig deals with ISO 639-1 language codes:
// http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
//
// So, for each of the documented fdwCharSet values I've had to take a
// guess at the set of ISO 639-1 languages intended.
bool is_lgc = false;
switch (fdwCharSet) {
case PP_PRIVATEFONTCHARSET_ANSI:
// These values I don't really know what to do with, so I'm going to map
// them to English also.
case PP_PRIVATEFONTCHARSET_DEFAULT:
case PP_PRIVATEFONTCHARSET_MAC:
case PP_PRIVATEFONTCHARSET_OEM:
case PP_PRIVATEFONTCHARSET_SYMBOL:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en"));
break;
case PP_PRIVATEFONTCHARSET_BALTIC:
// The three baltic languages.
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("et"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lv"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lt"));
break;
case PP_PRIVATEFONTCHARSET_CHINESEBIG5:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw"));
break;
case PP_PRIVATEFONTCHARSET_GB2312:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn"));
break;
case PP_PRIVATEFONTCHARSET_EASTEUROPE:
// A scattering of eastern European languages.
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu"));
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr"));
break;
case PP_PRIVATEFONTCHARSET_GREEK:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el"));
break;
case PP_PRIVATEFONTCHARSET_HANGUL:
case PP_PRIVATEFONTCHARSET_JOHAB:
// Korean
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko"));
break;
case PP_PRIVATEFONTCHARSET_RUSSIAN:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru"));
break;
case PP_PRIVATEFONTCHARSET_SHIFTJIS:
// Japanese
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja"));
break;
case PP_PRIVATEFONTCHARSET_TURKISH:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr"));
break;
case PP_PRIVATEFONTCHARSET_VIETNAMESE:
is_lgc = true;
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi"));
break;
case PP_PRIVATEFONTCHARSET_ARABIC:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar"));
break;
case PP_PRIVATEFONTCHARSET_HEBREW:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he"));
break;
case PP_PRIVATEFONTCHARSET_THAI:
FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th"));
break;
// default:
// Don't add any languages in that case that we don't recognise the
// constant.
}
return is_lgc;
}
} // namespace
namespace font_service {
int MatchFontFaceWithFallback(const std::string& face,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallback_family) {
FcLangSet* langset = FcLangSetCreate();
bool is_lgc = MSCharSetToFontconfig(langset, charset);
FcPattern* pattern = FcPatternCreate();
FcPatternAddString(pattern, FC_FAMILY,
reinterpret_cast<const FcChar8*>(face.c_str()));
// TODO(thestig) Check if we can access Chrome's per-script font preference
// here and select better default fonts for non-LGC case.
std::string generic_font_name;
if (is_lgc) {
switch (fallback_family) {
case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF:
generic_font_name = "Times New Roman";
break;
case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF:
generic_font_name = "Arial";
break;
case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE:
generic_font_name = "Courier New";
break;
}
}
if (!generic_font_name.empty()) {
const FcChar8* fc_generic_font_name =
reinterpret_cast<const FcChar8*>(generic_font_name.c_str());
FcPatternAddString(pattern, FC_FAMILY, fc_generic_font_name);
}
if (is_bold)
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
if (is_italic)
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
FcPatternAddLangSet(pattern, FC_LANG, langset);
FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
FcResult result;
FcFontSet* font_set = FcFontSort(nullptr, pattern, 0, nullptr, &result);
int font_fd = -1;
int good_enough_index = -1;
bool good_enough_index_set = false;
if (font_set) {
for (int i = 0; i < font_set->nfont; ++i) {
FcPattern* current = font_set->fonts[i];
// Older versions of fontconfig have a bug where they cannot select
// only scalable fonts so we have to manually filter the results.
FcBool is_scalable;
if (FcPatternGetBool(current, FC_SCALABLE, 0, &is_scalable) !=
FcResultMatch ||
!is_scalable) {
continue;
}
FcChar8* c_filename;
if (FcPatternGetString(current, FC_FILE, 0, &c_filename) !=
FcResultMatch) {
continue;
}
// We only want to return sfnt (TrueType) based fonts. We don't have a
// very good way of detecting this so we'll filter based on the
// filename.
bool is_sfnt = false;
static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc",
""};
for (size_t j = 0;; j++) {
if (kSFNTExtensions[j][0] == 0) {
// None of the extensions matched.
break;
}
if (base::EndsWith(std::string(reinterpret_cast<char*>(c_filename)),
kSFNTExtensions[j], base::CompareCase::SENSITIVE)) {
is_sfnt = true;
break;
}
}
if (!is_sfnt)
continue;
// This font is good enough to pass muster, but we might be able to do
// better with subsequent ones.
if (!good_enough_index_set) {
good_enough_index = i;
good_enough_index_set = true;
}
FcValue matrix;
bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0;
if (is_italic && have_matrix) {
// we asked for an italic font, but fontconfig is giving us a
// non-italic font with a transformation matrix.
continue;
}
FcValue embolden;
const bool have_embolden =
FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0;
if (is_bold && have_embolden) {
// we asked for a bold font, but fontconfig gave us a non-bold font
// and asked us to apply fake bolding.
continue;
}
font_fd =
HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
if (font_fd >= 0)
break;
}
}
if (font_fd == -1 && good_enough_index_set) {
// We didn't find a font that we liked, so we fallback to something
// acceptable.
FcPattern* current = font_set->fonts[good_enough_index];
FcChar8* c_filename;
FcPatternGetString(current, FC_FILE, 0, &c_filename);
font_fd = HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
}
if (font_set)
FcFontSetDestroy(font_set);
FcPatternDestroy(pattern);
return font_fd;
}
} // namespace font_service
// Copyright 2018 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 COMPONENTS_SERVICES_FONT_PPAPI_FONTCONFIG_MATCHING_H_
#define COMPONENTS_SERVICES_FONT_PPAPI_FONTCONFIG_MATCHING_H_
#include <stdint.h>
#include "base/macros.h"
#include "build/build_config.h"
#include "ppapi/buildflags/buildflags.h"
#include <string>
#if !BUILDFLAG(ENABLE_PLUGINS)
#error "Plugins should be enabled when including " ## __FILE__
#endif
namespace font_service {
int MatchFontFaceWithFallback(const std::string& face,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallback_family);
} // namespace font_service
#endif // COMPONENTS_SERVICES_FONT_PPAPI_FONTCONFIG_MATCHING_H_
...@@ -9,13 +9,14 @@ ...@@ -9,13 +9,14 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "components/services/font/public/cpp/font_service_thread.h" #include "components/services/font/public/cpp/font_service_thread.h"
#include "components/services/font/public/interfaces/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
namespace font_service { namespace font_service {
FontLoader::FontLoader(service_manager::Connector* connector) { FontLoader::FontLoader(service_manager::Connector* connector) {
mojom::FontServicePtr font_service; mojom::FontServicePtr font_service;
connector->BindInterface("font_service", &font_service); connector->BindInterface(font_service::mojom::kServiceName, &font_service);
thread_ = new internal::FontServiceThread(std::move(font_service)); thread_ = new internal::FontServiceThread(std::move(font_service));
} }
...@@ -66,6 +67,41 @@ SkStreamAsset* FontLoader::openStream(const FontIdentity& identity) { ...@@ -66,6 +67,41 @@ SkStreamAsset* FontLoader::openStream(const FontIdentity& identity) {
} }
} }
// Additional cross-thread accessible methods.
bool FontLoader::FallbackFontForCharacter(
uint32_t character,
std::string locale,
mojom::FontIdentityPtr* out_font_identity,
std::string* out_family_name,
bool* out_is_bold,
bool* out_is_italic) {
return thread_->FallbackFontForCharacter(character, std::move(locale),
out_font_identity, out_family_name,
out_is_bold, out_is_italic);
}
bool FontLoader::FontRenderStyleForStrike(
std::string family,
uint32_t size,
bool is_italic,
bool is_bold,
float device_scale_factor,
mojom::FontRenderStylePtr* out_font_render_style) {
return thread_->FontRenderStyleForStrike(std::move(family), size, is_italic,
is_bold, device_scale_factor,
out_font_render_style);
}
void FontLoader::MatchFontWithFallback(std::string family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallback_family_type,
base::File* out_font_file_handle) {
thread_->MatchFontWithFallback(std::move(family), is_bold, is_italic, charset,
fallback_family_type, out_font_file_handle);
}
void FontLoader::OnMappedFontFileDestroyed(internal::MappedFontFile* f) { void FontLoader::OnMappedFontFileDestroyed(internal::MappedFontFile* f) {
TRACE_EVENT1("font_loader", "FontLoader::OnMappedFontFileDestroyed", TRACE_EVENT1("font_loader", "FontLoader::OnMappedFontFileDestroyed",
"identity", f->font_id()); "identity", f->font_id());
......
...@@ -49,6 +49,35 @@ class FontLoader : public SkFontConfigInterface, ...@@ -49,6 +49,35 @@ class FontLoader : public SkFontConfigInterface,
SkFontStyle* out_style) override; SkFontStyle* out_style) override;
SkStreamAsset* openStream(const FontIdentity& identity) override; SkStreamAsset* openStream(const FontIdentity& identity) override;
// Additional cross-thread accessible methods below.
// Out parameters are only guaranteed to be initialized when method returns
// true.
bool FallbackFontForCharacter(uint32_t character,
std::string locale,
mojom::FontIdentityPtr* out_identity,
std::string* out_family_name,
bool* out_is_bold,
bool* out_is_italic);
// Out parameters are only guaranteed to be initialized when method returns
// true.
bool FontRenderStyleForStrike(
std::string family,
uint32_t size,
bool is_italic,
bool is_bold,
float device_scale_factor,
mojom::FontRenderStylePtr* out_font_render_style);
// Out parameter out_font_file_handle should always be an opened file handle
// to a matched or default font file. out_font_file_handle is a default
// initialized base::File on error.
void MatchFontWithFallback(std::string family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallbackFamilyType,
base::File* out_font_file_handle);
private: private:
// internal::MappedFontFile::Observer: // internal::MappedFontFile::Observer:
void OnMappedFontFileDestroyed(internal::MappedFontFile* f) override; void OnMappedFontFileDestroyed(internal::MappedFontFile* f) override;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/threading/thread_checker.h"
#include "components/services/font/public/interfaces/font_service.mojom.h" #include "components/services/font/public/interfaces/font_service.mojom.h"
#include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h" #include "third_party/skia/include/core/SkTypeface.h"
...@@ -45,6 +46,27 @@ class FontServiceThread : public base::Thread, ...@@ -45,6 +46,27 @@ class FontServiceThread : public base::Thread,
scoped_refptr<MappedFontFile> OpenStream( scoped_refptr<MappedFontFile> OpenStream(
const SkFontConfigInterface::FontIdentity& identity); const SkFontConfigInterface::FontIdentity& identity);
bool FallbackFontForCharacter(
uint32_t character,
std::string locale,
font_service::mojom::FontIdentityPtr* out_font_identity,
std::string* out_family_name,
bool* out_is_bold,
bool* out_is_italic);
bool FontRenderStyleForStrike(
std::string family,
uint32_t size,
bool is_italic,
bool is_bold,
float device_scale_factor,
font_service::mojom::FontRenderStylePtr* out_font_render_style);
void MatchFontWithFallback(std::string family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallbackFamilyType,
base::File* out_font_file_handle);
private: private:
friend class base::RefCountedThreadSafe<FontServiceThread>; friend class base::RefCountedThreadSafe<FontServiceThread>;
~FontServiceThread() override; ~FontServiceThread() override;
...@@ -82,6 +104,53 @@ class FontServiceThread : public base::Thread, ...@@ -82,6 +104,53 @@ class FontServiceThread : public base::Thread,
base::File* output_file, base::File* output_file,
base::File file); base::File file);
void FallbackFontForCharacterImpl(
base::WaitableEvent* done_event,
uint32_t character,
std::string locale,
bool* out_is_valid,
font_service::mojom::FontIdentityPtr* out_font_identity,
std::string* out_family_name,
bool* out_is_bold,
bool* out_is_italic);
void OnFallbackFontForCharacterComplete(
base::WaitableEvent* done_event,
bool* out_valid,
font_service::mojom::FontIdentityPtr* out_font_identity,
std::string* out_family_name,
bool* out_is_bold,
bool* out_is_italic,
mojom::FontIdentityPtr font_identity,
const std::string& family_name,
bool is_bold,
bool is_italic);
void FontRenderStyleForStrikeImpl(
base::WaitableEvent* done_event,
std::string family,
uint32_t size,
bool is_italic,
bool is_bold,
float device_scale_factor,
bool* out_valid,
mojom::FontRenderStylePtr* out_font_render_style);
void OnFontRenderStyleForStrikeComplete(
base::WaitableEvent* done_event,
bool* out_valid,
mojom::FontRenderStylePtr* out_font_render_style,
mojom::FontRenderStylePtr font_render_style);
void MatchFontWithFallbackImpl(base::WaitableEvent* done_event,
std::string family,
bool is_bold,
bool is_italic,
uint32_t charset,
uint32_t fallbackFamilyType,
base::File* out_font_file_handle);
void OnMatchFontWithFallbackComplete(base::WaitableEvent* done_event,
base::File* out_font_file_handle,
base::File file);
// Connection to |font_service_| has gone away. Called on the background // Connection to |font_service_| has gone away. Called on the background
// thread. // thread.
void OnFontServiceConnectionError(); void OnFontServiceConnectionError();
...@@ -98,14 +167,17 @@ class FontServiceThread : public base::Thread, ...@@ -98,14 +167,17 @@ class FontServiceThread : public base::Thread,
// non-thread bound, and binds it to the newly created thread. // non-thread bound, and binds it to the newly created thread.
mojo::InterfacePtr<mojom::FontService> font_service_; mojo::InterfacePtr<mojom::FontService> font_service_;
// All WaitableEvents supplied to OpenStreamImpl() are added here while // All WaitableEvents supplied to OpenStreamImpl() and the other *Impl()
// waiting on the response from the |font_service_| (FontService::OpenStream() // functions are added here while waiting on the response from the
// was called, but the callback has not been processed yet). If // |font_service_| (FontService::OpenStream() or other such functions were
// |font_service_| gets an error during this time all events in // called, but the callbacks have not been processed yet). If |font_service_|
// |pending_waitable_events_| are signaled. This is necessary as when the // gets an error during this time all events in |pending_waitable_events_| are
// pipe is closed the callbacks are never received. // signaled. This is necessary as when the pipe is closed the callbacks are
// never received.
std::set<base::WaitableEvent*> pending_waitable_events_; std::set<base::WaitableEvent*> pending_waitable_events_;
THREAD_CHECKER(thread_checker_);
base::WeakPtrFactory<FontServiceThread> weak_factory_; base::WeakPtrFactory<FontServiceThread> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FontServiceThread); DISALLOW_COPY_AND_ASSIGN(FontServiceThread);
......
...@@ -30,7 +30,26 @@ struct FontIdentity { ...@@ -30,7 +30,26 @@ struct FontIdentity {
string str_representation; string str_representation;
}; };
// Loads and resolves fonts. enum RenderStyleSwitch {
OFF = 0,
ON = 1,
NO_PREFERENCE = 2,
};
struct FontRenderStyle {
RenderStyleSwitch use_bitmaps; // use embedded bitmap strike if possible
RenderStyleSwitch use_autohint; // use 'auto' hinting (FreeType specific)
RenderStyleSwitch use_hinting; // hint glyphs to the pixel grid
uint8 hint_style; // level of hinting, 0..3
RenderStyleSwitch use_antialias; // antialias glyph shapes
// use subpixel rendering (partially-filled pixels)
RenderStyleSwitch use_subpixel_rendering;
// use subpixel positioning (fractional X positions for glyphs)
RenderStyleSwitch use_subpixel_positioning;
};
// Loads and resolves fonts & returns additional information accessible from
// FontConfig only outside the sandbox.
// //
// We still need to load fonts from within a sandboxed process. We set // We still need to load fonts from within a sandboxed process. We set
// up a service to match fonts and load them. This service needs full // up a service to match fonts and load them. This service needs full
...@@ -45,4 +64,27 @@ interface FontService { ...@@ -45,4 +64,27 @@ interface FontService {
// Returns a handle to the raw font specified by |id_number|. // Returns a handle to the raw font specified by |id_number|.
OpenStream(uint32 id_number) => (mojo_base.mojom.File? font_handle); OpenStream(uint32 id_number) => (mojo_base.mojom.File? font_handle);
// Returns a fallback FontIdentity and Typeface style for the given character
// and locale. If no fallback font can be found, returns a null identity.
FallbackFontForCharacter(uint32 character, string locale) =>
(FontIdentity? identity,
string family_name,
bool is_bold,
bool is_italic);
// Fill out the given WebFontRenderStyle with the user's preferences for
// rendering the given font at the given size (in pixels), given weight
// (is_bold or not), and given slant (is_italic or not).
FontRenderStyleForStrike(string family,
uint32 size,
bool is_italic,
bool is_bold,
float device_scale_factor) =>
(FontRenderStyle? font_render_style);
// PPAPI Specific font call to match a font family and charset.
MatchFontWithFallback(string family, bool is_bold, bool is_italic,
uint32 charset, uint32 fallback_family_type) =>
(mojo_base.mojom.File? font_file_handle);
}; };
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