Add SkFontMgr implementation for Fuchsia
The new SkFontMgr implementation will be used by Flutter and Chromium on
Fuchsia.
Change-Id: Ibd60a622282556e8557058e92fe865857f7024f9
Reviewed-on: https://skia-review.googlesource.com/c/173800
Reviewed-by: Ben Wagner <bungeman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index b4cf3d3..0fade34 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -73,6 +73,7 @@
skia_use_freetype && !skia_use_fontconfig
skia_enable_fontmgr_custom_empty = is_fuchsia && skia_use_freetype
skia_enable_fontmgr_android = skia_use_expat && skia_use_freetype
+ skia_enable_fontmgr_fuchsia = is_fuchsia
if (is_android) {
skia_use_vulkan = defined(ndk_api) && ndk_api >= 24
@@ -411,6 +412,18 @@
]
}
+optional("fontmgr_fuchsia") {
+ enabled = skia_enable_fontmgr_fuchsia
+
+ deps = [
+ "//garnet/public/fidl/fuchsia.fonts",
+ ]
+ sources = [
+ "src/ports/SkFontMgr_fuchsia.cpp",
+ "src/ports/SkFontMgr_fuchsia.h",
+ ]
+}
+
optional("fontmgr_empty") {
enabled = skia_enable_fontmgr_empty
sources = [
@@ -854,6 +867,7 @@
":fontmgr_custom_empty",
":fontmgr_empty",
":fontmgr_fontconfig",
+ ":fontmgr_fuchsia",
":heif",
":hsw",
":jpeg",
@@ -983,9 +997,7 @@
}
if (skia_use_fonthost_mac) {
- sources += [
- "src/ports/SkFontHost_mac.cpp",
- ]
+ sources += [ "src/ports/SkFontHost_mac.cpp" ]
}
if (is_mac) {
diff --git a/include/ports/SkFontMgr_fuchsia.h b/include/ports/SkFontMgr_fuchsia.h
new file mode 100644
index 0000000..4bcff82
--- /dev/null
+++ b/include/ports/SkFontMgr_fuchsia.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontMgr_fuchsia_DEFINED
+#define SkFontMgr_fuchsia_DEFINED
+
+#include <fuchsia/fonts/cpp/fidl.h>
+
+#include "SkRefCnt.h"
+
+class SkFontMgr;
+
+SK_API sk_sp<SkFontMgr> SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider);
+
+#endif // SkFontMgr_fuchsia_DEFINED
diff --git a/src/ports/SkFontMgr_fuchsia.cpp b/src/ports/SkFontMgr_fuchsia.cpp
new file mode 100644
index 0000000..81d621a
--- /dev/null
+++ b/src/ports/SkFontMgr_fuchsia.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFontMgr_fuchsia.h"
+
+#include <fuchsia/fonts/cpp/fidl.h>
+#include <lib/zx/vmar.h>
+#include <strings.h>
+#include <memory>
+#include <unordered_map>
+
+#include "third_party/skia/src/core/SkFontDescriptor.h"
+#include "third_party/skia/src/ports/SkFontMgr_custom.h"
+
+#include "SkFontMgr.h"
+#include "SkStream.h"
+#include "SkTypeface.h"
+#include "SkTypefaceCache.h"
+
+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 fBufferSize;
+ std::function<void()> releaseProc;
+
+ ReleaseSkDataContext(uint64_t bufferSize, const std::function<void()>& releaseProc)
+ : fBufferSize(bufferSize), releaseProc(releaseProc) {}
+};
+
+void ReleaseSkData(const void* buffer, void* context) {
+ auto releaseSkDataContext = reinterpret_cast<ReleaseSkDataContext*>(context);
+ SkASSERT(releaseSkDataContext);
+ UnmapMemory(buffer, releaseSkDataContext->fBufferSize);
+ releaseSkDataContext->releaseProc();
+ delete releaseSkDataContext;
+}
+
+sk_sp<SkData> MakeSkDataFromBuffer(const fuchsia::mem::Buffer& data,
+ std::function<void()> release_proc) {
+ uint64_t size = data.size;
+ uintptr_t buffer = 0;
+ zx_status_t 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, 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;
+ }
+}
+
+constexpr struct {
+ const char* fName;
+ fuchsia::fonts::FallbackGroup fFallbackGroup;
+} kFallbackGroupsByName[] = {
+ {"serif", fuchsia::fonts::FallbackGroup::SERIF},
+ {"sans", fuchsia::fonts::FallbackGroup::SANS_SERIF},
+ {"sans-serif", fuchsia::fonts::FallbackGroup::SANS_SERIF},
+ {"mono", fuchsia::fonts::FallbackGroup::MONOSPACE},
+ {"monospace", fuchsia::fonts::FallbackGroup::MONOSPACE},
+ {"cursive", fuchsia::fonts::FallbackGroup::CURSIVE},
+ {"fantasy", fuchsia::fonts::FallbackGroup::FANTASY},
+};
+
+fuchsia::fonts::FallbackGroup GetFallbackGroupByName(const char* name) {
+ if (!name) return fuchsia::fonts::FallbackGroup::NONE;
+ for (auto& group : kFallbackGroupsByName) {
+ if (strcasecmp(group.fName, name) == 0) {
+ return group.fFallbackGroup;
+ }
+ }
+ return fuchsia::fonts::FallbackGroup::NONE;
+}
+
+struct TypefaceId {
+ uint32_t bufferId;
+ uint32_t ttcIndex;
+
+ bool operator==(TypefaceId& other) {
+ return std::tie(bufferId, ttcIndex) == std::tie(other.bufferId, other.ttcIndex);
+ }
+}
+
+constexpr kNullTypefaceId = {0xFFFFFFFF, 0xFFFFFFFF};
+
+class SkTypeface_Fuchsia : public SkTypeface_Stream {
+public:
+ SkTypeface_Fuchsia(std::unique_ptr<SkFontData> fontData, const SkFontStyle& style,
+ bool isFixedPitch, const SkString familyName, TypefaceId id)
+ : SkTypeface_Stream(std::move(fontData), style, isFixedPitch,
+ /*sys_font=*/true, familyName)
+ , fId(id) {}
+
+ TypefaceId id() { return fId; }
+
+private:
+ TypefaceId fId;
+};
+
+sk_sp<SkTypeface> CreateTypefaceFromSkStream(std::unique_ptr<SkStreamAsset> stream,
+ const SkFontArguments& args, TypefaceId id) {
+ using Scanner = SkTypeface_FreeType::Scanner;
+ Scanner scanner;
+ bool isFixedPitch;
+ SkFontStyle style;
+ SkString name;
+ Scanner::AxisDefinitions axisDefinitions;
+ if (!scanner.scanFont(stream.get(), args.getCollectionIndex(), &name, &style, &isFixedPitch,
+ &axisDefinitions)) {
+ return nullptr;
+ }
+
+ const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
+ SkAutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.count());
+ Scanner::computeAxisValues(axisDefinitions, position, axisValues, name);
+
+ auto fontData = std::make_unique<SkFontData>(std::move(stream), args.getCollectionIndex(),
+ axisValues.get(), axisDefinitions.count());
+ return sk_make_sp<SkTypeface_Fuchsia>(std::move(fontData), style, isFixedPitch, name, id);
+}
+
+sk_sp<SkTypeface> CreateTypefaceFromSkData(sk_sp<SkData> data, TypefaceId id) {
+ return CreateTypefaceFromSkStream(std::make_unique<SkMemoryStream>(std::move(data)),
+ SkFontArguments().setCollectionIndex(id.ttcIndex), id);
+}
+
+class SkFontMgr_Fuchsia final : public SkFontMgr {
+public:
+ SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider);
+ ~SkFontMgr_Fuchsia() override;
+
+protected:
+ // SkFontMgr overrides.
+ int onCountFamilies() const override;
+ void onGetFamilyName(int index, SkString* familyName) const override;
+ SkFontStyleSet* onMatchFamily(const char familyName[]) const override;
+ SkFontStyleSet* onCreateStyleSet(int index) const override;
+ SkTypeface* onMatchFamilyStyle(const char familyName[], const SkFontStyle&) const override;
+ SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const override;
+ SkTypeface* onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const override;
+ sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const override;
+ sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
+ int ttcIndex) const override;
+ sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
+ const SkFontArguments&) const override;
+ sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override;
+ sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override;
+
+private:
+ friend class SkFontStyleSet_Fuchsia;
+
+ sk_sp<SkTypeface> FetchTypeface(const char familyName[], const SkFontStyle& style,
+ const char* bcp47[], int bcp47Count, SkUnichar character,
+ bool allow_fallback, bool exact_style_match) const;
+
+ sk_sp<SkData> GetOrCreateSkData(int bufferId, const fuchsia::mem::Buffer& buffer) const;
+ void OnSkDataDeleted(int bufferId) const;
+
+ sk_sp<SkTypeface> GetOrCreateTypeface(TypefaceId id, const fuchsia::mem::Buffer& buffer) const;
+
+ mutable fuchsia::fonts::ProviderSyncPtr fFontProvider;
+
+ mutable SkMutex fCacheMutex;
+
+ // Must be accessed only with fCacheMutex acquired.
+ mutable std::unordered_map<int, SkData*> fBufferCache;
+ mutable SkTypefaceCache fTypefaceCache;
+};
+
+class SkFontStyleSet_Fuchsia : public SkFontStyleSet {
+public:
+ SkFontStyleSet_Fuchsia(sk_sp<SkFontMgr_Fuchsia> font_manager, std::string familyName,
+ std::vector<SkFontStyle> styles)
+ : fFontManager(font_manager), fFamilyName(familyName), fStyles(styles) {}
+
+ ~SkFontStyleSet_Fuchsia() override = default;
+
+ int count() override { return fStyles.size(); }
+
+ void getStyle(int index, SkFontStyle* style, SkString* styleName) override {
+ SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
+ if (style) *style = fStyles[index];
+
+ // We don't have style names. Return an empty name.
+ if (styleName) styleName->reset();
+ }
+
+ SkTypeface* createTypeface(int index) override {
+ SkASSERT(index >= 0 && index < static_cast<int>(fStyles.size()));
+
+ if (fTypefaces.empty()) fTypefaces.resize(fStyles.size());
+
+ if (!fTypefaces[index]) {
+ fTypefaces[index] = fFontManager->FetchTypeface(
+ fFamilyName.c_str(), fStyles[index], /*bcp47=*/nullptr,
+ /*bcp47Count=*/0, /*character=*/0,
+ /*allow_fallback=*/false, /*exact_style_match=*/true);
+ }
+
+ return SkSafeRef(fTypefaces[index].get());
+ }
+
+ SkTypeface* matchStyle(const SkFontStyle& pattern) override { return matchStyleCSS3(pattern); }
+
+private:
+ sk_sp<SkFontMgr_Fuchsia> fFontManager;
+ std::string fFamilyName;
+ std::vector<SkFontStyle> fStyles;
+ std::vector<sk_sp<SkTypeface>> fTypefaces;
+};
+
+SkFontMgr_Fuchsia::SkFontMgr_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider)
+ : fFontProvider(std::move(provider)) {}
+
+SkFontMgr_Fuchsia::~SkFontMgr_Fuchsia() = default;
+
+int SkFontMgr_Fuchsia::onCountFamilies() const {
+ // Family enumeration is not supported.
+ return 0;
+}
+
+void SkFontMgr_Fuchsia::onGetFamilyName(int index, SkString* familyName) const {
+ // Family enumeration is not supported.
+ familyName->reset();
+}
+
+SkFontStyleSet* SkFontMgr_Fuchsia::onCreateStyleSet(int index) const {
+ // Family enumeration is not supported.
+ return nullptr;
+}
+
+SkFontStyleSet* SkFontMgr_Fuchsia::onMatchFamily(const char familyName[]) const {
+ fuchsia::fonts::FamilyInfoPtr familyInfo;
+ int result = fFontProvider->GetFamilyInfo(familyName, &familyInfo);
+ if (result != ZX_OK || !familyInfo) return nullptr;
+
+ std::vector<SkFontStyle> styles;
+ for (auto& style : *(familyInfo->styles)) {
+ styles.push_back(SkFontStyle(style.weight, style.width, FuchsiaToSkSlant(style.slant)));
+ }
+
+ return new SkFontStyleSet_Fuchsia(sk_ref_sp(this), familyInfo->name, std::move(styles));
+}
+
+SkTypeface* SkFontMgr_Fuchsia::onMatchFamilyStyle(const char familyName[],
+ const SkFontStyle& style) const {
+ sk_sp<SkTypeface> typeface =
+ FetchTypeface(familyName, style, /*bcp47=*/nullptr,
+ /*bcp47Count=*/0, /*character=*/0,
+ /*allow_fallback=*/false, /*exact_style_match=*/false);
+ return typeface.release();
+}
+
+SkTypeface* SkFontMgr_Fuchsia::onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const {
+ sk_sp<SkTypeface> typeface =
+ FetchTypeface(familyName, style, bcp47, bcp47Count, character, /*allow_fallback=*/true,
+ /*exact_style_match=*/false);
+ return typeface.release();
+}
+
+SkTypeface* SkFontMgr_Fuchsia::onMatchFaceStyle(const SkTypeface*, const SkFontStyle&) const {
+ return nullptr;
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromData(sk_sp<SkData>, int ttcIndex) const {
+ SkASSERT(false);
+ return nullptr;
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> asset,
+ int ttcIndex) const {
+ return makeFromStream(std::move(asset), SkFontArguments().setCollectionIndex(ttcIndex));
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> asset,
+ const SkFontArguments& args) const {
+ return CreateTypefaceFromSkStream(std::move(asset), args, kNullTypefaceId);
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::onMakeFromFile(const char path[], int ttcIndex) const {
+ return makeFromStream(std::make_unique<SkFILEStream>(path), ttcIndex);
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::onLegacyMakeTypeface(const char familyName[],
+ SkFontStyle style) const {
+ return sk_sp<SkTypeface>(matchFamilyStyle(familyName, style));
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::FetchTypeface(const char familyName[],
+ const SkFontStyle& style, const char* bcp47[],
+ int bcp47Count, SkUnichar character,
+ bool allow_fallback,
+ bool exact_style_match) const {
+ fuchsia::fonts::Request request;
+ request.weight = style.weight();
+ request.width = style.width();
+ request.slant = SkToFuchsiaSlant(style.slant());
+ request.language.reset(std::vector<fidl::StringPtr>(bcp47, bcp47 + bcp47Count));
+ request.character = character;
+ request.fallback_group = GetFallbackGroupByName(familyName);
+
+ // If family name is not specified or it is a generic fallback group name (e.g. "serif") then
+ // enable fallback, otherwise pass the family name as is.
+ if (!familyName || *familyName == '\0' ||
+ request.fallback_group != fuchsia::fonts::FallbackGroup::NONE) {
+ request.family = "";
+ allow_fallback = true;
+ } else {
+ request.family = familyName;
+ }
+
+ request.flags = 0;
+ if (!allow_fallback) request.flags |= fuchsia::fonts::REQUEST_FLAG_NO_FALLBACK;
+ if (exact_style_match) request.flags |= fuchsia::fonts::REQUEST_FLAG_EXACT_MATCH;
+
+ fuchsia::fonts::ResponsePtr response;
+ int result = fFontProvider->GetFont(std::move(request), &response);
+ if (result != ZX_OK) return nullptr;
+
+ // The service may return null response if there is no font matching the request.
+ if (!response) return nullptr;
+
+ return GetOrCreateTypeface(TypefaceId{response->buffer_id, response->font_index},
+ response->buffer);
+}
+
+sk_sp<SkData> SkFontMgr_Fuchsia::GetOrCreateSkData(int bufferId,
+ const fuchsia::mem::Buffer& buffer) const {
+ fCacheMutex.assertHeld();
+
+ auto iter = fBufferCache.find(bufferId);
+ if (iter != fBufferCache.end()) {
+ return sk_ref_sp(iter->second);
+ }
+ auto font_mgr = sk_ref_sp(this);
+ auto data = MakeSkDataFromBuffer(buffer,
+ [font_mgr, bufferId]() { font_mgr->OnSkDataDeleted(bufferId); });
+ if (!data) {
+ return nullptr;
+ }
+ fBufferCache[bufferId] = data.get();
+ return data;
+}
+
+void SkFontMgr_Fuchsia::OnSkDataDeleted(int bufferId) const {
+ SK_UNUSED bool wasFound = fBufferCache.erase(bufferId) != 0;
+ SkASSERT(wasFound);
+}
+
+static bool FindByTypefaceId(SkTypeface* cachedTypeface, void* ctx) {
+ SkTypeface_Fuchsia* cachedFuchsiaTypeface = static_cast<SkTypeface_Fuchsia*>(cachedTypeface);
+ TypefaceId* id = static_cast<TypefaceId*>(ctx);
+
+ return cachedFuchsiaTypeface->id() == *id;
+}
+
+sk_sp<SkTypeface> SkFontMgr_Fuchsia::GetOrCreateTypeface(TypefaceId id,
+ const fuchsia::mem::Buffer& buffer) const {
+ SkAutoMutexAcquire mutexLock(fCacheMutex);
+
+ SkTypeface* cached = fTypefaceCache.findByProcAndRef(FindByTypefaceId, &id);
+ if (cached) return sk_sp<SkTypeface>(cached);
+
+ sk_sp<SkData> data = GetOrCreateSkData(id.bufferId, buffer);
+ if (!data) return nullptr;
+
+ auto result = CreateTypefaceFromSkData(std::move(data), id);
+ fTypefaceCache.add(result.get());
+ return result;
+}
+
+SK_API sk_sp<SkFontMgr> SkFontMgr_New_Fuchsia(fuchsia::fonts::ProviderSyncPtr provider) {
+ return sk_make_sp<SkFontMgr_Fuchsia>(std::move(provider));
+}