diff --git a/skia/BUILD.gn b/skia/BUILD.gn index 6db6d7b18769c5..767b496308b17c 100644 --- a/skia/BUILD.gn +++ b/skia/BUILD.gn @@ -485,13 +485,13 @@ component("skia") { if (is_fuchsia) { sources += [ "//third_party/skia/src/ports/SkFontMgr_custom.cpp", + "//third_party/skia/src/ports/SkFontMgr_fuchsia.cpp", "ext/fontmgr_default_fuchsia.cc", "ext/fontmgr_default_fuchsia.h", - "ext/fontmgr_fuchsia.cc", - "ext/fontmgr_fuchsia.h", ] deps += [ "//third_party/fuchsia-sdk/sdk:fonts", + "//third_party/fuchsia-sdk/sdk:zx", "//third_party/icu:icuuc", ] } diff --git a/skia/ext/fontmgr_default_fuchsia.cc b/skia/ext/fontmgr_default_fuchsia.cc index 379a00c8662bb4..42702d671bcf8f 100644 --- a/skia/ext/fontmgr_default_fuchsia.cc +++ b/skia/ext/fontmgr_default_fuchsia.cc @@ -7,7 +7,8 @@ #include #include "base/fuchsia/component_context.h" -#include "skia/ext/fontmgr_fuchsia.h" +#include "third_party/skia/include/core/SkFontMgr.h" +#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h" namespace { // This is a purposefully leaky pointer that has ownership of the FontMgr. @@ -23,7 +24,7 @@ SK_API sk_sp SkFontMgr::Factory() { if (g_default_fontmgr) { return sk_ref_sp(g_default_fontmgr); } - return sk_make_sp( + return SkFontMgr_New_Fuchsia( base::fuchsia::ComponentContext::GetDefault() ->ConnectToServiceSync()); } diff --git a/skia/ext/fontmgr_fuchsia.cc b/skia/ext/fontmgr_fuchsia.cc deleted file mode 100644 index 3c9a60fed801c4..00000000000000 --- a/skia/ext/fontmgr_fuchsia.cc +++ /dev/null @@ -1,339 +0,0 @@ -// 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 - -#include - -#include "base/bind.h" -#include "base/callback.h" -#include "base/containers/small_map.h" -#include "base/fuchsia/fuchsia_logging.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_checker.h" -#include "third_party/icu/source/common/unicode/uchar.h" -#include "third_party/skia/src/core/SkFontDescriptor.h" -#include "third_party/skia/src/core/SkMakeUnique.h" -#include "third_party/skia/src/ports/SkFontHost_FreeType_common.h" -#include "third_party/skia/src/ports/SkFontMgr_custom.h" - -namespace skia { - -namespace { - -constexpr char kDefaultFont[] = "Roboto"; - -// Currently fonts::Provider doesn't support font aliases. The map below is -// used to map common web fonts to font families that are expected to be present -// in fonts::Provider. -constexpr struct { - const char* font_name_in; - const char* font_name_out; -} kFontMap[] = {{"sans", "Roboto"}, - {"sans-serif", "Roboto"}, - {"arial", "Roboto"}, - {"helvetica", "Roboto"}, - {"roboto", "Roboto"}, - {"roboto slab", "RobotoSlab"}, - {"serif", "RobotoSlab"}, - {"georgia", "RobotoSlab"}, - {"times", "RobotoSlab"}, - {"times roman", "RobotoSlab"}, - {"times new roman", "RobotoSlab"}, - {"roboto mono", "RobotoMono"}, - {"consolas", "RobotoMono"}, - {"courier", "RobotoMono"}, - {"courier new", "RobotoMono"}, - {"monospace", "RobotoMono"}}; - -fuchsia::fonts::Slant ToFontSlant(SkFontStyle::Slant slant) { - return (slant == SkFontStyle::kItalic_Slant) ? fuchsia::fonts::Slant::ITALIC - : fuchsia::fonts::Slant::UPRIGHT; -} - -void UnmapMemory(const void* buffer, void* context) { - const uintptr_t size = reinterpret_cast(context); - zx::vmar::root_self()->unmap(reinterpret_cast(buffer), size); -} - -sk_sp BufferToSkData(fuchsia::mem::Buffer data) { - uintptr_t buffer = 0; - zx_status_t status = zx::vmar::root_self()->map( - 0, data.vmo, 0, data.size, ZX_VM_FLAG_PERM_READ, &buffer); - if (status != ZX_OK) { - ZX_DLOG(ERROR, status) << "zx_vmar_map"; - return nullptr; - } - - return SkData::MakeWithProc(reinterpret_cast(buffer), data.size, - UnmapMemory, reinterpret_cast(data.size)); -} - -// SkTypeface that notifies FontCache when it is being destroyed. -class CachedTypeface : public SkTypeface_Stream { - public: - CachedTypeface(std::unique_ptr font_data, - const SkFontStyle& style, - bool is_fixed_pitch, - const SkString family_name, - base::OnceClosure on_deleted) - : SkTypeface_Stream(std::move(font_data), - style, - is_fixed_pitch, - /*sys_font=*/true, - family_name), - on_deleted_(std::move(on_deleted)) {} - - ~CachedTypeface() override { - if (on_deleted_) - std::move(on_deleted_).Run(); - } - - private: - base::OnceClosure on_deleted_; - - DISALLOW_COPY_AND_ASSIGN(CachedTypeface); -}; - -sk_sp CreateTypefaceFromSkStream( - std::unique_ptr stream, - const SkFontArguments& args, - base::OnceClosure on_deleted) { - using Scanner = SkTypeface_FreeType::Scanner; - Scanner scanner; - bool is_fixed_pitch; - SkFontStyle style; - SkString name; - Scanner::AxisDefinitions axis_definitions; - if (!scanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, - &is_fixed_pitch, &axis_definitions)) { - return nullptr; - } - - const SkFontArguments::VariationPosition position = - args.getVariationDesignPosition(); - SkAutoSTMalloc<4, SkFixed> axis_values(axis_definitions.count()); - Scanner::computeAxisValues(axis_definitions, position, axis_values, name); - - auto font_data = - std::make_unique(std::move(stream), args.getCollectionIndex(), - axis_values.get(), axis_definitions.count()); - return sk_make_sp(std::move(font_data), style, is_fixed_pitch, - name, std::move(on_deleted)); -} - -sk_sp CreateTypefaceFromBuffer(fuchsia::mem::Buffer buffer, - base::OnceClosure on_deleted) { - sk_sp data = BufferToSkData(std::move(buffer)); - if (!data) - return nullptr; - - // TODO(https://crbug.com/800156): Initialize font arguments with font index - // when font collection support is implemented in Provider. - SkFontArguments args; - - return CreateTypefaceFromSkStream( - std::make_unique(std::move(data)), args, - std::move(on_deleted)); -} - -} // namespace - -class FuchsiaFontManager::FontCache { - public: - FontCache(); - ~FontCache(); - - sk_sp GetTypefaceFromBuffer(fuchsia::mem::Buffer buffer); - - private: - void OnTypefaceDeleted(zx_koid_t vmo_koid); - - THREAD_CHECKER(thread_checker_); - - // SkTypeface cache. They key is koid of the VMO that contains the typeface. - // This allows to reuse previously-created SkTypeface when fonts::Provider - // returns FontData with the same VMO. - base::small_map> typefaces_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(FontCache); -}; - -FuchsiaFontManager::FontCache::FontCache() : weak_factory_(this) {} - -FuchsiaFontManager::FontCache::~FontCache() = default; - -sk_sp FuchsiaFontManager::FontCache::GetTypefaceFromBuffer( - fuchsia::mem::Buffer buffer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - zx_info_handle_basic_t vmo_info; - zx_status_t status = buffer.vmo.get_info(ZX_INFO_HANDLE_BASIC, &vmo_info, - sizeof(vmo_info), nullptr, nullptr); - if (status != ZX_OK) { - ZX_DLOG(ERROR, status) << "zx_object_get_info"; - return nullptr; - } - - sk_sp result; - SkTypeface** cached_typeface = &(typefaces_[vmo_info.koid]); - if (*cached_typeface) { - result = sk_ref_sp(*cached_typeface); - } else { - result = CreateTypefaceFromBuffer( - std::move(buffer), - base::BindOnce(&FontCache::OnTypefaceDeleted, - weak_factory_.GetWeakPtr(), vmo_info.koid)); - *cached_typeface = result.get(); - } - return result; -} - -void FuchsiaFontManager::FontCache::OnTypefaceDeleted(zx_koid_t vmo_koid) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - bool was_found = typefaces_.erase(vmo_koid) != 0; - DCHECK(was_found); -} - -FuchsiaFontManager::FuchsiaFontManager( - fuchsia::fonts::ProviderSyncPtr font_provider) - : font_provider_(std::move(font_provider)), font_cache_(new FontCache()) { - for (auto& m : kFontMap) { - font_map_[m.font_name_in] = m.font_name_out; - } - - // Get default font. - default_typeface_.reset(onMatchFamilyStyle(kDefaultFont, SkFontStyle())); - if (!default_typeface_) { - default_typeface_ = sk_make_sp(); - LOG(ERROR) << "Failed to get default font from fonts::Provider."; - } -} - -FuchsiaFontManager::~FuchsiaFontManager() = default; - -int FuchsiaFontManager::onCountFamilies() const { - NOTREACHED(); - return 0; -} - -void FuchsiaFontManager::onGetFamilyName(int index, - SkString* family_name) const { - NOTREACHED(); -} - -SkFontStyleSet* FuchsiaFontManager::onCreateStyleSet(int index) const { - NOTREACHED(); - return nullptr; -} - -SkFontStyleSet* FuchsiaFontManager::onMatchFamily( - const char family_name[]) const { - NOTREACHED(); - return nullptr; -} - -SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( - const char family_name[], - const SkFontStyle& style) const { - std::string family_name_lowercase = base::ToLowerASCII(family_name); - - fuchsia::fonts::Request request; - auto it = font_map_.find(family_name_lowercase); - request.family = (it != font_map_.end()) ? it->second.c_str() : family_name; - request.weight = style.weight(); - request.width = style.width(); - request.slant = ToFontSlant(style.slant()); - request.language = fidl::VectorPtr::New(0); - - fuchsia::fonts::ResponsePtr response; - zx_status_t status = font_provider_->GetFont(std::move(request), &response); - if (status != ZX_OK) { - ZX_DLOG(ERROR, status) << "Failed to query font provider."; - } else if (response) { - sk_sp result = - font_cache_->GetTypefaceFromBuffer(std::move(response->buffer)); - if (result) - return result.release(); - - LOG(ERROR) << "fonts::Provider returned invalid FontData for " - << family_name; - } - - // If Sans was requested and we failed to get a valid response from - // fonts::Provider then return |default_typeface_|. blink::FontCache queries - // Sans as a last-resort font. Returning |default_typeface_| here ensures that - // the renderer doesn't crash when fonts::Provider stops working. - if (family_name_lowercase == "sans") { - // Copy |default_typeface_| to increment ref-count before returning it. - sk_sp result = default_typeface_; - return result.release(); - } - - return nullptr; -} - -SkTypeface* FuchsiaFontManager::onMatchFamilyStyleCharacter( - const char family_name[], - const SkFontStyle& style, - const char* bcp47[], - int bcp47Count, - SkUnichar character) const { - if (u_hasBinaryProperty(character, UCHAR_EMOJI)) - return onMatchFamilyStyle("Noto Color Emoji", style); - - return nullptr; -} - -SkTypeface* FuchsiaFontManager::onMatchFaceStyle( - const SkTypeface* typeface, - const SkFontStyle& style) const { - NOTREACHED(); - return nullptr; -} - -sk_sp FuchsiaFontManager::onMakeFromData(sk_sp data, - int ttc_index) const { - return makeFromStream(std::make_unique(std::move(data)), - ttc_index); -} - -sk_sp FuchsiaFontManager::onMakeFromStreamIndex( - std::unique_ptr stream, - int ttc_index) const { - return makeFromStream(std::move(stream), - SkFontArguments().setCollectionIndex(ttc_index)); -} - -sk_sp FuchsiaFontManager::onMakeFromStreamArgs( - std::unique_ptr stream, - const SkFontArguments& args) const { - return CreateTypefaceFromSkStream(std::move(stream), args, - /*on_deleted=*/base::OnceClosure()); -} - -sk_sp FuchsiaFontManager::onMakeFromFile(const char path[], - int ttc_index) const { - NOTREACHED(); - return nullptr; -} - -sk_sp FuchsiaFontManager::onLegacyMakeTypeface( - const char family_name[], - SkFontStyle style) const { - sk_sp typeface; - - if (family_name) - typeface.reset(this->onMatchFamilyStyle(family_name, style)); - - return typeface; -} - -} // namespace skia diff --git a/skia/ext/fontmgr_fuchsia.h b/skia/ext/fontmgr_fuchsia.h deleted file mode 100644 index cb129979cace55..00000000000000 --- a/skia/ext/fontmgr_fuchsia.h +++ /dev/null @@ -1,70 +0,0 @@ -// 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 - -#include - -#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 SK_API FuchsiaFontManager : public SkFontMgr { - public: - explicit FuchsiaFontManager(fuchsia::fonts::ProviderSyncPtr 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 onMakeFromData(sk_sp, int ttc_index) const override; - sk_sp onMakeFromStreamIndex(std::unique_ptr, - int ttc_index) const override; - sk_sp onMakeFromStreamArgs(std::unique_ptr, - const SkFontArguments&) const override; - sk_sp onMakeFromFile(const char path[], - int ttc_index) const override; - sk_sp onLegacyMakeTypeface(const char family_name[], - SkFontStyle) const override; - - private: - class FontCache; - - fuchsia::fonts::ProviderSyncPtr font_provider_; - - // Map applied to font family name before sending requests to the FontService. - base::flat_map 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 font_cache_; - - sk_sp default_typeface_; - - DISALLOW_COPY_AND_ASSIGN(FuchsiaFontManager); -}; - -} // namespace skia - -#endif // SKIA_EXT_FONTMGR_FUCHSIA_H_ diff --git a/skia/ext/fontmgr_fuchsia_unittest.cc b/skia/ext/fontmgr_fuchsia_unittest.cc index 8053a03823a30c..a5381b83b698a8 100644 --- a/skia/ext/fontmgr_fuchsia_unittest.cc +++ b/skia/ext/fontmgr_fuchsia_unittest.cc @@ -2,126 +2,28 @@ // 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 #include -#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/fuchsia/component_context.h" #include "base/path_service.h" -#include "base/task_runner.h" -#include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkFontMgr.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h" namespace skia { -namespace { - -constexpr zx_rights_t kFontDataRights = - ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_MAP; - -fuchsia::mem::Buffer LoadFont(const base::FilePath& file_path) { - std::string file_content; - CHECK(ReadFileToString(file_path, &file_content)); - fuchsia::mem::Buffer buffer; - zx_status_t status = zx::vmo::create(file_content.size(), 0, &buffer.vmo); - ZX_CHECK(status == ZX_OK, status); - status = buffer.vmo.write(file_content.data(), 0, file_content.size()); - ZX_CHECK(status == ZX_OK, status); - buffer.size = file_content.size(); - return buffer; -} - -class MockFontProvider : public fuchsia::fonts::Provider { - 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::Provider implementation. - void GetFont(fuchsia::fonts::Request request, - GetFontCallback callback) override { - fuchsia::mem::Buffer* font_buffer = nullptr; - if (*request.family == "Roboto") { - font_buffer = &roboto_; - } else if (*request.family == "RobotoSlab") { - font_buffer = &roboto_slab_; - } - - if (!font_buffer) { - callback(nullptr); - return; - } - - auto response = fuchsia::fonts::Response::New(); - EXPECT_EQ( - font_buffer->vmo.duplicate(kFontDataRights, &(response->buffer.vmo)), - ZX_OK); - response->buffer.size = font_buffer->size; - callback(std::move(response)); - } - void GetFamilyInfo(fidl::StringPtr family, - GetFamilyInfoCallback callback) override {} - - private: - fuchsia::mem::Buffer roboto_; - fuchsia::mem::Buffer 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 request) { - provider_thread_.task_runner()->PostTask( - FROM_HERE, base::BindOnce(&MockFontProviderService::DoBind, - base::Unretained(this), std::move(request))); - } - - private: - void DoBind(fidl::InterfaceRequest request) { - provider_binding_ = - std::make_unique>( - &provider_, std::move(request)); - } - - base::Thread provider_thread_; - - MockFontProvider provider_; - std::unique_ptr> provider_binding_; -}; - -} // namespace - +// Tests for SkFontMgr_Fuchsia in Skia. class FuchsiaFontManagerTest : public testing::Test { public: FuchsiaFontManagerTest() { - fuchsia::fonts::ProviderSyncPtr font_provider; - font_provider_service_.Bind(font_provider.NewRequest()); - font_manager_ = sk_make_sp(std::move(font_provider)); + font_manager_ = SkFontMgr_New_Fuchsia( + base::fuchsia::ComponentContext::GetDefault() + ->ConnectToServiceSync()); } protected: - MockFontProviderService font_provider_service_; sk_sp font_manager_; }; @@ -129,6 +31,8 @@ class FuchsiaFontManagerTest : public testing::Test { TEST_F(FuchsiaFontManagerTest, Caching) { sk_sp sans( font_manager_->matchFamilyStyle("sans", SkFontStyle())); + EXPECT_TRUE(sans); + sk_sp sans2( font_manager_->matchFamilyStyle("sans", SkFontStyle()));