diff --git a/Libraries/LibGfx/Font/Typeface.cpp b/Libraries/LibGfx/Font/Typeface.cpp index 13abae202b..6cfe7e8031 100644 --- a/Libraries/LibGfx/Font/Typeface.cpp +++ b/Libraries/LibGfx/Font/Typeface.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace Gfx { @@ -84,20 +86,21 @@ hb_face_t* Typeface::harfbuzz_typeface() const return m_harfbuzz_face; } -ReadonlyBytes Typeface::font_data_bytes() const +void Typeface::encode_font_data_for_ipc(IPC::Encoder& encoder) const { - if (!m_font_data.has_value()) - return buffer(); - return m_font_data->visit( - [](Core::AnonymousBuffer const& anonymous_buffer) { return anonymous_buffer.bytes(); }, - [](NonnullRefPtr const& resource) { return resource->data(); }); -} + VERIFY(m_font_data.has_value()); -Optional Typeface::anonymous_font_data() const -{ - if (!m_font_data.has_value() || !m_font_data->has()) - return {}; - return m_font_data->get(); + m_font_data->visit( + [&](Core::AnonymousBuffer const& anonymous_buffer) { + MUST(encoder.encode(FontDataFormat::RawFontData)); + MUST(encoder.encode(anonymous_buffer)); + MUST(encoder.encode(ttc_index())); + }, + [&](NonnullRefPtr const& resource) { + MUST(encoder.encode(FontDataFormat::ResourceFontData)); + MUST(encoder.encode(resource->uri())); + MUST(encoder.encode(ttc_index())); + }); } void Typeface::set_anonymous_font_data(Core::AnonymousBuffer anonymous_buffer) @@ -116,3 +119,59 @@ void Typeface::copy_font_data_from(Typeface const& other) } } + +namespace IPC { + +static NonnullRefPtr match_system_typeface(Optional system_ui_font_kind, String family_name, u16 weight, u16 width, u8 slope) +{ + if (system_ui_font_kind.has_value()) { + auto typeface = MUST(Gfx::TypefaceSkia::match_system_ui(system_ui_font_kind.value(), 0, weight, width, slope)); + if (typeface) + return typeface.release_nonnull(); + } + + auto typeface = MUST(Gfx::TypefaceSkia::match_family_style(family_name.bytes_as_string_view(), weight, width, slope)); + VERIFY(typeface); + return typeface.release_nonnull(); +} + +template<> +ErrorOr encode(Encoder& encoder, Gfx::Typeface const& typeface) +{ + typeface.encode_font_data_for_ipc(encoder); + return {}; +} + +template<> +ErrorOr> decode(Decoder& decoder) +{ + auto format = TRY(decoder.decode()); + + switch (format) { + case Gfx::Typeface::FontDataFormat::RawFontData: { + auto font_data = TRY(decoder.decode()); + auto ttc_index = TRY(decoder.decode()); + if (!font_data.is_valid()) + return Error::from_string_literal("Typeface IPC data contained invalid font data"); + return TRY(Gfx::Typeface::try_load_from_anonymous_buffer(move(font_data), ttc_index)); + } + case Gfx::Typeface::FontDataFormat::ResourceFontData: { + auto resource_uri = TRY(decoder.decode()); + auto ttc_index = TRY(decoder.decode()); + auto resource = TRY(Core::Resource::load_from_uri(resource_uri.bytes_as_string_view())); + return TRY(Gfx::Typeface::try_load_from_resource(*resource, ttc_index)); + } + case Gfx::Typeface::FontDataFormat::SystemFont: { + auto system_ui_font_kind = TRY(decoder.decode>()); + auto family_name = TRY(decoder.decode()); + auto weight = TRY(decoder.decode()); + auto width = TRY(decoder.decode()); + auto slope = TRY(decoder.decode()); + return match_system_typeface(system_ui_font_kind, move(family_name), weight, width, slope); + } + } + + return Error::from_string_literal("Typeface IPC data contained invalid font data format"); +} + +} diff --git a/Libraries/LibGfx/Font/Typeface.h b/Libraries/LibGfx/Font/Typeface.h index e6bef19da2..242873a9a1 100644 --- a/Libraries/LibGfx/Font/Typeface.h +++ b/Libraries/LibGfx/Font/Typeface.h @@ -17,6 +17,7 @@ #include #include #include +#include #define POINTS_PER_INCH 72.0f #define DEFAULT_DPI 96 @@ -69,9 +70,6 @@ public: [[nodiscard]] NonnullRefPtr font(float point_size, FontVariationSettings const& variations = {}, Gfx::ShapeFeatures const& shape_features = {}) const; hb_face_t* harfbuzz_typeface() const; - ReadonlyBytes font_data_bytes() const; - Optional anonymous_font_data() const; - u32 font_data_ttc_index() const { return ttc_index(); } template bool fast_is() const = delete; @@ -79,16 +77,30 @@ public: virtual bool is_skia() const { return false; } protected: + enum class FontDataFormat : u8 { + RawFontData, + ResourceFontData, + SystemFont, + }; + Typeface(); virtual ReadonlyBytes buffer() const = 0; virtual u32 ttc_index() const = 0; + virtual void encode_font_data_for_ipc(IPC::Encoder&) const; void set_anonymous_font_data(Core::AnonymousBuffer); void set_resource_font_data(Core::Resource const&); void copy_font_data_from(Typeface const&); + bool has_font_data_backing() const { return m_font_data.has_value(); } private: + template + friend ErrorOr IPC::encode(IPC::Encoder&, T const&); + + template + friend ErrorOr IPC::decode(IPC::Decoder&); + using FontDataBacking = Variant>; Optional m_font_data; @@ -106,3 +118,13 @@ struct AK::Traits : public AK::DefaultTraits +ErrorOr encode(Encoder&, Gfx::Typeface const&); + +template<> +ErrorOr> decode(Decoder&); + +} diff --git a/Libraries/LibGfx/Font/TypefaceSkia.cpp b/Libraries/LibGfx/Font/TypefaceSkia.cpp index fdad0bef7c..5fadbdd4c0 100644 --- a/Libraries/LibGfx/Font/TypefaceSkia.cpp +++ b/Libraries/LibGfx/Font/TypefaceSkia.cpp @@ -5,14 +5,16 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include -#include #include #include +#include #include #include #include +#include #include #if defined(AK_OS_ANDROID) # include @@ -34,14 +36,16 @@ namespace Gfx { static sk_sp s_font_manager; struct TypefaceSkia::Impl { - Impl(sk_sp skia_typeface, std::unique_ptr stream = {}) + Impl(sk_sp skia_typeface, std::unique_ptr stream = {}, Optional system_ui_font_kind = {}) : skia_typeface(move(skia_typeface)) , stream(move(stream)) + , system_ui_font_kind(move(system_ui_font_kind)) { } sk_sp skia_typeface; std::unique_ptr stream; + Optional system_ui_font_kind; }; static SkFontMgr& font_manager() @@ -66,6 +70,18 @@ static SkFontMgr& font_manager() return *s_font_manager; } +static std::unique_ptr copy_stream_to_memory_stream(SkStreamAsset& stream) +{ + auto stream_copy = stream.duplicate(); + VERIFY(stream_copy); + + auto data = SkData::MakeFromStream(stream_copy.get(), stream_copy->getLength()); + VERIFY(data); + VERIFY(data->size() == stream.getLength()); + + return std::make_unique(move(data)); +} + static SkFontStyle::Slant slope_to_skia_slant(u8 slope) { switch (slope) { @@ -78,7 +94,11 @@ static SkFontStyle::Slant slope_to_skia_slant(u8 slope) } } -ErrorOr> TypefaceSkia::typeface_from_skia_typeface(sk_sp skia_typeface) +#ifdef AK_OS_MACOS +static CTFontRef create_system_ui_font(SystemUIFontKind, float point_size, u8 slope); +#endif + +ErrorOr> TypefaceSkia::typeface_from_skia_typeface(sk_sp skia_typeface, Optional system_ui_font_kind) { if (!skia_typeface) return RefPtr {}; @@ -91,22 +111,20 @@ ErrorOr> TypefaceSkia::typeface_from_skia_typeface(sk_sp(stream->getMemoryBase()), stream->getLength() }; return adopt_ref(*new TypefaceSkia { - make(skia_typeface, std::move(stream)), + make(skia_typeface, std::move(stream), system_ui_font_kind), bytes, ttc_index }); } - auto data = skia_typeface->serialize(SkTypeface::SerializeBehavior::kDoIncludeData); - if (!data) + if (!stream) return Error::from_string_literal("Failed to get font data from typeface"); - auto anonymous_buffer = TRY(Core::AnonymousBuffer::create_with_size(data->size())); - if (data->size() > 0) - memcpy(anonymous_buffer.data(), data->data(), data->size()); - - auto result = TRY(TypefaceSkia::load_from_buffer(anonymous_buffer.bytes(), ttc_index)); - result->set_anonymous_font_data(move(anonymous_buffer)); - return result; + auto memory_stream = copy_stream_to_memory_stream(*stream); + auto bytes = ReadonlyBytes { static_cast(memory_stream->getMemoryBase()), memory_stream->getLength() }; + return adopt_ref(*new TypefaceSkia { + make(skia_typeface, move(memory_stream), system_ui_font_kind), + bytes, + ttc_index }); } ErrorOr> TypefaceSkia::load_from_buffer(AK::ReadonlyBytes buffer, u32 ttc_index) @@ -129,6 +147,23 @@ ErrorOr> TypefaceSkia::load_from_buffer(AK::Readonly return adopt_ref(*new TypefaceSkia { make(skia_typeface), buffer, ttc_index }); } +void TypefaceSkia::encode_font_data_for_ipc(IPC::Encoder& encoder) const +{ + if (has_font_data_backing()) { + Typeface::encode_font_data_for_ipc(encoder); + return; + } + + auto family_name = family().to_string(); + + MUST(encoder.encode(FontDataFormat::SystemFont)); + MUST(encoder.encode(impl().system_ui_font_kind)); + MUST(encoder.encode(family_name)); + MUST(encoder.encode(weight())); + MUST(encoder.encode(width())); + MUST(encoder.encode(slope())); +} + #ifdef AK_OS_MACOS // NB: These are the CoreText string values behind the public AppKit NSFontDescriptorSystemDesign constants. // Keeping them here avoids pulling Objective-C headers into this C++ file. @@ -204,7 +239,7 @@ ErrorOr> TypefaceSkia::match_system_ui(SystemUIFontKind kin return RefPtr {}; auto skia_typeface = SkMakeTypefaceFromCTFont(ct_font); - auto typeface = typeface_from_skia_typeface(move(skia_typeface)); + auto typeface = typeface_from_skia_typeface(move(skia_typeface), kind); CFRelease(ct_font); return typeface; #else @@ -217,6 +252,12 @@ ErrorOr> TypefaceSkia::match_system_ui(SystemUIFontKind kin #endif } +ErrorOr> TypefaceSkia::match_family_style(StringView family_name, u16 weight, u16 width, u8 slope) +{ + auto skia_typeface = font_manager().matchFamilyStyle(ByteString(family_name).characters(), SkFontStyle { weight, width, slope_to_skia_slant(slope) }); + return typeface_from_skia_typeface(move(skia_typeface)); +} + ErrorOr> TypefaceSkia::find_typeface_for_code_point(u32 code_point, u16 weight, u16 width, u8 slope) { SkFontStyle style(weight, width, slope_to_skia_slant(slope)); @@ -273,9 +314,19 @@ RefPtr TypefaceSkia::clone_with_variations(Vector(skia_typeface), m_buffer, m_ttc_index }); - typeface->copy_font_data_from(*this); - return typeface; + if (has_font_data_backing()) { + auto typeface = adopt_ref(*new TypefaceSkia { + make(skia_typeface, std::unique_ptr {}, impl().system_ui_font_kind), + m_buffer, + m_ttc_index }); + typeface->copy_font_data_from(*this); + return typeface; + } + + auto typeface_or_error = typeface_from_skia_typeface(move(skia_typeface), impl().system_ui_font_kind); + if (typeface_or_error.is_error()) + return {}; + return typeface_or_error.release_value(); } SkTypeface const* TypefaceSkia::sk_typeface() const diff --git a/Libraries/LibGfx/Font/TypefaceSkia.h b/Libraries/LibGfx/Font/TypefaceSkia.h index 54be7695d8..234eaaa1e1 100644 --- a/Libraries/LibGfx/Font/TypefaceSkia.h +++ b/Libraries/LibGfx/Font/TypefaceSkia.h @@ -26,6 +26,7 @@ class TypefaceSkia : public Gfx::Typeface { public: static ErrorOr> load_from_buffer(ReadonlyBytes, u32 ttc_index = 0); static ErrorOr> match_system_ui(SystemUIFontKind, float point_size, u16 weight, double width, u8 slope); + static ErrorOr> match_family_style(StringView family_name, u16 weight, u16 width, u8 slope); static ErrorOr> find_typeface_for_code_point(u32 code_point, u16 weight, u16 width, u8 slope); static Optional resolve_generic_family(StringView family_name, u16 weight, u8 slope); @@ -44,12 +45,15 @@ public: SkTypeface const* sk_typeface() const; +protected: + virtual void encode_font_data_for_ipc(IPC::Encoder&) const override; + private: struct Impl; Impl& impl() const { return *m_impl; } NonnullOwnPtr m_impl; - static ErrorOr> typeface_from_skia_typeface(sk_sp); + static ErrorOr> typeface_from_skia_typeface(sk_sp, Optional = {}); TypefaceSkia(NonnullOwnPtr, ReadonlyBytes, u32 ttc_index = 0); diff --git a/Libraries/LibIPC/Encoder.h b/Libraries/LibIPC/Encoder.h index 07274ddd34..815d8343cc 100644 --- a/Libraries/LibIPC/Encoder.h +++ b/Libraries/LibIPC/Encoder.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include namespace IPC {