1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Font: Cache HarfBuzz fonts and font details

This commit is contained in:
Anthony Nicholls 2025-07-14 12:54:30 +01:00 committed by Anthony Nicholls
parent c0f164ee28
commit 5b0a2b9b80
8 changed files with 287 additions and 186 deletions

View file

@ -130,11 +130,6 @@ public:
return fromFont (dwFont, customFontCollection, nullptr, MetricsMechanism::gdiWithDwriteFallback);
}
Native getNativeDetails() const override
{
return Native { hbFont.get(), nonPortableMetrics };
}
Typeface::Ptr createSystemFallback (const String& c, const String& language) const override
{
auto factory = factories->getDWriteFactory().getInterface<IDWriteFactory2>();
@ -171,6 +166,11 @@ public:
ComSmartPtr<IDWriteFontFace> getIDWriteFontFace() const { return dwFontFace; }
const Native* getNativeDetails() const override
{
return native.get();
}
static Typeface::Ptr findSystemTypeface()
{
NONCLIENTMETRICS nonClientMetrics{};
@ -295,8 +295,7 @@ private:
collection (std::move (collectionIn)),
dwFont (font),
dwFontFace (face),
hbFont (std::move (hbFontIn)),
nonPortableMetrics (metrics)
native (std::make_unique<Native> (TypefaceNativeOptions { std::move (hbFontIn), metrics }))
{
if (collection != nullptr)
factories->getFonts().addCollection (collection);
@ -341,8 +340,9 @@ private:
const auto name = getLocalisedFamilyName (*dwFont);
const auto style = getLocalisedStyle (*dwFont);
const HbFace hbFace { hb_directwrite_face_create (dwFace) };
HbFont font { hb_font_create (hbFace.get()) };
HbFace hbFace { hb_directwrite_face_create (dwFace), IncrementRef::no };
HbFont font { hb_font_create (hbFace.get()), IncrementRef::no };
const auto dwMetrics = getDwriteMetrics (*dwFace);
const auto metrics = mm == MetricsMechanism::gdiWithDwriteFallback
@ -411,8 +411,7 @@ private:
ComSmartPtr<IDWriteFontCollection> collection;
ComSmartPtr<IDWriteFont> dwFont;
ComSmartPtr<IDWriteFontFace> dwFontFace;
HbFont hbFont;
TypefaceAscentDescent nonPortableMetrics;
std::unique_ptr<Native> native;
};
struct DefaultFontNames

View file

@ -93,9 +93,9 @@ std::unique_ptr<InputStream> makeAndroidInputStreamWrapper (LocalRef<jobject> st
struct AndroidCachedTypeface
{
std::shared_ptr<hb_font_t> font;
HbFont font;
GlobalRef javaFont;
TypefaceAscentDescent nonPortableMetrics;
TypefaceAscentDescent metrics;
};
//==============================================================================
@ -235,7 +235,7 @@ public:
{
return new AndroidTypeface (DoCache::no,
result->font,
result->nonPortableMetrics,
result->metrics,
font.getTypefaceName(),
font.getTypefaceStyle(),
result->javaFont);
@ -251,7 +251,7 @@ public:
return {};
}
HbFont hbFont { hb_font_create (face.get()) };
HbFont hbFont { hb_font_create (face.get()), IncrementRef::no };
FontStyleHelpers::initSynthetics (hbFont.get(), font);
const auto androidFont = shouldStoreAndroidFont (face.get())
@ -271,11 +271,6 @@ public:
return fromMemory (DoCache::yes, blob, index);
}
Native getNativeDetails() const override
{
return Native { hbFont.get(), nonPortableMetrics, this };
}
Typeface::Ptr createSystemFallback (const String& text, const String& language) const override
{
if (__builtin_available (android 29, *))
@ -293,6 +288,11 @@ public:
c->remove ({ getName(), getStyle() });
}
const Native* getNativeDetails() const override
{
return native.get();
}
static Typeface::Ptr findSystemTypeface()
{
if (__builtin_available (android 29, *))
@ -358,8 +358,8 @@ private:
const AFontMatcherPtr matcher { AFontMatcher_create() };
const auto weight = hb_style_get_value (hbFont.get(), HB_STYLE_TAG_WEIGHT);
const auto italic = hb_style_get_value (hbFont.get(), HB_STYLE_TAG_ITALIC) != 0.0f;
const auto weight = hb_style_get_value (native->getFont(), HB_STYLE_TAG_WEIGHT);
const auto italic = hb_style_get_value (native->getFont(), HB_STYLE_TAG_ITALIC) != 0.0f;
AFontMatcher_setStyle (matcher.get(), (uint16_t) weight, italic);
AFontMatcher_setLocales (matcher.get(), language.toRawUTF8());
@ -367,7 +367,7 @@ private:
const auto utf16 = text.toUTF16();
const AFontPtr matched { AFontMatcher_match (matcher.get(),
readFontName (hb_font_get_face (hbFont.get()),
readFontName (hb_font_get_face (native->getFont()),
HB_OT_NAME_ID_FONT_FAMILY,
nullptr).toRawUTF8(),
unalignedPointerCast<const uint16_t*> (utf16.getAddress()),
@ -442,7 +442,7 @@ private:
const auto metrics = findNonPortableMetricsForData (blob);
return new AndroidTypeface (cache,
HbFont { hb_font_create (face.get()) },
HbFont (hb_font_create (face.get()), IncrementRef::no),
metrics,
readFontName (face.get(), HB_OT_NAME_ID_FONT_FAMILY, nullptr),
readFontName (face.get(), HB_OT_NAME_ID_FONT_SUBFAMILY, nullptr),
@ -461,20 +461,19 @@ private:
}
AndroidTypeface (DoCache cache,
std::shared_ptr<hb_font_t> fontIn,
HbFont fontIn,
TypefaceAscentDescent nonPortableMetricsIn,
const String& name,
const String& style,
GlobalRef javaFontIn)
: Typeface (name, style),
hbFont (std::move (fontIn)),
doCache (cache),
nonPortableMetrics (nonPortableMetricsIn),
javaFont (std::move (javaFontIn))
javaFont (std::move (javaFontIn)),
native (std::make_unique<Native> (TypefaceNativeOptions { std::move (fontIn), nonPortableMetricsIn, this }))
{
if (doCache == DoCache::yes)
if (auto* c = MemoryFontCache::getInstance())
c->add ({ name, style }, { hbFont, javaFont, nonPortableMetrics });
c->add ({ name, style }, { fontIn, javaFont, nonPortableMetricsIn });
}
static std::tuple<MemoryBlock, TypefaceAscentDescent> getBlobForFont (const Font& font)
@ -664,22 +663,22 @@ private:
auto* env = getEnv();
hb_glyph_extents_t extents{};
const auto extents = native->getGlyphExtents ((hb_codepoint_t) glyph);
if (! hb_font_get_glyph_extents (hbFont.get(), (hb_codepoint_t) glyph, &extents))
if (! extents.has_value())
{
// Trying to retrieve an image for a glyph that's not present in the font?
jassertfalse;
return {};
}
const auto upem = (jint) hb_face_get_upem (hb_font_get_face (hbFont.get()));
const auto upem = (jint) hb_face_get_upem (hb_font_get_face (native->getFont()));
constexpr jint referenceSize = 128;
const jint pixelW = (referenceSize * abs (extents.width)) / upem;
const jint pixelH = (referenceSize * abs (extents.height)) / upem;
const jint pixelBearingX = (referenceSize * extents.x_bearing) / upem;
const jint pixelBearingY = (referenceSize * extents.y_bearing) / upem;
const jint pixelW = (referenceSize * abs (extents->width)) / upem;
const jint pixelH = (referenceSize * abs (extents->height)) / upem;
const jint pixelBearingX = (referenceSize * extents->x_bearing) / upem;
const jint pixelBearingY = (referenceSize * extents->y_bearing) / upem;
const jint pixelPadding = 2;
@ -760,10 +759,9 @@ private:
.followedBy (transform) } } };
}
std::shared_ptr<hb_font_t> hbFont;
DoCache doCache;
TypefaceAscentDescent nonPortableMetrics;
GlobalRef javaFont;
std::unique_ptr<Native> native;
};
//==============================================================================

View file

@ -394,10 +394,8 @@ public:
if (face == nullptr)
return {};
auto* hbFace = hb_ft_face_create_referenced (face->face);
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
HbFont hb { hb_font_create (hbFace) };
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
HbFont hb { hb_font_create (hbFace.get()), IncrementRef::no };
if (hb == nullptr)
return {};
@ -413,10 +411,8 @@ public:
if (face == nullptr)
return {};
auto* hbFace = hb_ft_face_create_referenced (face->face);
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
HbFont hb { hb_font_create (hbFace) };
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
HbFont hb { hb_font_create (hbFace.get()), IncrementRef::no };
if (hb == nullptr)
return {};
@ -424,11 +420,6 @@ public:
return new FreeTypeTypeface (DoCache::yes, face, std::move (hb), face->face->family_name, face->face->style_name);
}
Native getNativeDetails() const override
{
return Native { hb.get(), nonPortableMetrics };
}
Typeface::Ptr createSystemFallback ([[maybe_unused]] const String& text,
[[maybe_unused]] const String& language) const override
{
@ -478,11 +469,18 @@ public:
~FreeTypeTypeface() override
{
native.reset();
if (doCache == DoCache::yes)
if (auto* list = FTTypefaceList::getInstanceWithoutCreating())
list->removeMemoryFace (ftFace);
}
const Native* getNativeDetails() const override
{
return native.get();
}
static Typeface::Ptr findSystemTypeface()
{
#if JUCE_USE_FONTCONFIG
@ -530,8 +528,8 @@ private:
if (face == nullptr)
return {};
const HbFace hbFace { hb_ft_face_create_referenced (face->face) };
HbFont cachedFont { hb_font_create (hbFace.get()) };
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
HbFont cachedFont { hb_font_create (hbFace.get()), IncrementRef::no };
if (cachedFont == nullptr)
return {};
@ -541,6 +539,15 @@ private:
}
#endif
static TypefaceAscentDescent getNativeMetrics (FTFaceWrapper::Ptr ftFace)
{
const auto upem = (float) ftFace->face->units_per_EM;
const auto ascent = (float) std::abs (ftFace->face->ascender) / upem;
const auto descent = (float) std::abs (ftFace->face->descender) / upem;
return { ascent, descent };
}
FreeTypeTypeface (DoCache cache,
FTFaceWrapper::Ptr ftFaceIn,
HbFont hbIn,
@ -548,8 +555,8 @@ private:
const String& styleIn)
: Typeface (nameIn, styleIn),
ftFace (ftFaceIn),
hb (std::move (hbIn)),
doCache (cache)
doCache (cache),
native (std::make_unique<Native> (TypefaceNativeOptions { std::move (hbIn), getNativeMetrics (ftFaceIn) }))
{
if (doCache == DoCache::yes)
if (auto* list = FTTypefaceList::getInstance())
@ -557,10 +564,8 @@ private:
}
FTFaceWrapper::Ptr ftFace;
HbFont hb;
DoCache doCache;
TypefaceAscentDescent nonPortableMetrics { (float) std::abs (ftFace->face->ascender) / (float) ftFace->face->units_per_EM,
(float) std::abs (ftFace->face->descender) / (float) ftFace->face->units_per_EM };
std::unique_ptr<Native> native;
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
};

View file

@ -174,14 +174,17 @@ public:
if (ctFont == nullptr)
return {};
HbFont result { hb_coretext_font_create (ctFont.get()) };
HbFont result { hb_coretext_font_create (ctFont.get()), IncrementRef::no };
if (result == nullptr)
return {};
FontStyleHelpers::initSynthetics (result.get(), font);
return new CoreTextTypeface (std::move (ctFont), std::move (result), font.getTypefaceName(), font.getTypefaceStyle());
return new CoreTextTypeface (std::move (ctFont),
std::move (result),
font.getTypefaceName(),
font.getTypefaceStyle());
}
static Typeface::Ptr from (Span<const std::byte> data)
@ -220,7 +223,7 @@ public:
if (ctFont == nullptr)
return {};
HbFont result { hb_coretext_font_create (ctFont.get()) };
HbFont result { hb_coretext_font_create (ctFont.get()), IncrementRef::no };
if (result == nullptr)
return {};
@ -235,11 +238,6 @@ public:
std::move (copy));
}
Native getNativeDetails() const override
{
return Native { hb.get(), nonPortableMetrics };
}
Typeface::Ptr createSystemFallback (const String& c, const String& language) const override
{
const CFUniquePtr<CFStringRef> cfText { c.toCFString() };
@ -261,7 +259,7 @@ public:
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
kCTFontStyleNameAttribute) };
HbFont result { hb_coretext_font_create (newFont.get()) };
HbFont result { hb_coretext_font_create (newFont.get()), IncrementRef::no };
if (result == nullptr)
return {};
@ -293,6 +291,11 @@ public:
return ctFont.get();
}
const Native* getNativeDetails() const override
{
return native.get();
}
static Typeface::Ptr findSystemTypeface()
{
CFUniquePtr<CTFontRef> defaultCtFont (CTFontCreateUIFontForLanguage (kCTFontUIFontSystem, 0.0, nullptr));
@ -301,7 +304,7 @@ public:
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
kCTFontStyleNameAttribute) };
HbFont result { hb_coretext_font_create (defaultCtFont.get()) };
HbFont result { hb_coretext_font_create (defaultCtFont.get()), IncrementRef::no };
if (result == nullptr)
return {};
@ -314,6 +317,17 @@ public:
}
private:
static TypefaceAscentDescent getNativeMetrics (CTFontRef ctFont)
{
const CFUniquePtr<CGFontRef> cgFont { CTFontCopyGraphicsFont (ctFont, nullptr) };
const auto upem = (float) CGFontGetUnitsPerEm (cgFont.get());
const auto ascent = std::abs ((float) CGFontGetAscent (cgFont.get()) / upem);
const auto descent = std::abs ((float) CGFontGetDescent (cgFont.get()) / upem);
return { ascent, descent };
}
CoreTextTypeface (CFUniquePtr<CTFontRef> nativeFont,
HbFont fontIn,
const String& name,
@ -321,8 +335,8 @@ private:
MemoryBlock data = {})
: Typeface (name, style),
ctFont (std::move (nativeFont)),
hb (std::move (fontIn)),
storage (std::move (data))
storage (std::move (data)),
native (std::make_unique<Native> (TypefaceNativeOptions { std::move (fontIn), getNativeMetrics (ctFont.get()) }))
{
if (! storage.isEmpty())
getRegistered().add (ctFont.get());
@ -342,15 +356,8 @@ private:
// We store this, rather than calling hb_coretext_font_get_ct_font, because harfbuzz may
// override the font cascade list in the returned font.
CFUniquePtr<CTFontRef> ctFont;
HbFont hb;
MemoryBlock storage;
TypefaceAscentDescent nonPortableMetrics = [&]
{
const CFUniquePtr<CGFontRef> cgFont { CTFontCopyGraphicsFont (ctFont.get(), nullptr) };
const auto upem = (float) CGFontGetUnitsPerEm (cgFont.get());
return TypefaceAscentDescent { (float) std::abs (CGFontGetAscent (cgFont.get()) / upem),
(float) std::abs (CGFontGetDescent (cgFont.get()) / upem) };
}();
std::unique_ptr<Native> native;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreTextTypeface)
};