LibGfx: Avoid copying macOS system font data

Keep CoreText system UI fonts backed by their CoreGraphics font instead
of opening the Skia typeface stream during font matching. Opening that
stream copies the full macOS system font data into SkData, which is very
expensive when CSS font computation asks for several system UI faces.

Let Typeface subclasses provide the HarfBuzz face creation path, and use
HarfBuzz's CoreText integration for these macOS system fonts. Clone Skia
font variations through SkTypeface::makeClone() so variation handling no
longer depends on rebuilding a typeface from the raw font stream.
This commit is contained in:
Andreas Kling 2026-05-27 21:35:42 +02:00 committed by Alexander Kalenik
parent fe6cfe99fe
commit 1eb541ce9e
4 changed files with 79 additions and 9 deletions

View file

@ -78,12 +78,17 @@ NonnullRefPtr<Font> Typeface::font(float point_size, FontVariationSettings const
}
hb_face_t* Typeface::harfbuzz_typeface() const
{
if (!m_harfbuzz_face)
m_harfbuzz_face = create_harfbuzz_face();
return m_harfbuzz_face;
}
hb_face_t* Typeface::create_harfbuzz_face() const
{
if (!m_harfbuzz_blob)
m_harfbuzz_blob = hb_blob_create(reinterpret_cast<char const*>(buffer().data()), buffer().size(), HB_MEMORY_MODE_READONLY, nullptr, [](void*) { });
if (!m_harfbuzz_face)
m_harfbuzz_face = hb_face_create(m_harfbuzz_blob, ttc_index());
return m_harfbuzz_face;
return hb_face_create(m_harfbuzz_blob, ttc_index());
}
void Typeface::encode_font_data_for_ipc(IPC::Encoder& encoder) const

View file

@ -88,6 +88,7 @@ protected:
virtual ReadonlyBytes buffer() const = 0;
virtual u32 ttc_index() const = 0;
virtual void encode_font_data_for_ipc(IPC::Encoder&) const;
virtual hb_face_t* create_harfbuzz_face() const;
void set_anonymous_font_data(Core::AnonymousBuffer);
void set_resource_font_data(Core::Resource const&);

View file

@ -12,6 +12,7 @@
#include <LibIPC/Encoder.h>
#include <core/SkData.h>
#include <core/SkFontArguments.h>
#include <core/SkFontMgr.h>
#include <core/SkStream.h>
#include <core/SkString.h>
@ -27,6 +28,7 @@
#ifdef AK_OS_MACOS
# include <CoreText/CoreText.h>
# include <harfbuzz/hb-coretext.h>
# include <ports/SkFontMgr_mac_ct.h>
# include <ports/SkTypeface_mac.h>
#endif
@ -36,16 +38,38 @@ namespace Gfx {
static sk_sp<SkFontMgr> s_font_manager;
struct TypefaceSkia::Impl {
Impl(sk_sp<SkTypeface> skia_typeface, std::unique_ptr<SkStreamAsset> stream = {}, Optional<SystemUIFontKind> system_ui_font_kind = {})
Impl(sk_sp<SkTypeface> skia_typeface, std::unique_ptr<SkStreamAsset> stream = {}, Optional<SystemUIFontKind> system_ui_font_kind = {}
#ifdef AK_OS_MACOS
,
CGFontRef cg_font = nullptr
#endif
)
: skia_typeface(move(skia_typeface))
, stream(move(stream))
, system_ui_font_kind(move(system_ui_font_kind))
{
#ifdef AK_OS_MACOS
if (cg_font) {
this->cg_font = cg_font;
CFRetain(this->cg_font);
}
#endif
}
~Impl()
{
#ifdef AK_OS_MACOS
if (cg_font)
CFRelease(cg_font);
#endif
}
sk_sp<SkTypeface> skia_typeface;
std::unique_ptr<SkStreamAsset> stream;
Optional<SystemUIFontKind> system_ui_font_kind;
#ifdef AK_OS_MACOS
CGFontRef cg_font { nullptr };
#endif
};
static SkFontMgr& font_manager()
@ -96,6 +120,23 @@ static SkFontStyle::Slant slope_to_skia_slant(u8 slope)
#ifdef AK_OS_MACOS
static CTFontRef create_system_ui_font(SystemUIFontKind, float point_size, u8 slope);
ErrorOr<RefPtr<TypefaceSkia>> TypefaceSkia::typeface_from_core_text_typeface(sk_sp<SkTypeface> skia_typeface, CTFontRef ct_font, SystemUIFontKind system_ui_font_kind)
{
if (!skia_typeface)
return RefPtr<TypefaceSkia> {};
auto cg_font = CTFontCopyGraphicsFont(ct_font, nullptr);
if (!cg_font)
return Error::from_string_literal("Failed to get graphics font from CoreText font");
auto typeface = adopt_ref(*new TypefaceSkia {
make<TypefaceSkia::Impl>(move(skia_typeface), std::unique_ptr<SkStreamAsset> {}, system_ui_font_kind, cg_font),
{},
0 });
CFRelease(cg_font);
return typeface;
}
#endif
ErrorOr<RefPtr<TypefaceSkia>> TypefaceSkia::typeface_from_skia_typeface(sk_sp<SkTypeface> skia_typeface, Optional<SystemUIFontKind> system_ui_font_kind)
@ -239,7 +280,7 @@ ErrorOr<RefPtr<TypefaceSkia>> TypefaceSkia::match_system_ui(SystemUIFontKind kin
return RefPtr<TypefaceSkia> {};
auto skia_typeface = SkMakeTypefaceFromCTFont(ct_font);
auto typeface = typeface_from_skia_typeface(move(skia_typeface), kind);
auto typeface = typeface_from_core_text_typeface(move(skia_typeface), ct_font, kind);
CFRelease(ct_font);
return typeface;
#else
@ -307,10 +348,7 @@ RefPtr<TypefaceSkia const> TypefaceSkia::clone_with_variations(Vector<FontVariat
font_args.setCollectionIndex(static_cast<int>(m_ttc_index));
auto data = SkData::MakeWithoutCopy(m_buffer.data(), m_buffer.size());
auto stream = std::make_unique<SkMemoryStream>(data);
auto skia_typeface = font_manager().makeFromStream(move(stream), font_args);
auto skia_typeface = impl().skia_typeface->makeClone(font_args);
if (!skia_typeface)
return {};
@ -323,6 +361,15 @@ RefPtr<TypefaceSkia const> TypefaceSkia::clone_with_variations(Vector<FontVariat
return typeface;
}
#ifdef AK_OS_MACOS
if (impl().cg_font) {
return adopt_ref(*new TypefaceSkia {
make<TypefaceSkia::Impl>(move(skia_typeface), std::unique_ptr<SkStreamAsset> {}, impl().system_ui_font_kind, impl().cg_font),
{},
m_ttc_index });
}
#endif
auto typeface_or_error = typeface_from_skia_typeface(move(skia_typeface), impl().system_ui_font_kind);
if (typeface_or_error.is_error())
return {};
@ -334,6 +381,15 @@ SkTypeface const* TypefaceSkia::sk_typeface() const
return impl().skia_typeface.get();
}
hb_face_t* TypefaceSkia::create_harfbuzz_face() const
{
#ifdef AK_OS_MACOS
if (impl().cg_font)
return hb_coretext_face_create(impl().cg_font);
#endif
return Typeface::create_harfbuzz_face();
}
TypefaceSkia::TypefaceSkia(NonnullOwnPtr<Impl> impl, ReadonlyBytes buffer, u32 ttc_index)
: m_impl(move(impl))
, m_buffer(buffer)

View file

@ -8,6 +8,10 @@
#include <LibGfx/Font/Typeface.h>
#ifdef AK_OS_MACOS
# include <CoreText/CoreText.h>
#endif
template<typename T>
class sk_sp;
@ -47,6 +51,7 @@ public:
protected:
virtual void encode_font_data_for_ipc(IPC::Encoder&) const override;
virtual hb_face_t* create_harfbuzz_face() const override;
private:
struct Impl;
@ -54,6 +59,9 @@ private:
NonnullOwnPtr<Impl> m_impl;
static ErrorOr<RefPtr<TypefaceSkia>> typeface_from_skia_typeface(sk_sp<SkTypeface>, Optional<SystemUIFontKind> = {});
#ifdef AK_OS_MACOS
static ErrorOr<RefPtr<TypefaceSkia>> typeface_from_core_text_typeface(sk_sp<SkTypeface>, CTFontRef, SystemUIFontKind);
#endif
TypefaceSkia(NonnullOwnPtr<Impl>, ReadonlyBytes, u32 ttc_index = 0);