mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[fuchsia] Migrate from custom FuchsiaFontManager to SkFontMgr_fuchsia (#10700)
Use Skia's own implementation of SkFontMgr for Fuchsia, for consistency with other Skia clients on Fuchsia. FL-290
This commit is contained in:
parent
e0beaff619
commit
70de3ec2c3
@ -897,9 +897,6 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/compositor_context.cc
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/compositor_context.h
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.cc
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/engine.h
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_font_manager.cc
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_font_manager.h
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/fuchsia_font_manager_unittest.cc
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.cc
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.h
|
||||
FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart
|
||||
|
||||
@ -56,8 +56,6 @@ template("flutter_runner") {
|
||||
"compositor_context.h",
|
||||
"engine.cc",
|
||||
"engine.h",
|
||||
"fuchsia_font_manager.cc",
|
||||
"fuchsia_font_manager.h",
|
||||
"isolate_configurator.cc",
|
||||
"isolate_configurator.h",
|
||||
"logging.h",
|
||||
@ -128,6 +126,7 @@ template("flutter_runner") {
|
||||
"$fuchsia_sdk_root/pkg:zx",
|
||||
"$fuchsia_sdk_root/pkg/lib/sys/cpp",
|
||||
"$fuchsia_sdk_root/pkg/lib/vfs/cpp",
|
||||
"//third_party/skia",
|
||||
"//third_party/tonic",
|
||||
] + extra_deps
|
||||
|
||||
|
||||
@ -14,11 +14,10 @@
|
||||
#include "flutter/runtime/dart_vm_lifecycle.h"
|
||||
#include "flutter/shell/common/rasterizer.h"
|
||||
#include "flutter/shell/common/run_configuration.h"
|
||||
#include "runtime/dart/utils/files.h"
|
||||
|
||||
#include "fuchsia_font_manager.h"
|
||||
#include "platform_view.h"
|
||||
#include "runtime/dart/utils/files.h"
|
||||
#include "task_runner_adapter.h"
|
||||
#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
|
||||
#include "thread.h"
|
||||
|
||||
namespace flutter_runner {
|
||||
@ -275,7 +274,7 @@ Engine::Engine(Delegate& delegate,
|
||||
|
||||
// Set default font manager.
|
||||
engine->GetFontCollection().GetFontCollection()->SetDefaultFontManager(
|
||||
sk_make_sp<txt::FuchsiaFontManager>(std::move(sync_font_provider)));
|
||||
SkFontMgr_New_Fuchsia(std::move(sync_font_provider)));
|
||||
|
||||
if (engine->Run(std::move(run_configuration)) ==
|
||||
flutter::Engine::RunStatus::Failure) {
|
||||
|
||||
@ -1,454 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 "fuchsia_font_manager.h"
|
||||
|
||||
#include <lib/fit/function.h>
|
||||
#include <lib/zx/vmar.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "logging.h"
|
||||
#include "runtime/dart/utils/inlines.h"
|
||||
#include "runtime/dart/utils/vmo.h"
|
||||
#include "third_party/icu/source/common/unicode/uchar.h"
|
||||
|
||||
namespace txt {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr char kDefaultFontFamily[] = "Roboto";
|
||||
|
||||
void UnmapMemory(const void* buffer, uint64_t size) {
|
||||
static_assert(sizeof(void*) == sizeof(uint64_t), "pointers aren't 64-bit");
|
||||
zx::vmar::root_self()->unmap(reinterpret_cast<uintptr_t>(buffer), size);
|
||||
}
|
||||
|
||||
struct ReleaseSkDataContext {
|
||||
uint64_t buffer_size;
|
||||
int buffer_id;
|
||||
fit::function<void()> release_proc;
|
||||
|
||||
ReleaseSkDataContext(uint64_t buffer_size,
|
||||
int buffer_id,
|
||||
fit::function<void()> release_proc)
|
||||
: buffer_size(buffer_size),
|
||||
buffer_id(buffer_id),
|
||||
release_proc(std::move(release_proc)) {}
|
||||
};
|
||||
|
||||
void ReleaseSkData(const void* buffer, void* context) {
|
||||
auto skdata_context = reinterpret_cast<ReleaseSkDataContext*>(context);
|
||||
DEBUG_CHECK(skdata_context != nullptr, LOG_TAG, "");
|
||||
UnmapMemory(buffer, skdata_context->buffer_size);
|
||||
skdata_context->release_proc();
|
||||
delete skdata_context;
|
||||
}
|
||||
|
||||
sk_sp<SkData> MakeSkDataFromBuffer(const fuchsia::mem::Buffer& data,
|
||||
int buffer_id,
|
||||
fit::function<void()> release_proc) {
|
||||
bool is_valid;
|
||||
zx_status_t status = dart_utils::IsSizeValid(data, &is_valid);
|
||||
if (!is_valid || data.size > std::numeric_limits<size_t>::max()) {
|
||||
return nullptr;
|
||||
}
|
||||
uint64_t size = data.size;
|
||||
uintptr_t buffer = 0;
|
||||
status = zx::vmar::root_self()->map(0, data.vmo, 0, size, ZX_VM_PERM_READ,
|
||||
&buffer);
|
||||
if (status != ZX_OK)
|
||||
return nullptr;
|
||||
auto context =
|
||||
new ReleaseSkDataContext(size, buffer_id, std::move(release_proc));
|
||||
return SkData::MakeWithProc(reinterpret_cast<void*>(buffer), size,
|
||||
ReleaseSkData, context);
|
||||
}
|
||||
|
||||
fuchsia::fonts::Slant SkToFuchsiaSlant(SkFontStyle::Slant slant) {
|
||||
switch (slant) {
|
||||
case SkFontStyle::kOblique_Slant:
|
||||
return fuchsia::fonts::Slant::OBLIQUE;
|
||||
case SkFontStyle::kItalic_Slant:
|
||||
return fuchsia::fonts::Slant::ITALIC;
|
||||
case SkFontStyle::kUpright_Slant:
|
||||
default:
|
||||
return fuchsia::fonts::Slant::UPRIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
SkFontStyle::Slant FuchsiaToSkSlant(fuchsia::fonts::Slant slant) {
|
||||
switch (slant) {
|
||||
case fuchsia::fonts::Slant::OBLIQUE:
|
||||
return SkFontStyle::kOblique_Slant;
|
||||
case fuchsia::fonts::Slant::ITALIC:
|
||||
return SkFontStyle::kItalic_Slant;
|
||||
case fuchsia::fonts::Slant::UPRIGHT:
|
||||
default:
|
||||
return SkFontStyle::kUpright_Slant;
|
||||
}
|
||||
}
|
||||
|
||||
fidl::VectorPtr<std::string> BuildLanguageList(const char* bcp47[],
|
||||
int bcp47_count) {
|
||||
DEBUG_CHECK(bcp47 != nullptr || bcp47_count == 0, LOG_TAG, "");
|
||||
auto languages = fidl::VectorPtr<std::string>::New(0);
|
||||
for (int i = 0; i < bcp47_count; i++) {
|
||||
languages.push_back(bcp47[i]);
|
||||
}
|
||||
return languages;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> CreateTypefaceFromSkData(sk_sp<SkData> data, int font_index) {
|
||||
return SkFontMgr::RefDefault()->makeFromData(std::move(data), font_index);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class FuchsiaFontManager::TypefaceCache {
|
||||
public:
|
||||
TypefaceCache() {}
|
||||
~TypefaceCache();
|
||||
|
||||
// Get an SkTypeface with the given buffer id, font index, and buffer
|
||||
// data. Creates a new SkTypeface if one does not already exist.
|
||||
sk_sp<SkTypeface> GetOrCreateTypeface(
|
||||
int buffer_id,
|
||||
int font_index,
|
||||
const fuchsia::mem::Buffer& buffer) const;
|
||||
|
||||
// Callback called when an SkData with the given buffer id is deleted.
|
||||
void OnSkDataDeleted(int buffer_id) const;
|
||||
|
||||
private:
|
||||
// Used to identify an SkTypeface in the cache.
|
||||
struct TypefaceId {
|
||||
int buffer_id;
|
||||
int font_index;
|
||||
|
||||
// Needed by std::unordered_map.
|
||||
bool operator==(const TypefaceId& other) const {
|
||||
return (buffer_id == other.buffer_id && font_index == other.font_index);
|
||||
}
|
||||
|
||||
// Used for debugging.
|
||||
friend std::ostream& operator<<(std::ostream& os, const TypefaceId& id) {
|
||||
return os << "TypfaceId: [buffer_id: " << id.buffer_id
|
||||
<< ", font_index: " << id.font_index << "]";
|
||||
}
|
||||
};
|
||||
|
||||
// Needed by std::unordered_map.
|
||||
struct TypefaceIdHash {
|
||||
std::size_t operator()(const TypefaceId& id) const {
|
||||
return std::hash<int>()(id.buffer_id) ^
|
||||
(std::hash<int>()(id.font_index) << 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Try to get an SkData with the given buffer id from the cache. If an
|
||||
// SkData is not found, create it and add it to the cache.
|
||||
sk_sp<SkData> GetOrCreateSkData(int buffer_id,
|
||||
const fuchsia::mem::Buffer& buffer) const;
|
||||
|
||||
// Create a new SkTypeface for the given TypefaceId and SkData and add it to
|
||||
// the cache.
|
||||
sk_sp<SkTypeface> CreateSkTypeface(TypefaceId id, sk_sp<SkData> buffer) const;
|
||||
|
||||
mutable std::unordered_map<TypefaceId, SkTypeface*, TypefaceIdHash>
|
||||
typeface_cache_;
|
||||
mutable std::unordered_map<int, std::shared_ptr<BufferHolder>> buffer_cache_;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
TypefaceCache(const TypefaceCache&) = delete;
|
||||
TypefaceCache& operator=(const TypefaceCache&) = delete;
|
||||
};
|
||||
|
||||
class FuchsiaFontManager::BufferHolder {
|
||||
public:
|
||||
BufferHolder(const TypefaceCache* cache, int buffer_id)
|
||||
: cache_(cache), buffer_id_(buffer_id) {}
|
||||
~BufferHolder() {}
|
||||
|
||||
void SetData(SkData* data) { data_ = data; }
|
||||
|
||||
SkData* GetData() const { return data_; }
|
||||
|
||||
void OnDataDeleted() { cache_->OnSkDataDeleted(buffer_id_); }
|
||||
|
||||
private:
|
||||
const TypefaceCache* cache_;
|
||||
int buffer_id_;
|
||||
SkData* data_;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
BufferHolder(const BufferHolder&) = delete;
|
||||
BufferHolder& operator=(const BufferHolder&) = delete;
|
||||
};
|
||||
|
||||
FuchsiaFontManager::TypefaceCache::~TypefaceCache() {
|
||||
for (const auto& entry : typeface_cache_) {
|
||||
entry.second->weak_unref();
|
||||
}
|
||||
}
|
||||
|
||||
void FuchsiaFontManager::TypefaceCache::OnSkDataDeleted(int buffer_id) const {
|
||||
bool was_found = buffer_cache_.erase(buffer_id) != 0;
|
||||
DEBUG_CHECK(was_found, LOG_TAG, "");
|
||||
}
|
||||
|
||||
sk_sp<SkData> FuchsiaFontManager::TypefaceCache::GetOrCreateSkData(
|
||||
int buffer_id,
|
||||
const fuchsia::mem::Buffer& buffer) const {
|
||||
auto iter = buffer_cache_.find(buffer_id);
|
||||
if (iter != buffer_cache_.end()) {
|
||||
return sk_ref_sp(iter->second->GetData());
|
||||
}
|
||||
auto holder = std::make_shared<BufferHolder>(this, buffer_id);
|
||||
std::weak_ptr<BufferHolder> weak_holder = holder;
|
||||
auto data = MakeSkDataFromBuffer(buffer, buffer_id, [weak_holder]() {
|
||||
if (auto holder = weak_holder.lock()) {
|
||||
holder->OnDataDeleted();
|
||||
}
|
||||
});
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
holder->SetData(data.get());
|
||||
buffer_cache_[buffer_id] = std::move(holder);
|
||||
return data;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::TypefaceCache::CreateSkTypeface(
|
||||
TypefaceId id,
|
||||
sk_sp<SkData> buffer) const {
|
||||
auto result = CreateTypefaceFromSkData(std::move(buffer), id.font_index);
|
||||
result->weak_ref();
|
||||
typeface_cache_[id] = result.get();
|
||||
return result;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::TypefaceCache::GetOrCreateTypeface(
|
||||
int buffer_id,
|
||||
int font_index,
|
||||
const fuchsia::mem::Buffer& buffer) const {
|
||||
auto id = TypefaceId{buffer_id, font_index};
|
||||
auto iter = typeface_cache_.find(id);
|
||||
if (iter != typeface_cache_.end()) {
|
||||
if (iter->second->try_ref()) {
|
||||
return sk_ref_sp(iter->second);
|
||||
} else {
|
||||
iter->second->weak_unref();
|
||||
typeface_cache_.erase(iter);
|
||||
}
|
||||
}
|
||||
sk_sp<SkData> data = GetOrCreateSkData(buffer_id, buffer);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
return CreateSkTypeface(id, std::move(data));
|
||||
}
|
||||
|
||||
class FuchsiaFontManager::FontStyleSet : public SkFontStyleSet {
|
||||
public:
|
||||
FontStyleSet(sk_sp<FuchsiaFontManager> font_manager,
|
||||
std::string family_name,
|
||||
std::vector<SkFontStyle> styles)
|
||||
: font_manager_(font_manager),
|
||||
family_name_(family_name),
|
||||
styles_(styles) {}
|
||||
|
||||
~FontStyleSet() override = default;
|
||||
|
||||
int count() override { return styles_.size(); }
|
||||
|
||||
void getStyle(int index, SkFontStyle* style, SkString* style_name) override {
|
||||
DEBUG_CHECK(index >= 0 && index < static_cast<int>(styles_.size()), LOG_TAG,
|
||||
"");
|
||||
if (style)
|
||||
*style = styles_[index];
|
||||
|
||||
// We don't have style names. Return an empty name.
|
||||
if (style_name)
|
||||
style_name->reset();
|
||||
}
|
||||
|
||||
SkTypeface* createTypeface(int index) override {
|
||||
DEBUG_CHECK(index >= 0 && index < static_cast<int>(styles_.size()), LOG_TAG,
|
||||
"");
|
||||
|
||||
if (typefaces_.empty())
|
||||
typefaces_.resize(styles_.size());
|
||||
|
||||
if (!typefaces_[index]) {
|
||||
typefaces_[index] = font_manager_->FetchTypeface(
|
||||
family_name_.c_str(), styles_[index], /*bcp47=*/nullptr,
|
||||
/*bcp47_count=*/0, /*character=*/0,
|
||||
fuchsia::fonts::REQUEST_FLAG_NO_FALLBACK |
|
||||
fuchsia::fonts::REQUEST_FLAG_EXACT_MATCH);
|
||||
}
|
||||
|
||||
return SkSafeRef(typefaces_[index].get());
|
||||
}
|
||||
|
||||
SkTypeface* matchStyle(const SkFontStyle& pattern) override {
|
||||
return matchStyleCSS3(pattern);
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<FuchsiaFontManager> font_manager_;
|
||||
std::string family_name_;
|
||||
std::vector<SkFontStyle> styles_;
|
||||
std::vector<sk_sp<SkTypeface>> typefaces_;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
FontStyleSet(const FontStyleSet&) = delete;
|
||||
FontStyleSet& operator=(const FontStyleSet&) = delete;
|
||||
};
|
||||
|
||||
FuchsiaFontManager::FuchsiaFontManager(fuchsia::fonts::ProviderSyncPtr provider)
|
||||
: font_provider_(std::move(provider)),
|
||||
typeface_cache_(new FuchsiaFontManager::TypefaceCache()) {}
|
||||
|
||||
FuchsiaFontManager::~FuchsiaFontManager() = default;
|
||||
|
||||
int FuchsiaFontManager::onCountFamilies() const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FuchsiaFontManager::onGetFamilyName(int index,
|
||||
SkString* familyName) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
}
|
||||
|
||||
SkFontStyleSet* FuchsiaFontManager::onCreateStyleSet(int index) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkFontStyleSet* FuchsiaFontManager::onMatchFamily(
|
||||
const char family_name[]) const {
|
||||
fuchsia::fonts::FamilyInfoPtr family_info;
|
||||
int err = font_provider_->GetFamilyInfo(family_name, &family_info);
|
||||
if (err != ZX_OK) {
|
||||
#ifndef NDEBUG
|
||||
FX_LOGF(ERROR, LOG_TAG,
|
||||
"Error fetching family from provider [err=%d]. Did "
|
||||
"you run Flutter in an environment that has a font manager?",
|
||||
err);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!family_info)
|
||||
return nullptr;
|
||||
|
||||
std::vector<SkFontStyle> styles;
|
||||
for (auto& style : family_info->styles) {
|
||||
styles.push_back(
|
||||
SkFontStyle(style.weight, style.width, FuchsiaToSkSlant(style.slant)));
|
||||
}
|
||||
|
||||
return new FontStyleSet(sk_ref_sp(this), family_info->name,
|
||||
std::move(styles));
|
||||
}
|
||||
|
||||
SkTypeface* FuchsiaFontManager::onMatchFamilyStyle(
|
||||
const char familyName[],
|
||||
const SkFontStyle& style) const {
|
||||
sk_sp<SkTypeface> typeface = FetchTypeface(familyName, style, nullptr, 0, 0);
|
||||
return typeface.release();
|
||||
}
|
||||
|
||||
SkTypeface* FuchsiaFontManager::onMatchFamilyStyleCharacter(
|
||||
const char familyName[],
|
||||
const SkFontStyle& style,
|
||||
const char* bcp47[],
|
||||
int bcp47_count,
|
||||
SkUnichar character) const {
|
||||
sk_sp<SkTypeface> typeface =
|
||||
FetchTypeface(kDefaultFontFamily, style, bcp47, bcp47_count, character);
|
||||
return typeface.release();
|
||||
}
|
||||
|
||||
SkTypeface* FuchsiaFontManager::onMatchFaceStyle(const SkTypeface*,
|
||||
const SkFontStyle&) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromData(sk_sp<SkData>,
|
||||
int ttcIndex) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromStreamIndex(
|
||||
std::unique_ptr<SkStreamAsset>,
|
||||
int ttcIndex) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromStreamArgs(
|
||||
std::unique_ptr<SkStreamAsset>,
|
||||
const SkFontArguments&) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::onMakeFromFile(const char path[],
|
||||
int ttcIndex) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::onLegacyMakeTypeface(
|
||||
const char familyName[],
|
||||
SkFontStyle) const {
|
||||
DEBUG_CHECK(false, LOG_TAG, "");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> FuchsiaFontManager::FetchTypeface(const char family_name[],
|
||||
const SkFontStyle& style,
|
||||
const char* bcp47[],
|
||||
int bcp47_count,
|
||||
SkUnichar character,
|
||||
uint32_t flags) const {
|
||||
TRACE_EVENT0("flutter", "FuchsiaFontManager::FetchTypeface");
|
||||
fuchsia::fonts::Request request;
|
||||
request.family = family_name;
|
||||
request.weight = style.weight();
|
||||
request.width = style.width();
|
||||
request.slant = SkToFuchsiaSlant(style.slant());
|
||||
request.language = BuildLanguageList(bcp47, bcp47_count);
|
||||
request.character = character;
|
||||
request.flags = flags;
|
||||
|
||||
fuchsia::fonts::ResponsePtr response;
|
||||
int err = font_provider_->GetFont(std::move(request), &response);
|
||||
if (err != ZX_OK) {
|
||||
#ifndef NDEBUG
|
||||
FX_LOGF(ERROR, LOG_TAG,
|
||||
"Error fetching font from provider [err=%d]. Did "
|
||||
"you run Flutter in an environment that has a font manager?",
|
||||
err);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The service may return null response if there is no font matching the
|
||||
// request.
|
||||
if (!response) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return typeface_cache_->GetOrCreateTypeface(
|
||||
response->buffer_id, response->font_index, response->buffer);
|
||||
}
|
||||
|
||||
} // namespace txt
|
||||
@ -1,92 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 TXT_FUCHSIA_FONT_MANAGER_H_
|
||||
#define TXT_FUCHSIA_FONT_MANAGER_H_
|
||||
|
||||
#include <fuchsia/fonts/cpp/fidl.h>
|
||||
#include <memory>
|
||||
|
||||
#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 txt {
|
||||
|
||||
class FuchsiaFontManager final : public SkFontMgr {
|
||||
public:
|
||||
FuchsiaFontManager(fuchsia::fonts::ProviderSyncPtr provider);
|
||||
|
||||
~FuchsiaFontManager() override;
|
||||
|
||||
protected:
|
||||
// |SkFontMgr|
|
||||
int onCountFamilies() const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
void onGetFamilyName(int index, SkString* familyName) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
SkFontStyleSet* onCreateStyleSet(int index) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
SkTypeface* onMatchFamilyStyle(const char familyName[],
|
||||
const SkFontStyle&) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
|
||||
const SkFontStyle&,
|
||||
const char* bcp47[],
|
||||
int bcp47Count,
|
||||
SkUnichar character) const override;
|
||||
// |SkFontMgr|
|
||||
SkTypeface* onMatchFaceStyle(const SkTypeface*,
|
||||
const SkFontStyle&) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
|
||||
int ttcIndex) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
|
||||
const SkFontArguments&) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
sk_sp<SkTypeface> onMakeFromFile(const char path[],
|
||||
int ttcIndex) const override;
|
||||
|
||||
// |SkFontMgr|
|
||||
sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[],
|
||||
SkFontStyle) const override;
|
||||
|
||||
private:
|
||||
class BufferHolder;
|
||||
class TypefaceCache;
|
||||
class FontStyleSet;
|
||||
friend class FontStyleSet;
|
||||
|
||||
sk_sp<SkTypeface> FetchTypeface(const char family_name[],
|
||||
const SkFontStyle& style,
|
||||
const char* bcp47[],
|
||||
int bcp47_count,
|
||||
SkUnichar character,
|
||||
uint32_t flags = 0) const;
|
||||
|
||||
mutable fuchsia::fonts::ProviderSyncPtr font_provider_;
|
||||
std::unique_ptr<TypefaceCache> typeface_cache_;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
FuchsiaFontManager(const FuchsiaFontManager&) = delete;
|
||||
FuchsiaFontManager& operator=(const FuchsiaFontManager&) = delete;
|
||||
};
|
||||
|
||||
} // namespace txt
|
||||
|
||||
#endif // TXT_FUCHSIA_FONT_MANAGER_H_
|
||||
@ -1,202 +0,0 @@
|
||||
// Copyright 2013 The Flutter 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 "topaz/runtime/flutter_runner/fuchsia_font_manager.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <fuchsia/fonts/cpp/fidl.h>
|
||||
#include <fuchsia/sys/cpp/fidl.h>
|
||||
#include <lib/fdio/fd.h>
|
||||
#include <lib/gtest/real_loop_fixture.h>
|
||||
#include <lib/sys/cpp/service_directory.h>
|
||||
#include <lib/zx/channel.h>
|
||||
#include <lib/zx/handle.h>
|
||||
#include <memory>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "third_party/skia/include/core/SkFontMgr.h"
|
||||
#include "third_party/skia/include/core/SkTypeface.h"
|
||||
|
||||
namespace {
|
||||
|
||||
zx::channel CloneChannelFromFileDescriptor(int fd) {
|
||||
zx::handle handle;
|
||||
zx_status_t status = fdio_fd_clone(fd, handle.reset_and_get_address());
|
||||
if (status != ZX_OK)
|
||||
return zx::channel();
|
||||
|
||||
zx_info_handle_basic_t info = {};
|
||||
status =
|
||||
handle.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
|
||||
|
||||
if (status != ZX_OK || info.type != ZX_OBJ_TYPE_CHANNEL)
|
||||
return zx::channel();
|
||||
|
||||
return zx::channel(handle.release());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace txt {
|
||||
|
||||
namespace {
|
||||
|
||||
// A codepoint guaranteed to be unknown in any font/family.
|
||||
constexpr SkUnichar kUnknownUnicodeCharacter = 0xFFF0;
|
||||
|
||||
// Font family to use for tests.
|
||||
constexpr char kTestFontFamily[] = "Roboto";
|
||||
|
||||
// URL for the fonts service.
|
||||
constexpr char kFontsServiceUrl[] =
|
||||
"fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx";
|
||||
|
||||
class FuchsiaFontManagerTest : public gtest::RealLoopFixture {
|
||||
public:
|
||||
FuchsiaFontManagerTest() {
|
||||
auto services = sys::ServiceDirectory::CreateFromNamespace();
|
||||
// Grab launcher and launch font provider.
|
||||
fuchsia::sys::LauncherPtr launcher;
|
||||
services->Connect(launcher.NewRequest());
|
||||
|
||||
zx::channel out_services_request;
|
||||
auto font_services =
|
||||
sys::ServiceDirectory::CreateWithRequest(&out_services_request);
|
||||
auto launch_info_font_service = GetLaunchInfoForFontService();
|
||||
launch_info_font_service.directory_request =
|
||||
std::move(out_services_request);
|
||||
|
||||
launcher->CreateComponent(std::move(launch_info_font_service),
|
||||
font_service_controller_.NewRequest());
|
||||
|
||||
// Connect to the font provider service and then wrap it inside the font
|
||||
// manager we will be testing.
|
||||
fuchsia::fonts::ProviderSyncPtr provider_ptr;
|
||||
font_services->Connect(provider_ptr.NewRequest());
|
||||
|
||||
font_manager_ = sk_make_sp<FuchsiaFontManager>(std::move(provider_ptr));
|
||||
}
|
||||
|
||||
fuchsia::sys::LaunchInfo GetLaunchInfoForFontService() {
|
||||
fuchsia::sys::LaunchInfo launch_info;
|
||||
launch_info.url = kFontsServiceUrl;
|
||||
launch_info.arguments.reset(
|
||||
{"--no-default-fonts", "--font-manifest=/test_fonts/manifest.json"});
|
||||
auto tmp_dir_fd =
|
||||
open("/pkg/data/testdata/test_fonts", O_DIRECTORY | O_RDONLY);
|
||||
launch_info.flat_namespace = fuchsia::sys::FlatNamespace::New();
|
||||
launch_info.flat_namespace->paths.push_back("/test_fonts");
|
||||
launch_info.flat_namespace->directories.push_back(
|
||||
CloneChannelFromFileDescriptor(tmp_dir_fd));
|
||||
close(tmp_dir_fd);
|
||||
return launch_info;
|
||||
}
|
||||
|
||||
protected:
|
||||
fuchsia::sys::ComponentControllerPtr font_service_controller_;
|
||||
sk_sp<SkFontMgr> font_manager_;
|
||||
};
|
||||
|
||||
// Verify that a typeface is returned for a found character.
|
||||
TEST_F(FuchsiaFontManagerTest, ValidResponseWhenCharacterFound) {
|
||||
sk_sp<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
|
||||
"", SkFontStyle(), nullptr, 0, '&'));
|
||||
EXPECT_TRUE(typeface.get() != nullptr);
|
||||
}
|
||||
|
||||
// Verify that a codepoint that doesn't map to a character correctly returns
|
||||
// an empty typeface.
|
||||
TEST_F(FuchsiaFontManagerTest, EmptyResponseWhenCharacterNotFound) {
|
||||
sk_sp<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter(
|
||||
"", SkFontStyle(), nullptr, 0, kUnknownUnicodeCharacter));
|
||||
EXPECT_TRUE(typeface.get() == nullptr);
|
||||
}
|
||||
|
||||
// Verify that SkTypeface objects are cached.
|
||||
TEST_F(FuchsiaFontManagerTest, Caching) {
|
||||
sk_sp<SkTypeface> typeface(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
sk_sp<SkTypeface> typeface2(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
|
||||
// Expect that the same SkTypeface is returned for both requests.
|
||||
EXPECT_EQ(typeface.get(), typeface2.get());
|
||||
|
||||
// Request a different typeface and verify that a different SkTypeface is
|
||||
// returned.
|
||||
sk_sp<SkTypeface> typeface3(
|
||||
font_manager_->matchFamilyStyle("Roboto Slab", SkFontStyle()));
|
||||
EXPECT_NE(typeface.get(), typeface3.get());
|
||||
}
|
||||
|
||||
// Verify that SkTypeface can outlive the manager.
|
||||
TEST_F(FuchsiaFontManagerTest, TypefaceOutlivesManager) {
|
||||
sk_sp<SkTypeface> typeface(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
font_manager_.reset();
|
||||
EXPECT_TRUE(typeface.get() != nullptr);
|
||||
}
|
||||
|
||||
// Verify that we can query a font after releasing a previous instance.
|
||||
TEST_F(FuchsiaFontManagerTest, ReleaseThenCreateAgain) {
|
||||
sk_sp<SkTypeface> typeface(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
EXPECT_TRUE(typeface != nullptr);
|
||||
typeface.reset();
|
||||
|
||||
sk_sp<SkTypeface> typeface2(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
EXPECT_TRUE(typeface2 != nullptr);
|
||||
}
|
||||
|
||||
// Verify that we get a new typeface instance after releasing a previous
|
||||
// instance of the same typeface (i.e. the cache purges the released typeface).
|
||||
TEST_F(FuchsiaFontManagerTest, ReleasedTypefaceIsPurged) {
|
||||
sk_sp<SkTypeface> typeface(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
EXPECT_TRUE(typeface != nullptr);
|
||||
typeface.reset();
|
||||
|
||||
sk_sp<SkTypeface> typeface2(
|
||||
font_manager_->matchFamilyStyle(kTestFontFamily, SkFontStyle()));
|
||||
EXPECT_TRUE(typeface2 != nullptr);
|
||||
EXPECT_NE(typeface.get(), typeface2.get());
|
||||
}
|
||||
|
||||
// Verify that unknown font families are handled correctly.
|
||||
TEST_F(FuchsiaFontManagerTest, MatchUnknownFamily) {
|
||||
SkFontStyleSet* style_set = font_manager_->matchFamily("unknown");
|
||||
EXPECT_TRUE(style_set == nullptr || style_set->count() == 0);
|
||||
}
|
||||
|
||||
// Verify that a style set is returned for a known family.
|
||||
TEST_F(FuchsiaFontManagerTest, MatchKnownFamily) {
|
||||
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
|
||||
EXPECT_GT(style_set->count(), 0);
|
||||
}
|
||||
|
||||
// Verify getting an SkFontStyle from a matched family.
|
||||
TEST_F(FuchsiaFontManagerTest, FontFamilyGetStyle) {
|
||||
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
|
||||
SkFontStyle style;
|
||||
style_set->getStyle(0, &style, nullptr);
|
||||
EXPECT_EQ(style.weight(), 400);
|
||||
EXPECT_EQ(style.width(), 5);
|
||||
EXPECT_EQ(style.slant(), SkFontStyle::kUpright_Slant);
|
||||
}
|
||||
|
||||
// Verify creating a typeface from a matched family.
|
||||
TEST_F(FuchsiaFontManagerTest, FontFamilyCreateTypeface) {
|
||||
SkFontStyleSet* style_set = font_manager_->matchFamily(kTestFontFamily);
|
||||
SkTypeface* typeface = style_set->createTypeface(0);
|
||||
EXPECT_TRUE(typeface != nullptr);
|
||||
SkFontStyle style = typeface->fontStyle();
|
||||
EXPECT_EQ(style.weight(), 400);
|
||||
EXPECT_EQ(style.width(), 5);
|
||||
EXPECT_EQ(style.slant(), SkFontStyle::kUpright_Slant);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace txt
|
||||
@ -16,7 +16,6 @@
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
#include "flutter/lib/ui/text/font_collection.h"
|
||||
#include "flutter/runtime/dart_vm.h"
|
||||
#include "fuchsia_font_manager.h"
|
||||
#include "runtime/dart/utils/vmo.h"
|
||||
#include "runtime/dart/utils/vmservice_object.h"
|
||||
#include "third_party/icu/source/common/unicode/udata.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user