From 1f8bee35f48da338e85c44c569d55104c90e3fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= Date: Fri, 14 Apr 2023 13:41:30 +0300 Subject: [PATCH] Add stub Fontations SkTypeface backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparation for using Rust code to fill the actual functionality. At the moment, this backend can draw a single outline, emulating drawing the capital H from Roboto Regular, and emulating Roboto Regular font metrics. The code is to a large extent taken from TestTypeface code in tools/fonts but is intended to be filled and replaced with Rust logic from src/ports/fontations/* in forthcoming CLs. Define build flag use_fontations for GN and bazel, add a bazel alias --with_fontations for enabling building of this backend. Add a GM test (for the GN build) which directly instantiates this typeface and draws three instances of the H glyphs at different sizes. Bug: skia:14257 Change-Id: I6460e70b2dac8665e4d7f7171bad9b43b8d93c84 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/662076 Reviewed-by: Kevin Lubick Reviewed-by: Ben Wagner Commit-Queue: Dominik Röttsches --- .bazelrc | 1 + BUILD.gn | 15 +++ bazel/common_config_settings/BUILD.bazel | 5 + gm/fontations.cpp | 75 +++++++++++++++ gn/gm.gni | 2 + gn/skia.gni | 1 + src/core/SkGlyph.h | 1 + src/ports/BUILD.bazel | 20 ++++ src/ports/SkTypeface_fontations.cpp | 112 +++++++++++++++++++++++ src/ports/SkTypeface_fontations.h | 62 +++++++++++++ 10 files changed, 294 insertions(+) create mode 100644 gm/fontations.cpp create mode 100644 src/ports/SkTypeface_fontations.cpp create mode 100644 src/ports/SkTypeface_fontations.h diff --git a/.bazelrc b/.bazelrc index 3fa9604882de..e0305dacde85 100644 --- a/.bazelrc +++ b/.bazelrc @@ -77,6 +77,7 @@ build --flag_alias=enable_vma=//src/gpu:use_vulkan_memory_allocator build --flag_alias=with_default_global_memory_pool=//src/lazy:use_default_global_memory_pool build --flag_alias=with_no_global_memory_pool=no//src/lazy:use_default_global_memory_pool build --flag_alias=with_harfbuzz=//bazel/common_config_settings:use_harfbuzz +build --flag_alias=with_fontations=//bazel/common_config_settings:use_fontations build --flag_alias=with_no_harfbuzz=no//bazel/common_config_settings:use_harfbuzz build --flag_alias=with_icu=//bazel/common_config_settings:use_icu build --flag_alias=with_no_icu=no//bazel/common_config_settings:use_icu diff --git a/BUILD.gn b/BUILD.gn index 63777b7194c1..97301ba842d6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1388,6 +1388,14 @@ optional("typeface_freetype") { ] } +optional("typeface_fontations") { + enabled = skia_use_fontations + sources = [ + "src/ports/SkTypeface_fontations.cpp", + "src/ports/SkTypeface_fontations.h", + ] +} + optional("webp_decode") { enabled = skia_use_libwebp_decode public_defines = [ "SK_CODEC_DECODES_WEBP" ] @@ -1639,6 +1647,10 @@ skia_component("skia") { defines += [ "SK_ENABLE_SPIRV_VALIDATION" ] } + if (skia_use_fontations) { + deps += [ ":typeface_fontations" ] + } + if (skia_include_multiframe_procs) { sources += [ "tools/SkSharingProc.cpp" ] } @@ -2215,6 +2227,9 @@ if (skia_enable_tools) { if (!skia_enable_ganesh) { sources -= ganesh_gm_sources } + if (skia_use_fontations) { + sources += fontations_gm_sources + } deps = [ ":etc1", ":flags", diff --git a/bazel/common_config_settings/BUILD.bazel b/bazel/common_config_settings/BUILD.bazel index 893cd224a9ed..e73997520557 100644 --- a/bazel/common_config_settings/BUILD.bazel +++ b/bazel/common_config_settings/BUILD.bazel @@ -208,6 +208,11 @@ bool_flag( default = False, ) +bool_flag( + name = "use_fontations", + default = False, +) + bool_flag( name = "use_icu", default = False, diff --git a/gm/fontations.cpp b/gm/fontations.cpp new file mode 100644 index 000000000000..9942d924681c --- /dev/null +++ b/gm/fontations.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm/gm.h" +#include "include/core/SkCanvas.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkTypeface.h" +#include "src/ports/SkTypeface_fontations.h" + +namespace skiagm { + +namespace { +const SkScalar kTextSizes[] = {12, 18, 30, 120}; + +} // namespace + +class FontationsTypefaceGM : public GM { +public: + FontationsTypefaceGM() { this->setBGColor(SK_ColorWHITE); } + +protected: + void onOnceBeforeDraw() override { fTypeface = sk_sp(new SkTypeface_Fontations()); } + + SkString onShortName() override { return SkString("typeface_fontations"); } + + SkISize onISize() override { return SkISize::Make(400, 200); } + + DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { + SkPaint paint; + paint.setColor(SK_ColorBLACK); + + if (!fTypeface) { + *errorMsg = "Unable to initialize typeface."; + return DrawResult::kSkip; + } + + SkFont font(fTypeface); + uint16_t glyphs[] = {1, 1, 1}; + SkScalar x = 100; + SkScalar y = 150; + + for (SkScalar textSize : kTextSizes) { + font.setSize(textSize); + y += font.getSpacing(); + + /* Draw origin marker as a green dot. */ + paint.setColor(SK_ColorGREEN); + canvas->drawRect(SkRect::MakeXYWH(x, y, 2, 2), paint); + paint.setColor(SK_ColorBLACK); + + canvas->drawSimpleText(glyphs, + sizeof(uint16_t) * std::size(glyphs), + SkTextEncoding::kGlyphID, + x, + y, + font, + paint); + } + + return DrawResult::kOk; + } + +private: + using INHERITED = GM; + + sk_sp fTypeface; +}; + +DEF_GM(return new FontationsTypefaceGM();) + +} // namespace skiagm diff --git a/gn/gm.gni b/gn/gm.gni index 628d4973ab94..a24e849c8f2e 100644 --- a/gn/gm.gni +++ b/gn/gm.gni @@ -414,6 +414,8 @@ gm_sources = [ gl_gm_sources = [ "$_gm/rectangletexture.cpp" ] +fontations_gm_sources = [ "$_gm/fontations.cpp" ] + ganesh_gm_sources = [ "$_gm/aarecteffect.cpp", "$_gm/attributes.cpp", diff --git a/gn/skia.gni b/gn/skia.gni index b529317aff8c..1817968d4d1b 100644 --- a/gn/skia.gni +++ b/gn/skia.gni @@ -49,6 +49,7 @@ declare_args() { skia_use_ffmpeg = false skia_use_fixed_gamma_text = is_android skia_use_fontconfig = is_linux + skia_use_fontations = false skia_use_fonthost_mac = is_mac || is_ios skia_use_freetype = is_android || is_fuchsia || is_linux || is_wasm skia_use_harfbuzz = true diff --git a/src/core/SkGlyph.h b/src/core/SkGlyph.h index 17e31b72e61f..635d9392159b 100644 --- a/src/core/SkGlyph.h +++ b/src/core/SkGlyph.h @@ -554,6 +554,7 @@ class SkGlyph { friend class SkTestScalerContext; friend class SkTestSVGScalerContext; friend class SkUserScalerContext; + friend class SkFontationsScalerContext; friend class TestSVGTypeface; friend class TestTypeface; friend class SkGlyphTestPeer; diff --git a/src/ports/BUILD.bazel b/src/ports/BUILD.bazel index 6c718aa3678b..8a395571f7a7 100644 --- a/src/ports/BUILD.bazel +++ b/src/ports/BUILD.bazel @@ -30,6 +30,16 @@ skia_filegroup( ], ) +skia_filegroup( + name = "typeface_fontations", + srcs = select({ + "//bazel/common_config_settings:use_fontations_true": [ + "SkTypeface_fontations.cpp", + ], + "//conditions:default": [], + }), +) + # There can only be one FontMgr Factory, but multiple different types of FontMgr compiled into # a single build. skia_filegroup( @@ -257,6 +267,7 @@ skia_filegroup( ":malloc", ":osfile", ":skdebug", + ":typeface_fontations", ], visibility = ["//src:__pkg__"], ) @@ -281,6 +292,11 @@ skia_filegroup( "SkFontConfigTypeface.h", ], "//conditions:default": [], + }) + select({ + "//bazel/common_config_settings:use_fontations_true": [ + "SkTypeface_fontations.h", + ], + "//conditions:default": [], }), visibility = ["//src:__pkg__"], ) @@ -324,6 +340,10 @@ skia_cc_deps( }) + select({ "//bazel/common_config_settings:uses_android_fontmgr": ["@expat"], "//conditions:default": [], + }) + select({ + "//bazel/common_config_settings:use_fontations_true": [ + ], + "//conditions:default": [], }), ) diff --git a/src/ports/SkTypeface_fontations.cpp b/src/ports/SkTypeface_fontations.cpp new file mode 100644 index 000000000000..31d0b71dd650 --- /dev/null +++ b/src/ports/SkTypeface_fontations.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkFontMetrics.h" +#include "src/core/SkFontPriv.h" +#include "src/ports/SkTypeface_fontations.h" + +namespace { +/* Placeholder glyph example until we extract paths through fontations, representing the capital H + * from Roboto Regular. */ +void drawCapitalH(SkPath* path) { + path->setFillType(SkPathFillType::kWinding); + path->moveTo(1096, -0); + path->lineTo(1096, -673); + path->lineTo(362, -673); + path->lineTo(362, -0); + path->lineTo(169, -0); + path->lineTo(169, -1456); + path->lineTo(362, -1456); + path->lineTo(362, -830); + path->lineTo(1096, -830); + path->lineTo(1096, -1456); + path->lineTo(1288, -1456); + path->lineTo(1288, -0); + path->lineTo(1096, -0); + path->close(); +} + +constexpr SkScalar capitalHAdvance = 1461; +} + +int SkTypeface_Fontations::onGetUPEM() const { return 2048; } + +void SkTypeface_Fontations::onCharsToGlyphs(const SkUnichar* chars, + int count, + SkGlyphID glyphs[]) const { + sk_bzero(glyphs, count * sizeof(glyphs[0])); +} + +void SkTypeface_Fontations::onFilterRec(SkScalerContextRec* rec) const { + rec->setHinting(SkFontHinting::kNone); +} + +class SkFontationsScalerContext : public SkScalerContext { +public: + SkFontationsScalerContext(sk_sp face, + const SkScalerContextEffects& effects, + const SkDescriptor* desc) + : SkScalerContext(std::move(face), effects, desc) { + fRec.getSingleMatrix(&fMatrix); + this->forceGenerateImageFromPath(); + } + +protected: + + bool generateAdvance(SkGlyph* glyph) override { + const SkVector advance = fMatrix.mapXY(capitalHAdvance / getTypeface()->getUnitsPerEm(), + SkFloatToScalar(0.f)); + glyph->fAdvanceX = SkScalarToFloat(advance.fX); + glyph->fAdvanceY = SkScalarToFloat(advance.fY); + return true; + } + + void generateMetrics(SkGlyph* glyph, SkArenaAlloc*) override { + glyph->fMaskFormat = fRec.fMaskFormat; + glyph->zeroMetrics(); + this->generateAdvance(glyph); + // Always generates from paths, so SkScalerContext::makeGlyph will figure the bounds. + } + + void generateImage(const SkGlyph&) override { SK_ABORT("Should have generated from path."); } + + bool generatePath(const SkGlyph& glyph, SkPath* path) override { + drawCapitalH(path); + SkMatrix scaled = fMatrix.preScale(1.0f / getTypeface()->getUnitsPerEm(), + 1.0f / getTypeface()->getUnitsPerEm()); + *path = path->makeTransform(scaled); + return true; + } + + void generateFontMetrics(SkFontMetrics* metrics) override { + /* Hard-coded Roboto Regular metrics, to be replaced with Fontations calls. */ + metrics->fTop = -2163.f / getTypeface()->getUnitsPerEm(); + metrics->fAscent = -2146.f / getTypeface()->getUnitsPerEm(); + metrics->fDescent = 555.f / getTypeface()->getUnitsPerEm(); + metrics->fBottom = 555.f / getTypeface()->getUnitsPerEm(); + metrics->fLeading = 0; + metrics->fAvgCharWidth = 0; + metrics->fMaxCharWidth = 0; + metrics->fXMin = -1825.f / getTypeface()->getUnitsPerEm(); + metrics->fXMax = 4188.f / getTypeface()->getUnitsPerEm(); + metrics->fXHeight = -1082.f / getTypeface()->getUnitsPerEm(); + metrics->fCapHeight = -1456.f / getTypeface()->getUnitsPerEm(); + metrics->fFlags = 0; + + SkFontPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY()); + } + +private: + SkMatrix fMatrix; +}; + +std::unique_ptr SkTypeface_Fontations::onCreateScalerContext( + const SkScalerContextEffects& effects, const SkDescriptor* desc) const +{ + return std::make_unique( + sk_ref_sp(const_cast(this)), effects, desc); +} diff --git a/src/ports/SkTypeface_fontations.h b/src/ports/SkTypeface_fontations.h new file mode 100644 index 000000000000..5c37a9bf807a --- /dev/null +++ b/src/ports/SkTypeface_fontations.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTypeface_Fontations_DEFINED +#define SkTypeface_Fontations_DEFINED + +#include "include/core/SkStream.h" +#include "include/core/SkTypeface.h" +#include "src/core/SkAdvancedTypefaceMetrics.h" +#include "src/core/SkScalerContext.h" + +/** SkTypeface implementation based on Google Fonts Fontations Rust libraries. */ +class SkTypeface_Fontations : public SkTypeface { +public: + static sk_sp Make() { return sk_sp(new SkTypeface_Fontations); } + SkTypeface_Fontations() : SkTypeface(SkFontStyle(), true) {} + +protected: + + std::unique_ptr onOpenStream(int* ttcIndex) const override { return nullptr; } + sk_sp onMakeClone(const SkFontArguments& args) const override { + return sk_ref_sp(this); + } + std::unique_ptr onCreateScalerContext(const SkScalerContextEffects& effects, + const SkDescriptor* desc) const override; + void onFilterRec(SkScalerContextRec*) const override; + std::unique_ptr onGetAdvancedMetrics() const override { + return nullptr; + } + void onGetFontDescriptor(SkFontDescriptor*, bool*) const override {} + void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override; + int onCountGlyphs() const override { return 1; } + void getPostScriptGlyphNames(SkString*) const override {} + void getGlyphToUnicodeMap(SkUnichar*) const override {} + int onGetUPEM() const override; + class EmptyLocalizedStrings : public SkTypeface::LocalizedStrings { + public: + bool next(SkTypeface::LocalizedString*) override { return false; } + }; + void onGetFamilyName(SkString* familyName) const override { familyName->reset(); } + bool onGetPostScriptName(SkString*) const override { return false; } + SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override { + return new EmptyLocalizedStrings; + } + bool onGlyphMaskNeedsCurrentColor() const override { return false; } + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override { + return 0; + } + int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const override { + return 0; + } + int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } + size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; } +}; + +#endif // SkTypeface_Fontations_DEFINED