From e55a8caa0d956117ff095a03a6068d9e60b88fb0 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 17 Oct 2024 13:29:14 -0700 Subject: [PATCH 1/3] [Impeller] libImpeller: Allow custom font registrations. Fixes https://github.com/flutter/flutter/issues/156361 --- impeller/toolkit/interop/impeller.cc | 16 ++++ impeller/toolkit/interop/impeller.h | 7 ++ .../toolkit/interop/impeller_unittests.cc | 74 +++++++++++++++++++ .../toolkit/interop/typography_context.cc | 50 +++++++++++++ impeller/toolkit/interop/typography_context.h | 15 ++++ 5 files changed, 162 insertions(+) diff --git a/impeller/toolkit/interop/impeller.cc b/impeller/toolkit/interop/impeller.cc index 05d8c035c1f38..7cdd6dcd86ef6 100644 --- a/impeller/toolkit/interop/impeller.cc +++ b/impeller/toolkit/interop/impeller.cc @@ -1133,4 +1133,20 @@ void ImpellerTypographyContextRelease(ImpellerTypographyContext context) { ObjectBase::SafeRelease(context); } +IMPELLER_EXTERN_C +bool ImpellerTypographyContextRegisterFont(ImpellerTypographyContext context, + const ImpellerMapping* contents, + void* contents_on_release_user_data, + const char* family_name_alias) { + auto wrapped_contents = std::make_unique( + contents->data, // data ptr + contents->length, // data length + [contents, contents_on_release_user_data](auto, auto) { + contents->on_release(contents_on_release_user_data); + } // release callback + ); + return GetPeer(context)->RegisterFont(std::move(wrapped_contents), + ReadString(family_name_alias)); +} + } // namespace impeller::interop diff --git a/impeller/toolkit/interop/impeller.h b/impeller/toolkit/interop/impeller.h index 3652a8511fbbc..5fb0fb332b022 100644 --- a/impeller/toolkit/interop/impeller.h +++ b/impeller/toolkit/interop/impeller.h @@ -851,6 +851,13 @@ IMPELLER_EXPORT void ImpellerTypographyContextRelease( ImpellerTypographyContext IMPELLER_NULLABLE context); +IMPELLER_EXPORT +bool ImpellerTypographyContextRegisterFont( + ImpellerTypographyContext IMPELLER_NONNULL context, + const ImpellerMapping* IMPELLER_NONNULL contents, + void* IMPELLER_NULLABLE contents_on_release_user_data, + const char* IMPELLER_NULLABLE family_name_alias); + //------------------------------------------------------------------------------ // Paragraph Style //------------------------------------------------------------------------------ diff --git a/impeller/toolkit/interop/impeller_unittests.cc b/impeller/toolkit/interop/impeller_unittests.cc index 2a4690e517888..a386aaf956359 100644 --- a/impeller/toolkit/interop/impeller_unittests.cc +++ b/impeller/toolkit/interop/impeller_unittests.cc @@ -245,6 +245,80 @@ TEST_P(InteropPlaygroundTest, CanCreateParagraphs) { })); } +TEST_P(InteropPlaygroundTest, CanCreateParagraphsWithCustomFont) { + // Create a typography context. + auto type_context = Adopt(ImpellerTypographyContextNew()); + ASSERT_TRUE(type_context); + + // Open the custom font file. + std::unique_ptr font_data = + flutter::testing::OpenFixtureAsMapping("wtf.otf"); + ASSERT_NE(font_data, nullptr); + ASSERT_GT(font_data->GetSize(), 0u); + ImpellerMapping font_data_mapping = { + .data = font_data->GetMapping(), + .length = font_data->GetSize(), + .on_release = [](auto ctx) { + delete reinterpret_cast(ctx); + }}; + auto registered = + ImpellerTypographyContextRegisterFont(type_context.GetC(), // + &font_data_mapping, // + font_data.release(), // + nullptr // + ); + ASSERT_TRUE(registered); + + // Create a builder. + auto builder = + Adopt(ImpellerParagraphBuilderNew(type_context.GetC())); + ASSERT_TRUE(builder); + + // Create a paragraph style with the font size and foreground and background + // colors. + auto style = Adopt(ImpellerParagraphStyleNew()); + ASSERT_TRUE(style); + ImpellerParagraphStyleSetFontSize(style.GetC(), 150.0f); + ImpellerParagraphStyleSetFontFamily(style.GetC(), "WhatTheFlutter"); + + { + auto paint = Adopt(ImpellerPaintNew()); + ASSERT_TRUE(paint); + ImpellerColor color = {0.0, 1.0, 1.0, 1.0}; + ImpellerPaintSetColor(paint.GetC(), &color); + ImpellerParagraphStyleSetForeground(style.GetC(), paint.GetC()); + } + + // Push the style onto the style stack. + ImpellerParagraphBuilderPushStyle(builder.GetC(), style.GetC()); + std::string text = "0F0F0F0"; + + // Add the paragraph text data. + ImpellerParagraphBuilderAddText(builder.GetC(), + reinterpret_cast(text.data()), + text.size()); + + // Layout and build the paragraph. + auto paragraph = Adopt( + ImpellerParagraphBuilderBuildParagraphNew(builder.GetC(), 1200.0f)); + ASSERT_TRUE(paragraph); + + // Create a display list with just the paragraph drawn into it. + auto dl_builder = + Adopt(ImpellerDisplayListBuilderNew(nullptr)); + ImpellerPoint point = {20, 20}; + ImpellerDisplayListBuilderDrawParagraph(dl_builder.GetC(), paragraph.GetC(), + &point); + auto dl = Adopt( + ImpellerDisplayListBuilderCreateDisplayListNew(dl_builder.GetC())); + + ASSERT_TRUE( + OpenPlaygroundHere([&](const auto& context, const auto& surface) -> bool { + ImpellerSurfaceDrawDisplayList(surface.GetC(), dl.GetC()); + return true; + })); +} // namespace impeller::interop::testing + static void DrawTextFrame(ImpellerTypographyContext tc, ImpellerDisplayListBuilder builder, ImpellerParagraphStyle p_style, diff --git a/impeller/toolkit/interop/typography_context.cc b/impeller/toolkit/interop/typography_context.cc index 70b24338eba1d..d97125e869fac 100644 --- a/impeller/toolkit/interop/typography_context.cc +++ b/impeller/toolkit/interop/typography_context.cc @@ -7,6 +7,8 @@ #include #include "flutter/fml/icu_util.h" +#include "flutter/third_party/txt/src/txt/platform.h" +#include "impeller/base/validation.h" #include "impeller/toolkit/interop/embedded_icu_data.h" namespace impeller::interop { @@ -19,7 +21,12 @@ TypographyContext::TypographyContext() impeller_embedded_icu_data_data, impeller_embedded_icu_data_length); fml::icu::InitializeICUFromMapping(std::move(icu_data)); }); + // The fallback for all fonts. Looks in platform specific locations. collection_->SetupDefaultFontManager(0u); + + // Looks for fonts in user supplied blobs. + asset_font_manager_ = sk_make_sp(); + collection_->SetAssetFontManager(asset_font_manager_); } TypographyContext::~TypographyContext() = default; @@ -33,4 +40,47 @@ TypographyContext::GetFontCollection() const { return collection_; } +static sk_sp CreateTypefaceFromFontData( + std::unique_ptr font_data) { + if (!font_data) { + VALIDATION_LOG << "Invalid font data."; + return nullptr; + } + auto sk_data_context = font_data.release(); + auto sk_data = SkData::MakeWithProc( + sk_data_context->GetMapping(), // data ptr + sk_data_context->GetSize(), // data size + [](const void*, void* context) { + delete reinterpret_cast(context); + }, // release callback + sk_data_context // release callback context + ); + auto sk_data_stream = SkMemoryStream::Make(sk_data); + auto sk_typeface = + txt::GetDefaultFontManager()->makeFromStream(std::move(sk_data_stream)); + if (!sk_typeface) { + VALIDATION_LOG << "Could not create typeface with data."; + return nullptr; + } + return sk_typeface; +} + +bool TypographyContext::RegisterFont(std::unique_ptr font_data, + const std::string& family_name_alias) { + auto typeface = CreateTypefaceFromFontData(std::move(font_data)); + if (typeface == nullptr) { + return false; + } + SkString family_name; + typeface->getFamilyName(&family_name); + size_t result = 0u; + if (family_name_alias.empty()) { + result = asset_font_manager_->registerTypeface(std::move(typeface)); + } else { + result = asset_font_manager_->registerTypeface(std::move(typeface), + SkString{family_name_alias}); + } + return result != 0; +} + } // namespace impeller::interop diff --git a/impeller/toolkit/interop/typography_context.h b/impeller/toolkit/interop/typography_context.h index 8c68c30825609..b8b4252872f60 100644 --- a/impeller/toolkit/interop/typography_context.h +++ b/impeller/toolkit/interop/typography_context.h @@ -7,6 +7,7 @@ #include +#include "flutter/third_party/skia/modules/skparagraph/include/TypefaceFontProvider.h" #include "flutter/third_party/txt/src/txt/font_collection.h" #include "impeller/toolkit/interop/impeller.h" #include "impeller/toolkit/interop/object.h" @@ -29,8 +30,22 @@ class TypographyContext final const std::shared_ptr& GetFontCollection() const; + //---------------------------------------------------------------------------- + /// @brief Registers custom font data. If an alias for the family name is + /// provided, subsequent lookups will need to use that same alias. + /// If not, the family name will be read from the font data. + /// + /// @param[in] font_data The font data + /// @param[in] family_name_alias The family name alias + /// + /// @return If the font data could be successfully registered. + /// + bool RegisterFont(std::unique_ptr font_data, + const std::string& family_name_alias = ""); + private: std::shared_ptr collection_; + sk_sp asset_font_manager_; }; } // namespace impeller::interop From 80deae70af291ebf037dfb8968fad3acfc5a3b2f Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 17 Oct 2024 13:43:13 -0700 Subject: [PATCH 2/3] Dead code. --- impeller/toolkit/interop/typography_context.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/impeller/toolkit/interop/typography_context.cc b/impeller/toolkit/interop/typography_context.cc index d97125e869fac..ff796998c663f 100644 --- a/impeller/toolkit/interop/typography_context.cc +++ b/impeller/toolkit/interop/typography_context.cc @@ -71,8 +71,6 @@ bool TypographyContext::RegisterFont(std::unique_ptr font_data, if (typeface == nullptr) { return false; } - SkString family_name; - typeface->getFamilyName(&family_name); size_t result = 0u; if (family_name_alias.empty()) { result = asset_font_manager_->registerTypeface(std::move(typeface)); From 9cd88767626eca9964be27193c1c2fee71d7c8e9 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Fri, 18 Oct 2024 11:55:20 -0700 Subject: [PATCH 3/3] Jonahs review. --- impeller/toolkit/interop/impeller.cc | 2 +- impeller/toolkit/interop/typography_context.cc | 4 ++-- impeller/toolkit/interop/typography_context.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/impeller/toolkit/interop/impeller.cc b/impeller/toolkit/interop/impeller.cc index 7cdd6dcd86ef6..931b2a71025a7 100644 --- a/impeller/toolkit/interop/impeller.cc +++ b/impeller/toolkit/interop/impeller.cc @@ -1146,7 +1146,7 @@ bool ImpellerTypographyContextRegisterFont(ImpellerTypographyContext context, } // release callback ); return GetPeer(context)->RegisterFont(std::move(wrapped_contents), - ReadString(family_name_alias)); + family_name_alias); } } // namespace impeller::interop diff --git a/impeller/toolkit/interop/typography_context.cc b/impeller/toolkit/interop/typography_context.cc index ff796998c663f..ed863fa61ec5d 100644 --- a/impeller/toolkit/interop/typography_context.cc +++ b/impeller/toolkit/interop/typography_context.cc @@ -66,13 +66,13 @@ static sk_sp CreateTypefaceFromFontData( } bool TypographyContext::RegisterFont(std::unique_ptr font_data, - const std::string& family_name_alias) { + const char* family_name_alias) { auto typeface = CreateTypefaceFromFontData(std::move(font_data)); if (typeface == nullptr) { return false; } size_t result = 0u; - if (family_name_alias.empty()) { + if (family_name_alias == nullptr) { result = asset_font_manager_->registerTypeface(std::move(typeface)); } else { result = asset_font_manager_->registerTypeface(std::move(typeface), diff --git a/impeller/toolkit/interop/typography_context.h b/impeller/toolkit/interop/typography_context.h index b8b4252872f60..f086ffc6b4cf2 100644 --- a/impeller/toolkit/interop/typography_context.h +++ b/impeller/toolkit/interop/typography_context.h @@ -41,7 +41,7 @@ class TypographyContext final /// @return If the font data could be successfully registered. /// bool RegisterFont(std::unique_ptr font_data, - const std::string& family_name_alias = ""); + const char* family_name_alias); private: std::shared_ptr collection_;