Commit 587827f0 authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

[Fuchsia] Add SkFontMgr implementation for Fuchsia

Initial implementation of SkFontMgr for Fuchsia that implements minimal
SkFontMgr functionality used in Blink. There are still a number of
features that don't work properly and will require changes in the
system FontProvider to get fixed:
 1. Character to font matching (see onMatchFamilyStyleCharacter()).
    Currently the system API doesn't provide this feature.
 2. Style matching according to CSS3: Font style matching rules
    implemented in Fuchsia's font provider do not match CSS3 rules.
 3. Font aliasing: FontProvider supports only 3 Roboto fonts (Roboto,
    RobotoSlab and RobotoMono) doesn't support any font family aliases.
    To workaround this issue aliasing implemented directly in
    FuchsiaFontManager.

The new SkFontMgr is not enabled yet because it doesn't work in sandbox.
Will enabled it later in a separate CL.

Bug: 800156
Change-Id: I98a9bed3f98c492577cc9cf0a81f190c8837da31
Reviewed-on: https://chromium-review.googlesource.com/1114192
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572360}
parent 2aa1ee72
......@@ -481,6 +481,13 @@ component("skia") {
"//third_party/skia/src/ports/SkFontMgr_custom.cpp",
"//third_party/skia/src/ports/SkFontMgr_custom_empty.cpp",
"ext/fontmgr_default_fuchsia.cc",
"ext/fontmgr_default_fuchsia.h",
"ext/fontmgr_fuchsia.cc",
"ext/fontmgr_fuchsia.h",
]
deps += [
"//third_party/fuchsia-sdk:fonts",
"//third_party/icu:icuuc",
]
}
......@@ -795,6 +802,17 @@ test("skia_unittests") {
"//skia/public/interfaces:test_interfaces",
]
}
if (is_fuchsia) {
sources += [ "ext/fontmgr_fuchsia_unittest.cc" ]
deps += [
"//third_party/fuchsia-sdk:fonts",
"//third_party/test_fonts",
]
data_deps = [
"//third_party/test_fonts",
]
}
}
if (!is_ios) {
......
......@@ -22,5 +22,7 @@ SK_API sk_sp<SkFontMgr> SkFontMgr::Factory() {
if (g_default_fontmgr) {
return sk_ref_sp(g_default_fontmgr);
}
// TODO(crbug.com/800156): Replace with FuchsiaFontManager when we can
// access FontProvider in sandbox.
return SkFontMgr_New_Custom_Empty();
}
This diff is collapsed.
// 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 SKIA_EXT_FONTMGR_FUCHSIA_H_
#define SKIA_EXT_FONTMGR_FUCHSIA_H_
#include <memory>
#include <fuchsia/fonts/cpp/fidl.h>
#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace skia {
class FuchsiaFontManager : public SkFontMgr {
public:
explicit FuchsiaFontManager(
fuchsia::fonts::FontProviderSync2Ptr font_provider);
~FuchsiaFontManager() override;
protected:
// SkFontMgr overrides.
int onCountFamilies() const override;
void onGetFamilyName(int index, SkString* family_name) const override;
SkFontStyleSet* onMatchFamily(const char family_name[]) const override;
SkFontStyleSet* onCreateStyleSet(int index) const override;
SkTypeface* onMatchFamilyStyle(const char family_name[],
const SkFontStyle&) const override;
SkTypeface* onMatchFamilyStyleCharacter(const char family_name[],
const SkFontStyle&,
const char* bcp47[],
int bcp47_count,
SkUnichar character) const override;
SkTypeface* onMatchFaceStyle(const SkTypeface*,
const SkFontStyle&) const override;
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttc_index) const override;
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
int ttc_index) const override;
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
const SkFontArguments&) const override;
sk_sp<SkTypeface> onMakeFromFile(const char path[],
int ttc_index) const override;
sk_sp<SkTypeface> onLegacyMakeTypeface(const char family_name[],
SkFontStyle) const override;
private:
class FontCache;
fuchsia::fonts::FontProviderSync2Ptr font_provider_;
// Map applied to font family name before sending requests to the FontService.
base::flat_map<std::string, std::string> font_map_;
// FontCache keeps all SkTypeface instances returned by the manager. It allows
// to ensure that SkTypeface object is created only once for each typeface.
std::unique_ptr<FontCache> font_cache_;
sk_sp<SkTypeface> default_typeface_;
DISALLOW_COPY_AND_ASSIGN(FuchsiaFontManager);
};
} // namespace skia
#endif // SKIA_EXT_FONTMGR_FUCHSIA_H_
// 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 "skia/ext/fontmgr_fuchsia.h"
#include <fuchsia/fonts/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/location.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/task_runner.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace skia {
namespace {
constexpr zx_rights_t kFontDataRights =
ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP;
fuchsia::fonts::FontData LoadFont(const base::FilePath& file_path) {
std::string file_content;
CHECK(ReadFileToString(file_path, &file_content));
fuchsia::fonts::FontData data;
zx_status_t status =
zx::vmo::create(file_content.size(), 0, &data.buffer.vmo);
ZX_CHECK(status == ZX_OK, status);
status = data.buffer.vmo.write(file_content.data(), 0, file_content.size());
ZX_CHECK(status == ZX_OK, status);
data.buffer.size = file_content.size();
return data;
}
class MockFontProvider : public fuchsia::fonts::FontProvider {
public:
MockFontProvider() {
base::FilePath assets_dir;
EXPECT_TRUE(base::PathService::Get(base::DIR_ASSETS, &assets_dir));
// Roboto is not in test_fonts. Just load some arbitrary fonts for the
// tests.
roboto_ = LoadFont(assets_dir.Append("test_fonts/Arimo-Regular.ttf"));
roboto_slab_ = LoadFont(assets_dir.Append("test_fonts/Tinos-Regular.ttf"));
}
// fuchsia::fonts::FontProvider implementation.
void GetFont(fuchsia::fonts::FontRequest request,
GetFontCallback callback) override {
fuchsia::fonts::FontData* font_data = nullptr;
if (*request.family == "Roboto") {
font_data = &roboto_;
} else if (*request.family == "RobotoSlab") {
font_data = &roboto_slab_;
}
if (!font_data) {
callback(nullptr);
return;
}
auto response = fuchsia::fonts::FontResponse::New();
EXPECT_EQ(font_data->buffer.vmo.duplicate(kFontDataRights,
&(response->data.buffer.vmo)),
ZX_OK);
response->data.buffer.size = font_data->buffer.size;
callback(std::move(response));
}
private:
fuchsia::fonts::FontData roboto_;
fuchsia::fonts::FontData roboto_slab_;
};
class MockFontProviderService {
public:
MockFontProviderService() : provider_thread_("MockFontProvider") {
provider_thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
}
~MockFontProviderService() {
provider_thread_.task_runner()->DeleteSoon(FROM_HERE,
std::move(provider_binding_));
}
void Bind(fidl::InterfaceRequest<fuchsia::fonts::FontProvider> request) {
provider_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&MockFontProviderService::DoBind,
base::Unretained(this), std::move(request)));
}
private:
void DoBind(fidl::InterfaceRequest<fuchsia::fonts::FontProvider> request) {
provider_binding_ =
std::make_unique<fidl::Binding<fuchsia::fonts::FontProvider>>(
&provider_, std::move(request));
}
base::Thread provider_thread_;
MockFontProvider provider_;
std::unique_ptr<fidl::Binding<fuchsia::fonts::FontProvider>>
provider_binding_;
};
} // namespace
class FuchsiaFontManagerTest : public testing::Test {
public:
FuchsiaFontManagerTest() {
fuchsia::fonts::FontProviderSync2Ptr font_provider;
font_provider_service_.Bind(font_provider.NewRequest());
font_manager_ = sk_make_sp<FuchsiaFontManager>(std::move(font_provider));
}
protected:
MockFontProviderService font_provider_service_;
sk_sp<SkFontMgr> font_manager_;
};
// Verify that SkTypeface objects are cached.
TEST_F(FuchsiaFontManagerTest, Caching) {
sk_sp<SkTypeface> sans(
font_manager_->matchFamilyStyle("sans", SkFontStyle()));
sk_sp<SkTypeface> sans2(
font_manager_->matchFamilyStyle("sans", SkFontStyle()));
// Expect that the same SkTypeface is returned for both requests.
EXPECT_EQ(sans.get(), sans2.get());
// Request serif and verify that a different SkTypeface is returned.
sk_sp<SkTypeface> serif(
font_manager_->matchFamilyStyle("serif", SkFontStyle()));
EXPECT_NE(sans.get(), serif.get());
}
// Verify that SkTypeface can outlive the manager.
TEST_F(FuchsiaFontManagerTest, TypefaceOutlivesManager) {
sk_sp<SkTypeface> sans(
font_manager_->matchFamilyStyle("sans", SkFontStyle()));
font_manager_.reset();
}
// Verify that we can query a font after releasing a previous instance.
TEST_F(FuchsiaFontManagerTest, ReleaseThenCreateAgain) {
sk_sp<SkTypeface> serif(
font_manager_->matchFamilyStyle("serif", SkFontStyle()));
EXPECT_TRUE(serif);
serif.reset();
sk_sp<SkTypeface> serif2(
font_manager_->matchFamilyStyle("serif", SkFontStyle()));
EXPECT_TRUE(serif2);
}
} // namespace skia
\ No newline at end of file
......@@ -145,6 +145,17 @@ fuchsia_sdk_pkg("fit") {
]
}
fuchsia_sdk_fidl_pkg("fonts") {
namespace = "fuchsia"
namespace_path = "fuchsia"
sources = [
"font_provider.fidl",
]
deps = [
":mem",
]
}
fuchsia_sdk_fidl_pkg("gfx") {
namespace = "fuchsia.ui"
namespace_path = "fuchsia/ui"
......
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