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:
parent
c0f164ee28
commit
5b0a2b9b80
8 changed files with 287 additions and 186 deletions
|
|
@ -219,7 +219,7 @@ static std::vector<ShapedGlyph> lowLevelShape (Span<const juce_wchar> string,
|
||||||
{
|
{
|
||||||
static const auto language = SystemStats::getDisplayLanguage();
|
static const auto language = SystemStats::getDisplayLanguage();
|
||||||
|
|
||||||
HbBuffer buffer { hb_buffer_create() };
|
HbBuffer buffer { hb_buffer_create(), IncrementRef::no };
|
||||||
hb_buffer_clear_contents (buffer.get());
|
hb_buffer_clear_contents (buffer.get());
|
||||||
|
|
||||||
hb_buffer_set_cluster_level (buffer.get(), HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
|
hb_buffer_set_cluster_level (buffer.get(), HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
|
||||||
|
|
@ -316,20 +316,14 @@ static std::vector<ShapedGlyph> lowLevelShape (Span<const juce_wchar> string,
|
||||||
const auto xAdvanceBase = HbScale::hbToJuce (positions[visualIndex].x_advance);
|
const auto xAdvanceBase = HbScale::hbToJuce (positions[visualIndex].x_advance);
|
||||||
const auto yAdvanceBase = -HbScale::hbToJuce (positions[visualIndex].y_advance);
|
const auto yAdvanceBase = -HbScale::hbToJuce (positions[visualIndex].y_advance);
|
||||||
|
|
||||||
// For certain OS, Font and glyph ID combinations harfbuzz will not find extents data and
|
// For certain OS, Font and glyph ID combinations harfbuzz will not find extents data.
|
||||||
// hb_font_get_glyph_extents will return false. In such cases Typeface::getGlyphBounds
|
// In such cases Typeface::getGlyphBounds will return an empty rectangle. Here we need
|
||||||
// will return an empty rectangle. Here we need to distinguish this situation from the one
|
// to distinguish this situation from the one where extents information is available
|
||||||
// where extents information is available and is an empty rectangle, which indicates a
|
// and is an empty rectangle, which indicates a whitespace.
|
||||||
// whitespace.
|
const auto* native = font.getTypefacePtr()->getNativeDetails();
|
||||||
const auto extentsDataAvailable = std::invoke ([&]
|
const auto extents = native->getGlyphExtents (glyphId);
|
||||||
{
|
|
||||||
hb_glyph_extents_t extents{};
|
|
||||||
return hb_font_get_glyph_extents (font.getTypefacePtr()->getNativeDetails().getFont(),
|
|
||||||
(hb_codepoint_t) glyphId,
|
|
||||||
&extents);
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto whitespace = extentsDataAvailable
|
const auto whitespace = extents.has_value()
|
||||||
&& font.getTypefacePtr()->getGlyphBounds (font.getMetricsKind(), (int) glyphId).isEmpty()
|
&& font.getTypefacePtr()->getGlyphBounds (font.getMetricsKind(), (int) glyphId).isEmpty()
|
||||||
&& xAdvanceBase > 0;
|
&& xAdvanceBase > 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ public:
|
||||||
const ScopedLock lock (mutex);
|
const ScopedLock lock (mutex);
|
||||||
|
|
||||||
if (auto ptr = getTypefacePtr (f))
|
if (auto ptr = getTypefacePtr (f))
|
||||||
return ptr->getNativeDetails().getFontAtPointSizeAndScale (f.getHeightInPoints(), f.getHorizontalScale());
|
return ptr->getNativeDetails()->getFontAtPointSizeAndScale (f.getHeightInPoints(), f.getHorizontalScale());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +231,7 @@ public:
|
||||||
|
|
||||||
if (auto ptr = getTypefacePtr (f))
|
if (auto ptr = getTypefacePtr (f))
|
||||||
{
|
{
|
||||||
const auto ascentDescent = ptr->getNativeDetails().getAscentDescent (f.getMetricsKind());
|
const auto ascentDescent = ptr->getNativeDetails()->getAscentDescent (f.getMetricsKind());
|
||||||
|
|
||||||
auto adjusted = ascentDescent;
|
auto adjusted = ascentDescent;
|
||||||
adjusted.ascent = getAscentOverride().value_or (adjusted.ascent);
|
adjusted.ascent = getAscentOverride().value_or (adjusted.ascent);
|
||||||
|
|
@ -886,7 +886,7 @@ static bool characterNotRendered (uint32_t c)
|
||||||
|
|
||||||
static bool isFontSuitableForCodepoint (const Font& font, juce_wchar c)
|
static bool isFontSuitableForCodepoint (const Font& font, juce_wchar c)
|
||||||
{
|
{
|
||||||
const auto& hbFont = font.getNativeDetails().font;
|
const auto hbFont = font.getNativeDetails().font;
|
||||||
|
|
||||||
if (hbFont == nullptr)
|
if (hbFont == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -994,7 +994,7 @@ Font::Native Font::getNativeDetails() const
|
||||||
|
|
||||||
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||||
{
|
{
|
||||||
const auto resolvedTypeface = [&]() -> Typeface::Ptr
|
const auto resolvedTypeface = std::invoke ([&]() -> Typeface::Ptr
|
||||||
{
|
{
|
||||||
if (font.getTypefaceName() != getSystemUIFontName())
|
if (font.getTypefaceName() != getSystemUIFontName())
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -1010,7 +1010,7 @@ Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
|
||||||
auto copy = font;
|
auto copy = font;
|
||||||
copy.setTypefaceName (systemTypeface->getName());
|
copy.setTypefaceName (systemTypeface->getName());
|
||||||
return getDefaultTypefaceForFont (copy);
|
return getDefaultTypefaceForFont (copy);
|
||||||
}();
|
});
|
||||||
|
|
||||||
if (resolvedTypeface != nullptr)
|
if (resolvedTypeface != nullptr)
|
||||||
return resolvedTypeface;
|
return resolvedTypeface;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
namespace juce
|
namespace juce
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
class HbScale
|
class HbScale
|
||||||
{
|
{
|
||||||
static constexpr float factor = 1 << 16;
|
static constexpr float factor = 1 << 16;
|
||||||
|
|
@ -53,6 +54,92 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename HbType, HbType* (*incRef) (HbType*), void (*decRef) (HbType*)>
|
||||||
|
class HbPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HbPtr (HbType* i, IncrementRef incrementRefCount)
|
||||||
|
: instance (i)
|
||||||
|
{
|
||||||
|
if (incrementRefCount == IncrementRef::yes)
|
||||||
|
incRefIfNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
HbPtr() = default;
|
||||||
|
|
||||||
|
~HbPtr()
|
||||||
|
{
|
||||||
|
decRefIfNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
HbPtr (const HbPtr& other)
|
||||||
|
: HbPtr (other.instance, IncrementRef::yes)
|
||||||
|
{}
|
||||||
|
|
||||||
|
HbPtr (HbPtr&& other)
|
||||||
|
{
|
||||||
|
swap (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
HbPtr& operator= (const HbPtr& other)
|
||||||
|
{
|
||||||
|
HbPtr { other }.swap (*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HbPtr& operator= (HbPtr&& other)
|
||||||
|
{
|
||||||
|
swap (other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
HbPtr& operator= (std::nullptr_t)
|
||||||
|
{
|
||||||
|
return operator= (HbPtr { nullptr });
|
||||||
|
}
|
||||||
|
|
||||||
|
HbType* get() const { return instance; }
|
||||||
|
|
||||||
|
bool operator== (std::nullptr_t) const
|
||||||
|
{
|
||||||
|
return instance == nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void incRefIfNotNull()
|
||||||
|
{
|
||||||
|
if (instance != nullptr)
|
||||||
|
incRef (instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void decRefIfNotNull()
|
||||||
|
{
|
||||||
|
if (instance != nullptr)
|
||||||
|
decRef (instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap (HbPtr& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (instance, other.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
HbType* instance = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JUCE_HB_PTR_TYPE(type) \
|
||||||
|
HbPtr<hb_ ## type ## _t, hb_ ## type ## _reference, hb_ ## type ## _destroy>
|
||||||
|
|
||||||
|
using HbFont = JUCE_HB_PTR_TYPE (font);
|
||||||
|
using HbFontFuncs = JUCE_HB_PTR_TYPE (font_funcs);
|
||||||
|
using HbFace = JUCE_HB_PTR_TYPE (face);
|
||||||
|
using HbBuffer = JUCE_HB_PTR_TYPE (buffer);
|
||||||
|
using HbBlob = JUCE_HB_PTR_TYPE (blob);
|
||||||
|
using HbDrawFuncs = JUCE_HB_PTR_TYPE (draw_funcs);
|
||||||
|
|
||||||
|
#undef JUCE_HB_PTR_TYPE
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
#if JUCE_MAC || JUCE_IOS
|
#if JUCE_MAC || JUCE_IOS
|
||||||
template <CTFontOrientation orientation>
|
template <CTFontOrientation orientation>
|
||||||
|
|
@ -130,8 +217,7 @@ static auto getAdvancesFn()
|
||||||
*/
|
*/
|
||||||
static void overrideCTFontAdvances (hb_font_t* hb, CTFontRef fontRef)
|
static void overrideCTFontAdvances (hb_font_t* hb, CTFontRef fontRef)
|
||||||
{
|
{
|
||||||
using HbFontFuncs = std::unique_ptr<hb_font_funcs_t, FunctionPointerDestructor<hb_font_funcs_destroy>>;
|
HbFontFuncs funcs { hb_font_funcs_create(), IncrementRef::no };
|
||||||
const HbFontFuncs funcs { hb_font_funcs_create() };
|
|
||||||
|
|
||||||
// We pass the CTFontRef as user data to each of these functions.
|
// We pass the CTFontRef as user data to each of these functions.
|
||||||
// We don't pass a custom destructor for the user data, as that will be handled by the custom
|
// We don't pass a custom destructor for the user data, as that will be handled by the custom
|
||||||
|
|
@ -170,30 +256,31 @@ struct TypefaceAscentDescent
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using HbFont = std::unique_ptr<hb_font_t, FunctionPointerDestructor<hb_font_destroy>>;
|
|
||||||
using HbFace = std::unique_ptr<hb_face_t, FunctionPointerDestructor<hb_face_destroy>>;
|
|
||||||
using HbBuffer = std::unique_ptr<hb_buffer_t, FunctionPointerDestructor<hb_buffer_destroy>>;
|
|
||||||
using HbBlob = std::unique_ptr<hb_blob_t, FunctionPointerDestructor<hb_blob_destroy>>;
|
|
||||||
|
|
||||||
struct TypefaceFallbackColourGlyphSupport
|
struct TypefaceFallbackColourGlyphSupport
|
||||||
{
|
{
|
||||||
virtual ~TypefaceFallbackColourGlyphSupport() = default;
|
virtual ~TypefaceFallbackColourGlyphSupport() = default;
|
||||||
virtual std::vector<GlyphLayer> getFallbackColourGlyphLayers (int, const AffineTransform&) const = 0;
|
virtual std::vector<GlyphLayer> getFallbackColourGlyphLayers (int, const AffineTransform&) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TypefaceNativeOptions
|
||||||
|
{
|
||||||
|
HbFont font;
|
||||||
|
TypefaceAscentDescent metrics;
|
||||||
|
TypefaceFallbackColourGlyphSupport* colourGlyphSupport{};
|
||||||
|
};
|
||||||
|
|
||||||
class Typeface::Native
|
class Typeface::Native
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Native (hb_font_t* fontRef,
|
explicit Native (TypefaceNativeOptions options)
|
||||||
TypefaceAscentDescent nonPortableMetricsIn,
|
: font (std::move (options.font)),
|
||||||
const TypefaceFallbackColourGlyphSupport* colourGlyphSupportIn = {})
|
nonPortable (options.metrics),
|
||||||
: font (fontRef),
|
colourGlyphSupport (options.colourGlyphSupport)
|
||||||
nonPortable (nonPortableMetricsIn),
|
|
||||||
colourGlyphSupport (colourGlyphSupportIn)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* getFont() const { return font; }
|
// Returns the backing HarfBuzz font with a size of 1 pt (i.e. 1 pt per em).
|
||||||
|
hb_font_t* getFont() const { return font.get(); }
|
||||||
|
|
||||||
TypefaceAscentDescent getAscentDescent (TypefaceMetricsKind kind) const
|
TypefaceAscentDescent getAscentDescent (TypefaceMetricsKind kind) const
|
||||||
{
|
{
|
||||||
|
|
@ -209,52 +296,68 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<hb_glyph_extents_t> getGlyphExtents (hb_codepoint_t glyphId) const
|
||||||
|
{
|
||||||
|
return glyphExtentsCache.get (glyphId, [this] (auto gid) -> std::optional<hb_glyph_extents_t>
|
||||||
|
{
|
||||||
|
hb_glyph_extents_t extents{};
|
||||||
|
|
||||||
|
if (hb_font_get_glyph_extents (getFont(), gid, &extents) == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return extents;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
HbFont getFontAtPointSizeAndScale (float points, float horizontalScale) const
|
HbFont getFontAtPointSizeAndScale (float points, float horizontalScale) const
|
||||||
{
|
{
|
||||||
HbFont subFont { hb_font_create_sub_font (font) };
|
return subFontCache.get ({ points, horizontalScale }, [this] (auto args)
|
||||||
|
{
|
||||||
|
const auto [p, h] = args;
|
||||||
|
HbFont subFont { hb_font_create_sub_font (getFont()), IncrementRef::no };
|
||||||
|
|
||||||
hb_font_set_ptem (subFont.get(), points);
|
hb_font_set_ptem (subFont.get(), p);
|
||||||
hb_font_set_scale (subFont.get(), HbScale::juceToHb (points * horizontalScale), HbScale::juceToHb (points));
|
hb_font_set_scale (subFont.get(), HbScale::juceToHb (p * h), HbScale::juceToHb (p));
|
||||||
|
|
||||||
#if JUCE_MAC || JUCE_IOS
|
#if JUCE_MAC || JUCE_IOS
|
||||||
overrideCTFontAdvances (subFont.get(), hb_coretext_font_get_ct_font (subFont.get()));
|
overrideCTFontAdvances (subFont.get(), hb_coretext_font_get_ct_font (subFont.get()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return subFont;
|
return subFont;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<GlyphLayer> getFallbackColourGlyphLayers (int glyph,
|
std::vector<GlyphLayer> getFallbackColourGlyphLayers (int glyph,
|
||||||
const AffineTransform& transform) const
|
const AffineTransform& transform) const
|
||||||
{
|
{
|
||||||
if (colourGlyphSupport != nullptr)
|
if (colourGlyphSupport == nullptr)
|
||||||
return colourGlyphSupport->getFallbackColourGlyphLayers (glyph, transform);
|
return {};
|
||||||
|
|
||||||
return {};
|
return colourGlyphSupport->getFallbackColourGlyphLayers (glyph, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static TypefaceAscentDescent findPortableMetrics (hb_font_t* f, TypefaceAscentDescent fallback)
|
HbFont font;
|
||||||
|
TypefaceAscentDescent nonPortable;
|
||||||
|
TypefaceAscentDescent portable = std::invoke ([&]
|
||||||
{
|
{
|
||||||
hb_font_extents_t extents{};
|
hb_font_extents_t extents{};
|
||||||
|
|
||||||
if (! hb_font_get_h_extents (f, &extents))
|
if (! hb_font_get_h_extents (font.get(), &extents))
|
||||||
return fallback;
|
return nonPortable;
|
||||||
|
|
||||||
const auto ascent = std::abs ((float) extents.ascender);
|
const auto ascent = std::abs ((float) extents.ascender);
|
||||||
const auto descent = std::abs ((float) extents.descender);
|
const auto descent = std::abs ((float) extents.descender);
|
||||||
const auto upem = (float) hb_face_get_upem (hb_font_get_face (f));
|
const auto upem = (float) hb_face_get_upem (hb_font_get_face (font.get()));
|
||||||
|
|
||||||
TypefaceAscentDescent result;
|
TypefaceAscentDescent result;
|
||||||
result.ascent = ascent / upem;
|
result.ascent = ascent / upem;
|
||||||
result.descent = descent / upem;
|
result.descent = descent / upem;
|
||||||
return result;
|
return result;
|
||||||
}
|
});
|
||||||
|
TypefaceFallbackColourGlyphSupport* colourGlyphSupport;
|
||||||
hb_font_t* font = nullptr;
|
mutable LruCache<std::tuple<float, float>, HbFont> subFontCache;
|
||||||
|
mutable LruCache<hb_codepoint_t, std::optional<hb_glyph_extents_t>, 512> glyphExtentsCache;
|
||||||
TypefaceAscentDescent nonPortable;
|
|
||||||
TypefaceAscentDescent portable = findPortableMetrics (font, nonPortable);
|
|
||||||
const TypefaceFallbackColourGlyphSupport* colourGlyphSupport = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FontStyleHelpers
|
struct FontStyleHelpers
|
||||||
|
|
@ -354,12 +457,13 @@ struct FontStyleHelpers
|
||||||
(unsigned int) bytes.size(),
|
(unsigned int) bytes.size(),
|
||||||
HB_MEMORY_MODE_DUPLICATE,
|
HB_MEMORY_MODE_DUPLICATE,
|
||||||
nullptr,
|
nullptr,
|
||||||
nullptr) };
|
nullptr),
|
||||||
|
IncrementRef::no };
|
||||||
|
|
||||||
const auto count = hb_face_count (blob.get());
|
const auto count = hb_face_count (blob.get());
|
||||||
|
|
||||||
if (index < count)
|
if (index < count)
|
||||||
return HbFace { hb_face_create (blob.get(), index) };
|
return { hb_face_create (blob.get(), index), IncrementRef::no };
|
||||||
|
|
||||||
// Attempted to create a font from invalid data. Perhaps the font format was unrecognised.
|
// Attempted to create a font from invalid data. Perhaps the font format was unrecognised.
|
||||||
jassertfalse;
|
jassertfalse;
|
||||||
|
|
@ -367,20 +471,16 @@ struct FontStyleHelpers
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//==============================================================================
|
Typeface::Typeface (const String& nameIn, const String& styleIn)
|
||||||
Typeface::Typeface (const String& faceName, const String& faceStyle) noexcept
|
: name (nameIn), style (styleIn)
|
||||||
: name (faceName),
|
|
||||||
style (faceStyle)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Typeface::~Typeface() = default;
|
Typeface::~Typeface() = default;
|
||||||
|
|
||||||
using HbDrawFuncs = std::unique_ptr<hb_draw_funcs_t, FunctionPointerDestructor<hb_draw_funcs_destroy>>;
|
|
||||||
|
|
||||||
static HbDrawFuncs getPathDrawFuncs()
|
static HbDrawFuncs getPathDrawFuncs()
|
||||||
{
|
{
|
||||||
HbDrawFuncs funcs { hb_draw_funcs_create() };
|
HbDrawFuncs funcs { hb_draw_funcs_create(), IncrementRef::no };
|
||||||
|
|
||||||
hb_draw_funcs_set_move_to_func (funcs.get(), [] (auto*, void* data, auto*, float x, float y, auto*)
|
hb_draw_funcs_set_move_to_func (funcs.get(), [] (auto*, void* data, auto*, float x, float y, auto*)
|
||||||
{
|
{
|
||||||
|
|
@ -422,34 +522,32 @@ static HbDrawFuncs getPathDrawFuncs()
|
||||||
|
|
||||||
void Typeface::getOutlineForGlyph (TypefaceMetricsKind kind, int glyphNumber, Path& path) const
|
void Typeface::getOutlineForGlyph (TypefaceMetricsKind kind, int glyphNumber, Path& path) const
|
||||||
{
|
{
|
||||||
const auto native = getNativeDetails();
|
auto* font = getNativeDetails()->getFont();
|
||||||
auto* font = native.getFont();
|
const auto metrics = getNativeDetails()->getAscentDescent (kind);
|
||||||
const auto metrics = native.getAscentDescent (kind);
|
|
||||||
const auto factor = metrics.getHeightToPointsFactor();
|
const auto factor = metrics.getHeightToPointsFactor();
|
||||||
jassert (! std::isinf (factor));
|
jassert (! std::isinf (factor));
|
||||||
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
||||||
|
|
||||||
// getTypefaceGlyph returns glyphs in em space, getOutlineForGlyph returns glyphs in "special JUCE units" space
|
// getTypefaceGlyph returns glyphs in em space, getOutlineForGlyph returns glyphs in "special JUCE units" space
|
||||||
path = getGlyphPathInGlyphUnits ((hb_codepoint_t) glyphNumber, getNativeDetails().getFont());
|
path = getGlyphPathInGlyphUnits ((hb_codepoint_t) glyphNumber, font);
|
||||||
path.applyTransform (AffineTransform::scale (scale, -scale));
|
path.applyTransform (AffineTransform::scale (scale, -scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle<float> Typeface::getGlyphBounds (TypefaceMetricsKind kind, int glyphNumber) const
|
Rectangle<float> Typeface::getGlyphBounds (TypefaceMetricsKind kind, int glyphNumber) const
|
||||||
{
|
{
|
||||||
auto* font = getNativeDetails().getFont();
|
const auto extents = getNativeDetails()->getGlyphExtents ((hb_codepoint_t) glyphNumber);
|
||||||
|
|
||||||
hb_glyph_extents_t extents{};
|
if (! extents.has_value())
|
||||||
if (! hb_font_get_glyph_extents (font, (hb_codepoint_t) glyphNumber, &extents))
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const auto native = getNativeDetails();
|
auto* font = getNativeDetails()->getFont();
|
||||||
const auto metrics = native.getAscentDescent (kind);
|
const auto metrics = getNativeDetails()->getAscentDescent (kind);
|
||||||
const auto factor = metrics.getHeightToPointsFactor();
|
const auto factor = metrics.getHeightToPointsFactor();
|
||||||
jassert (! std::isinf (factor));
|
jassert (! std::isinf (factor));
|
||||||
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
||||||
|
|
||||||
return Rectangle { (float) extents.width, (float) extents.height }
|
return Rectangle { (float) extents->width, (float) extents->height }
|
||||||
.withPosition ((float) extents.x_bearing, (float) extents.y_bearing)
|
.withPosition ((float) extents->x_bearing, (float) extents->y_bearing)
|
||||||
.transformedBy (AffineTransform::scale (scale).scaled (1.0f, -1.0f));
|
.transformedBy (AffineTransform::scale (scale).scaled (1.0f, -1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,7 +575,7 @@ static Colour makeColour (hb_color_t c)
|
||||||
|
|
||||||
static std::vector<GlyphLayer> getCOLRv0Layers (const Typeface& typeface, int glyphNumber, const AffineTransform& transform)
|
static std::vector<GlyphLayer> getCOLRv0Layers (const Typeface& typeface, int glyphNumber, const AffineTransform& transform)
|
||||||
{
|
{
|
||||||
auto* font = typeface.getNativeDetails().getFont();
|
auto* font = typeface.getNativeDetails()->getFont();
|
||||||
auto* face = hb_font_get_face (font);
|
auto* face = hb_font_get_face (font);
|
||||||
constexpr auto palette = 0;
|
constexpr auto palette = 0;
|
||||||
|
|
||||||
|
|
@ -519,9 +617,16 @@ static std::vector<GlyphLayer> getBitmapLayer (const Typeface& typeface, int gly
|
||||||
if ((typeface.getColourGlyphFormats() & Typeface::colourGlyphFormatBitmap) == 0)
|
if ((typeface.getColourGlyphFormats() & Typeface::colourGlyphFormatBitmap) == 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto* font = typeface.getNativeDetails().getFont();
|
const auto* native = typeface.getNativeDetails();
|
||||||
|
const auto extents = native->getGlyphExtents ((hb_codepoint_t) glyphNumber);
|
||||||
|
|
||||||
const HbBlob blob { hb_ot_color_glyph_reference_png (font, (hb_codepoint_t) glyphNumber) };
|
if (! extents.has_value())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto* font = native->getFont();
|
||||||
|
|
||||||
|
HbBlob blob { hb_ot_color_glyph_reference_png (font, (hb_codepoint_t) glyphNumber),
|
||||||
|
IncrementRef::no };
|
||||||
|
|
||||||
unsigned int imageDataSize{};
|
unsigned int imageDataSize{};
|
||||||
const char* imageData = hb_blob_get_data (blob.get(), &imageDataSize);
|
const char* imageData = hb_blob_get_data (blob.get(), &imageDataSize);
|
||||||
|
|
@ -530,16 +635,13 @@ static std::vector<GlyphLayer> getBitmapLayer (const Typeface& typeface, int gly
|
||||||
if (juceImage.isNull())
|
if (juceImage.isNull())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
hb_glyph_extents_t extents{};
|
|
||||||
hb_font_get_glyph_extents (font, (hb_codepoint_t) glyphNumber, &extents);
|
|
||||||
|
|
||||||
const auto wDenom = std::max (1, juceImage.getWidth());
|
const auto wDenom = std::max (1, juceImage.getWidth());
|
||||||
const auto hDenom = std::max (1, juceImage.getHeight());
|
const auto hDenom = std::max (1, juceImage.getHeight());
|
||||||
|
|
||||||
const auto transform = AffineTransform::scale ((float) extents.width / (float) wDenom,
|
const auto transform = AffineTransform::scale ((float) extents->width / (float) wDenom,
|
||||||
(float) extents.height / (float) hDenom)
|
(float) extents->height / (float) hDenom)
|
||||||
.translated ((float) extents.x_bearing,
|
.translated ((float) extents->x_bearing,
|
||||||
(float) extents.y_bearing)
|
(float) extents->y_bearing)
|
||||||
.followedBy (t);
|
.followedBy (t);
|
||||||
return { GlyphLayer { ImageLayer { juceImage, transform } } };
|
return { GlyphLayer { ImageLayer { juceImage, transform } } };
|
||||||
}
|
}
|
||||||
|
|
@ -548,9 +650,8 @@ std::vector<GlyphLayer> Typeface::getLayersForGlyph (TypefaceMetricsKind kind,
|
||||||
int glyphNumber,
|
int glyphNumber,
|
||||||
const AffineTransform& transform) const
|
const AffineTransform& transform) const
|
||||||
{
|
{
|
||||||
auto native = getNativeDetails();
|
auto* font = getNativeDetails()->getFont();
|
||||||
auto* font = native.getFont();
|
const auto metrics = getNativeDetails()->getAscentDescent (kind);
|
||||||
const auto metrics = native.getAscentDescent (kind);
|
|
||||||
const auto factor = metrics.getHeightToPointsFactor();
|
const auto factor = metrics.getHeightToPointsFactor();
|
||||||
jassert (! std::isinf (factor));
|
jassert (! std::isinf (factor));
|
||||||
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
const auto scale = factor / (float) hb_face_get_upem (hb_font_get_face (font));
|
||||||
|
|
@ -569,7 +670,7 @@ std::vector<GlyphLayer> Typeface::getLayersForGlyph (TypefaceMetricsKind kind,
|
||||||
// easily display. In such cases, we can use system facilities to render the glyph into a
|
// easily display. In such cases, we can use system facilities to render the glyph into a
|
||||||
// bitmap. If the face has colour info that wasn't already handled, try rendering to a bitmap.
|
// bitmap. If the face has colour info that wasn't already handled, try rendering to a bitmap.
|
||||||
if (getColourGlyphFormats() != 0)
|
if (getColourGlyphFormats() != 0)
|
||||||
if (auto layer = native.getFallbackColourGlyphLayers (glyphNumber, combinedTransform); ! layer.empty())
|
if (auto layer = getNativeDetails()->getFallbackColourGlyphLayers (glyphNumber, combinedTransform); ! layer.empty())
|
||||||
return layer;
|
return layer;
|
||||||
|
|
||||||
// No colour info available for this glyph, so just get a simple monochromatic outline
|
// No colour info available for this glyph, so just get a simple monochromatic outline
|
||||||
|
|
@ -584,7 +685,7 @@ std::vector<GlyphLayer> Typeface::getLayersForGlyph (TypefaceMetricsKind kind,
|
||||||
|
|
||||||
int Typeface::getColourGlyphFormats() const
|
int Typeface::getColourGlyphFormats() const
|
||||||
{
|
{
|
||||||
auto* face = hb_font_get_face (getNativeDetails().getFont());
|
auto* face = hb_font_get_face (getNativeDetails()->getFont());
|
||||||
return (hb_ot_color_has_png (face) ? colourGlyphFormatBitmap : 0)
|
return (hb_ot_color_has_png (face) ? colourGlyphFormatBitmap : 0)
|
||||||
| (hb_ot_color_has_svg (face) ? colourGlyphFormatSvg : 0)
|
| (hb_ot_color_has_svg (face) ? colourGlyphFormatSvg : 0)
|
||||||
| (hb_ot_color_has_layers (face) ? colourGlyphFormatCOLRv0 : 0)
|
| (hb_ot_color_has_layers (face) ? colourGlyphFormatCOLRv0 : 0)
|
||||||
|
|
@ -593,7 +694,7 @@ int Typeface::getColourGlyphFormats() const
|
||||||
|
|
||||||
TypefaceMetrics Typeface::getMetrics (TypefaceMetricsKind kind) const
|
TypefaceMetrics Typeface::getMetrics (TypefaceMetricsKind kind) const
|
||||||
{
|
{
|
||||||
return getNativeDetails().getAscentDescent (kind).getTypefaceMetrics();
|
return getNativeDetails()->getAscentDescent (kind).getTypefaceMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize)
|
Typeface::Ptr Typeface::createSystemTypefaceFor (const void* fontFileData, size_t fontFileDataSize)
|
||||||
|
|
@ -604,7 +705,7 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (const void* fontFileData, size_
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
std::optional<uint32_t> Typeface::getNominalGlyphForCodepoint (juce_wchar cp) const
|
std::optional<uint32_t> Typeface::getNominalGlyphForCodepoint (juce_wchar cp) const
|
||||||
{
|
{
|
||||||
auto* font = getNativeDetails().getFont();
|
auto* font = getNativeDetails()->getFont();
|
||||||
|
|
||||||
if (font == nullptr)
|
if (font == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -630,14 +731,14 @@ static float doSimpleShapeWithNoBreaks (const Typeface& typeface,
|
||||||
float horizontalScale,
|
float horizontalScale,
|
||||||
Consumer&& consumer)
|
Consumer&& consumer)
|
||||||
{
|
{
|
||||||
HbBuffer buffer { hb_buffer_create() };
|
HbBuffer buffer { hb_buffer_create(), IncrementRef::no };
|
||||||
hb_buffer_add_utf8 (buffer.get(), text.toRawUTF8(), -1, 0, -1);
|
hb_buffer_add_utf8 (buffer.get(), text.toRawUTF8(), -1, 0, -1);
|
||||||
hb_buffer_set_cluster_level (buffer.get(), HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
hb_buffer_set_cluster_level (buffer.get(), HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
||||||
hb_buffer_guess_segment_properties (buffer.get());
|
hb_buffer_guess_segment_properties (buffer.get());
|
||||||
|
|
||||||
const auto& native = typeface.getNativeDetails();
|
const auto* native = typeface.getNativeDetails();
|
||||||
const auto points = typeface.getMetrics (kind).heightToPoints * height;
|
const auto points = typeface.getMetrics (kind).heightToPoints * height;
|
||||||
const auto sized = native.getFontAtPointSizeAndScale (points, horizontalScale);
|
const auto sized = native->getFontAtPointSizeAndScale (points, horizontalScale);
|
||||||
auto* font = sized.get();
|
auto* font = sized.get();
|
||||||
|
|
||||||
// Disable ligatures, because TextEditor requires a 1:1 codepoint/glyph mapping for caret
|
// Disable ligatures, because TextEditor requires a 1:1 codepoint/glyph mapping for caret
|
||||||
|
|
@ -737,7 +838,7 @@ std::vector<FontFeatureTag> Typeface::getSupportedFeatures() const
|
||||||
HB_OT_TAG_GSUB
|
HB_OT_TAG_GSUB
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* face = hb_font_get_face (getNativeDetails().getFont());
|
auto* face = hb_font_get_face (getNativeDetails()->getFont());
|
||||||
|
|
||||||
for (auto table : tagTables)
|
for (auto table : tagTables)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,6 @@ struct TypefaceMetrics
|
||||||
class JUCE_API Typeface : public ReferenceCountedObject
|
class JUCE_API Typeface : public ReferenceCountedObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Typeface (const String& name, const String& newStyle) noexcept;
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
/** A handy typedef for a pointer to a typeface. */
|
/** A handy typedef for a pointer to a typeface. */
|
||||||
using Ptr = ReferenceCountedObjectPtr<Typeface>;
|
using Ptr = ReferenceCountedObjectPtr<Typeface>;
|
||||||
|
|
@ -315,17 +313,6 @@ public:
|
||||||
*/
|
*/
|
||||||
std::optional<uint32_t> getNominalGlyphForCodepoint (juce_wchar) const;
|
std::optional<uint32_t> getNominalGlyphForCodepoint (juce_wchar) const;
|
||||||
|
|
||||||
/** @internal */
|
|
||||||
class Native;
|
|
||||||
|
|
||||||
/** @internal
|
|
||||||
|
|
||||||
At the moment, this is a way to get at the hb_font_t that backs this typeface.
|
|
||||||
The typeface's hb_font_t has a size of 1 pt (i.e. 1 pt per em).
|
|
||||||
This is only for internal use!
|
|
||||||
*/
|
|
||||||
virtual Native getNativeDetails() const = 0;
|
|
||||||
|
|
||||||
/** Attempts to locate a font with a similar style that is capable of displaying the requested
|
/** Attempts to locate a font with a similar style that is capable of displaying the requested
|
||||||
string.
|
string.
|
||||||
|
|
||||||
|
|
@ -394,6 +381,16 @@ public:
|
||||||
*/
|
*/
|
||||||
std::vector<FontFeatureTag> getSupportedFeatures() const;
|
std::vector<FontFeatureTag> getSupportedFeatures() const;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
class Native;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
virtual const Native* getNativeDetails() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** @internal */
|
||||||
|
Typeface (const String&, const String&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
String name;
|
String name;
|
||||||
|
|
|
||||||
|
|
@ -130,11 +130,6 @@ public:
|
||||||
return fromFont (dwFont, customFontCollection, nullptr, MetricsMechanism::gdiWithDwriteFallback);
|
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
|
Typeface::Ptr createSystemFallback (const String& c, const String& language) const override
|
||||||
{
|
{
|
||||||
auto factory = factories->getDWriteFactory().getInterface<IDWriteFactory2>();
|
auto factory = factories->getDWriteFactory().getInterface<IDWriteFactory2>();
|
||||||
|
|
@ -171,6 +166,11 @@ public:
|
||||||
|
|
||||||
ComSmartPtr<IDWriteFontFace> getIDWriteFontFace() const { return dwFontFace; }
|
ComSmartPtr<IDWriteFontFace> getIDWriteFontFace() const { return dwFontFace; }
|
||||||
|
|
||||||
|
const Native* getNativeDetails() const override
|
||||||
|
{
|
||||||
|
return native.get();
|
||||||
|
}
|
||||||
|
|
||||||
static Typeface::Ptr findSystemTypeface()
|
static Typeface::Ptr findSystemTypeface()
|
||||||
{
|
{
|
||||||
NONCLIENTMETRICS nonClientMetrics{};
|
NONCLIENTMETRICS nonClientMetrics{};
|
||||||
|
|
@ -295,8 +295,7 @@ private:
|
||||||
collection (std::move (collectionIn)),
|
collection (std::move (collectionIn)),
|
||||||
dwFont (font),
|
dwFont (font),
|
||||||
dwFontFace (face),
|
dwFontFace (face),
|
||||||
hbFont (std::move (hbFontIn)),
|
native (std::make_unique<Native> (TypefaceNativeOptions { std::move (hbFontIn), metrics }))
|
||||||
nonPortableMetrics (metrics)
|
|
||||||
{
|
{
|
||||||
if (collection != nullptr)
|
if (collection != nullptr)
|
||||||
factories->getFonts().addCollection (collection);
|
factories->getFonts().addCollection (collection);
|
||||||
|
|
@ -341,8 +340,9 @@ private:
|
||||||
const auto name = getLocalisedFamilyName (*dwFont);
|
const auto name = getLocalisedFamilyName (*dwFont);
|
||||||
const auto style = getLocalisedStyle (*dwFont);
|
const auto style = getLocalisedStyle (*dwFont);
|
||||||
|
|
||||||
const HbFace hbFace { hb_directwrite_face_create (dwFace) };
|
HbFace hbFace { hb_directwrite_face_create (dwFace), IncrementRef::no };
|
||||||
HbFont font { hb_font_create (hbFace.get()) };
|
HbFont font { hb_font_create (hbFace.get()), IncrementRef::no };
|
||||||
|
|
||||||
const auto dwMetrics = getDwriteMetrics (*dwFace);
|
const auto dwMetrics = getDwriteMetrics (*dwFace);
|
||||||
|
|
||||||
const auto metrics = mm == MetricsMechanism::gdiWithDwriteFallback
|
const auto metrics = mm == MetricsMechanism::gdiWithDwriteFallback
|
||||||
|
|
@ -411,8 +411,7 @@ private:
|
||||||
ComSmartPtr<IDWriteFontCollection> collection;
|
ComSmartPtr<IDWriteFontCollection> collection;
|
||||||
ComSmartPtr<IDWriteFont> dwFont;
|
ComSmartPtr<IDWriteFont> dwFont;
|
||||||
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
ComSmartPtr<IDWriteFontFace> dwFontFace;
|
||||||
HbFont hbFont;
|
std::unique_ptr<Native> native;
|
||||||
TypefaceAscentDescent nonPortableMetrics;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DefaultFontNames
|
struct DefaultFontNames
|
||||||
|
|
|
||||||
|
|
@ -93,9 +93,9 @@ std::unique_ptr<InputStream> makeAndroidInputStreamWrapper (LocalRef<jobject> st
|
||||||
|
|
||||||
struct AndroidCachedTypeface
|
struct AndroidCachedTypeface
|
||||||
{
|
{
|
||||||
std::shared_ptr<hb_font_t> font;
|
HbFont font;
|
||||||
GlobalRef javaFont;
|
GlobalRef javaFont;
|
||||||
TypefaceAscentDescent nonPortableMetrics;
|
TypefaceAscentDescent metrics;
|
||||||
};
|
};
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
@ -235,7 +235,7 @@ public:
|
||||||
{
|
{
|
||||||
return new AndroidTypeface (DoCache::no,
|
return new AndroidTypeface (DoCache::no,
|
||||||
result->font,
|
result->font,
|
||||||
result->nonPortableMetrics,
|
result->metrics,
|
||||||
font.getTypefaceName(),
|
font.getTypefaceName(),
|
||||||
font.getTypefaceStyle(),
|
font.getTypefaceStyle(),
|
||||||
result->javaFont);
|
result->javaFont);
|
||||||
|
|
@ -251,7 +251,7 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
HbFont hbFont { hb_font_create (face.get()) };
|
HbFont hbFont { hb_font_create (face.get()), IncrementRef::no };
|
||||||
FontStyleHelpers::initSynthetics (hbFont.get(), font);
|
FontStyleHelpers::initSynthetics (hbFont.get(), font);
|
||||||
|
|
||||||
const auto androidFont = shouldStoreAndroidFont (face.get())
|
const auto androidFont = shouldStoreAndroidFont (face.get())
|
||||||
|
|
@ -271,11 +271,6 @@ public:
|
||||||
return fromMemory (DoCache::yes, blob, index);
|
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
|
Typeface::Ptr createSystemFallback (const String& text, const String& language) const override
|
||||||
{
|
{
|
||||||
if (__builtin_available (android 29, *))
|
if (__builtin_available (android 29, *))
|
||||||
|
|
@ -293,6 +288,11 @@ public:
|
||||||
c->remove ({ getName(), getStyle() });
|
c->remove ({ getName(), getStyle() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Native* getNativeDetails() const override
|
||||||
|
{
|
||||||
|
return native.get();
|
||||||
|
}
|
||||||
|
|
||||||
static Typeface::Ptr findSystemTypeface()
|
static Typeface::Ptr findSystemTypeface()
|
||||||
{
|
{
|
||||||
if (__builtin_available (android 29, *))
|
if (__builtin_available (android 29, *))
|
||||||
|
|
@ -358,8 +358,8 @@ private:
|
||||||
|
|
||||||
const AFontMatcherPtr matcher { AFontMatcher_create() };
|
const AFontMatcherPtr matcher { AFontMatcher_create() };
|
||||||
|
|
||||||
const auto weight = hb_style_get_value (hbFont.get(), HB_STYLE_TAG_WEIGHT);
|
const auto weight = hb_style_get_value (native->getFont(), HB_STYLE_TAG_WEIGHT);
|
||||||
const auto italic = hb_style_get_value (hbFont.get(), HB_STYLE_TAG_ITALIC) != 0.0f;
|
const auto italic = hb_style_get_value (native->getFont(), HB_STYLE_TAG_ITALIC) != 0.0f;
|
||||||
AFontMatcher_setStyle (matcher.get(), (uint16_t) weight, italic);
|
AFontMatcher_setStyle (matcher.get(), (uint16_t) weight, italic);
|
||||||
|
|
||||||
AFontMatcher_setLocales (matcher.get(), language.toRawUTF8());
|
AFontMatcher_setLocales (matcher.get(), language.toRawUTF8());
|
||||||
|
|
@ -367,7 +367,7 @@ private:
|
||||||
const auto utf16 = text.toUTF16();
|
const auto utf16 = text.toUTF16();
|
||||||
|
|
||||||
const AFontPtr matched { AFontMatcher_match (matcher.get(),
|
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,
|
HB_OT_NAME_ID_FONT_FAMILY,
|
||||||
nullptr).toRawUTF8(),
|
nullptr).toRawUTF8(),
|
||||||
unalignedPointerCast<const uint16_t*> (utf16.getAddress()),
|
unalignedPointerCast<const uint16_t*> (utf16.getAddress()),
|
||||||
|
|
@ -442,7 +442,7 @@ private:
|
||||||
const auto metrics = findNonPortableMetricsForData (blob);
|
const auto metrics = findNonPortableMetricsForData (blob);
|
||||||
|
|
||||||
return new AndroidTypeface (cache,
|
return new AndroidTypeface (cache,
|
||||||
HbFont { hb_font_create (face.get()) },
|
HbFont (hb_font_create (face.get()), IncrementRef::no),
|
||||||
metrics,
|
metrics,
|
||||||
readFontName (face.get(), HB_OT_NAME_ID_FONT_FAMILY, nullptr),
|
readFontName (face.get(), HB_OT_NAME_ID_FONT_FAMILY, nullptr),
|
||||||
readFontName (face.get(), HB_OT_NAME_ID_FONT_SUBFAMILY, nullptr),
|
readFontName (face.get(), HB_OT_NAME_ID_FONT_SUBFAMILY, nullptr),
|
||||||
|
|
@ -461,20 +461,19 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidTypeface (DoCache cache,
|
AndroidTypeface (DoCache cache,
|
||||||
std::shared_ptr<hb_font_t> fontIn,
|
HbFont fontIn,
|
||||||
TypefaceAscentDescent nonPortableMetricsIn,
|
TypefaceAscentDescent nonPortableMetricsIn,
|
||||||
const String& name,
|
const String& name,
|
||||||
const String& style,
|
const String& style,
|
||||||
GlobalRef javaFontIn)
|
GlobalRef javaFontIn)
|
||||||
: Typeface (name, style),
|
: Typeface (name, style),
|
||||||
hbFont (std::move (fontIn)),
|
|
||||||
doCache (cache),
|
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 (doCache == DoCache::yes)
|
||||||
if (auto* c = MemoryFontCache::getInstance())
|
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)
|
static std::tuple<MemoryBlock, TypefaceAscentDescent> getBlobForFont (const Font& font)
|
||||||
|
|
@ -664,22 +663,22 @@ private:
|
||||||
|
|
||||||
auto* env = getEnv();
|
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?
|
// Trying to retrieve an image for a glyph that's not present in the font?
|
||||||
jassertfalse;
|
jassertfalse;
|
||||||
return {};
|
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;
|
constexpr jint referenceSize = 128;
|
||||||
|
|
||||||
const jint pixelW = (referenceSize * abs (extents.width)) / upem;
|
const jint pixelW = (referenceSize * abs (extents->width)) / upem;
|
||||||
const jint pixelH = (referenceSize * abs (extents.height)) / upem;
|
const jint pixelH = (referenceSize * abs (extents->height)) / upem;
|
||||||
const jint pixelBearingX = (referenceSize * extents.x_bearing) / upem;
|
const jint pixelBearingX = (referenceSize * extents->x_bearing) / upem;
|
||||||
const jint pixelBearingY = (referenceSize * extents.y_bearing) / upem;
|
const jint pixelBearingY = (referenceSize * extents->y_bearing) / upem;
|
||||||
|
|
||||||
const jint pixelPadding = 2;
|
const jint pixelPadding = 2;
|
||||||
|
|
||||||
|
|
@ -760,10 +759,9 @@ private:
|
||||||
.followedBy (transform) } } };
|
.followedBy (transform) } } };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<hb_font_t> hbFont;
|
|
||||||
DoCache doCache;
|
DoCache doCache;
|
||||||
TypefaceAscentDescent nonPortableMetrics;
|
|
||||||
GlobalRef javaFont;
|
GlobalRef javaFont;
|
||||||
|
std::unique_ptr<Native> native;
|
||||||
};
|
};
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
||||||
|
|
@ -394,10 +394,8 @@ public:
|
||||||
if (face == nullptr)
|
if (face == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto* hbFace = hb_ft_face_create_referenced (face->face);
|
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
|
||||||
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
|
HbFont hb { hb_font_create (hbFace.get()), IncrementRef::no };
|
||||||
|
|
||||||
HbFont hb { hb_font_create (hbFace) };
|
|
||||||
|
|
||||||
if (hb == nullptr)
|
if (hb == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -413,10 +411,8 @@ public:
|
||||||
if (face == nullptr)
|
if (face == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto* hbFace = hb_ft_face_create_referenced (face->face);
|
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
|
||||||
const ScopeGuard scope { [&] { hb_face_destroy (hbFace); } };
|
HbFont hb { hb_font_create (hbFace.get()), IncrementRef::no };
|
||||||
|
|
||||||
HbFont hb { hb_font_create (hbFace) };
|
|
||||||
|
|
||||||
if (hb == nullptr)
|
if (hb == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -424,11 +420,6 @@ public:
|
||||||
return new FreeTypeTypeface (DoCache::yes, face, std::move (hb), face->face->family_name, face->face->style_name);
|
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,
|
Typeface::Ptr createSystemFallback ([[maybe_unused]] const String& text,
|
||||||
[[maybe_unused]] const String& language) const override
|
[[maybe_unused]] const String& language) const override
|
||||||
{
|
{
|
||||||
|
|
@ -478,11 +469,18 @@ public:
|
||||||
|
|
||||||
~FreeTypeTypeface() override
|
~FreeTypeTypeface() override
|
||||||
{
|
{
|
||||||
|
native.reset();
|
||||||
|
|
||||||
if (doCache == DoCache::yes)
|
if (doCache == DoCache::yes)
|
||||||
if (auto* list = FTTypefaceList::getInstanceWithoutCreating())
|
if (auto* list = FTTypefaceList::getInstanceWithoutCreating())
|
||||||
list->removeMemoryFace (ftFace);
|
list->removeMemoryFace (ftFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Native* getNativeDetails() const override
|
||||||
|
{
|
||||||
|
return native.get();
|
||||||
|
}
|
||||||
|
|
||||||
static Typeface::Ptr findSystemTypeface()
|
static Typeface::Ptr findSystemTypeface()
|
||||||
{
|
{
|
||||||
#if JUCE_USE_FONTCONFIG
|
#if JUCE_USE_FONTCONFIG
|
||||||
|
|
@ -530,8 +528,8 @@ private:
|
||||||
if (face == nullptr)
|
if (face == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const HbFace hbFace { hb_ft_face_create_referenced (face->face) };
|
HbFace hbFace { hb_ft_face_create_referenced (face->face), IncrementRef::no };
|
||||||
HbFont cachedFont { hb_font_create (hbFace.get()) };
|
HbFont cachedFont { hb_font_create (hbFace.get()), IncrementRef::no };
|
||||||
|
|
||||||
if (cachedFont == nullptr)
|
if (cachedFont == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -541,6 +539,15 @@ private:
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
FreeTypeTypeface (DoCache cache,
|
||||||
FTFaceWrapper::Ptr ftFaceIn,
|
FTFaceWrapper::Ptr ftFaceIn,
|
||||||
HbFont hbIn,
|
HbFont hbIn,
|
||||||
|
|
@ -548,8 +555,8 @@ private:
|
||||||
const String& styleIn)
|
const String& styleIn)
|
||||||
: Typeface (nameIn, styleIn),
|
: Typeface (nameIn, styleIn),
|
||||||
ftFace (ftFaceIn),
|
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 (doCache == DoCache::yes)
|
||||||
if (auto* list = FTTypefaceList::getInstance())
|
if (auto* list = FTTypefaceList::getInstance())
|
||||||
|
|
@ -557,10 +564,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
FTFaceWrapper::Ptr ftFace;
|
FTFaceWrapper::Ptr ftFace;
|
||||||
HbFont hb;
|
|
||||||
DoCache doCache;
|
DoCache doCache;
|
||||||
TypefaceAscentDescent nonPortableMetrics { (float) std::abs (ftFace->face->ascender) / (float) ftFace->face->units_per_EM,
|
std::unique_ptr<Native> native;
|
||||||
(float) std::abs (ftFace->face->descender) / (float) ftFace->face->units_per_EM };
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
|
JUCE_DECLARE_NON_COPYABLE (FreeTypeTypeface)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -174,14 +174,17 @@ public:
|
||||||
if (ctFont == nullptr)
|
if (ctFont == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
HbFont result { hb_coretext_font_create (ctFont.get()) };
|
HbFont result { hb_coretext_font_create (ctFont.get()), IncrementRef::no };
|
||||||
|
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
FontStyleHelpers::initSynthetics (result.get(), font);
|
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)
|
static Typeface::Ptr from (Span<const std::byte> data)
|
||||||
|
|
@ -220,7 +223,7 @@ public:
|
||||||
if (ctFont == nullptr)
|
if (ctFont == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
HbFont result { hb_coretext_font_create (ctFont.get()) };
|
HbFont result { hb_coretext_font_create (ctFont.get()), IncrementRef::no };
|
||||||
|
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -235,11 +238,6 @@ public:
|
||||||
std::move (copy));
|
std::move (copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
Native getNativeDetails() const override
|
|
||||||
{
|
|
||||||
return Native { hb.get(), nonPortableMetrics };
|
|
||||||
}
|
|
||||||
|
|
||||||
Typeface::Ptr createSystemFallback (const String& c, const String& language) const override
|
Typeface::Ptr createSystemFallback (const String& c, const String& language) const override
|
||||||
{
|
{
|
||||||
const CFUniquePtr<CFStringRef> cfText { c.toCFString() };
|
const CFUniquePtr<CFStringRef> cfText { c.toCFString() };
|
||||||
|
|
@ -261,7 +259,7 @@ public:
|
||||||
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
|
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
|
||||||
kCTFontStyleNameAttribute) };
|
kCTFontStyleNameAttribute) };
|
||||||
|
|
||||||
HbFont result { hb_coretext_font_create (newFont.get()) };
|
HbFont result { hb_coretext_font_create (newFont.get()), IncrementRef::no };
|
||||||
|
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -293,6 +291,11 @@ public:
|
||||||
return ctFont.get();
|
return ctFont.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Native* getNativeDetails() const override
|
||||||
|
{
|
||||||
|
return native.get();
|
||||||
|
}
|
||||||
|
|
||||||
static Typeface::Ptr findSystemTypeface()
|
static Typeface::Ptr findSystemTypeface()
|
||||||
{
|
{
|
||||||
CFUniquePtr<CTFontRef> defaultCtFont (CTFontCreateUIFontForLanguage (kCTFontUIFontSystem, 0.0, nullptr));
|
CFUniquePtr<CTFontRef> defaultCtFont (CTFontCreateUIFontForLanguage (kCTFontUIFontSystem, 0.0, nullptr));
|
||||||
|
|
@ -301,7 +304,7 @@ public:
|
||||||
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
|
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
|
||||||
kCTFontStyleNameAttribute) };
|
kCTFontStyleNameAttribute) };
|
||||||
|
|
||||||
HbFont result { hb_coretext_font_create (defaultCtFont.get()) };
|
HbFont result { hb_coretext_font_create (defaultCtFont.get()), IncrementRef::no };
|
||||||
|
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -314,6 +317,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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,
|
CoreTextTypeface (CFUniquePtr<CTFontRef> nativeFont,
|
||||||
HbFont fontIn,
|
HbFont fontIn,
|
||||||
const String& name,
|
const String& name,
|
||||||
|
|
@ -321,8 +335,8 @@ private:
|
||||||
MemoryBlock data = {})
|
MemoryBlock data = {})
|
||||||
: Typeface (name, style),
|
: Typeface (name, style),
|
||||||
ctFont (std::move (nativeFont)),
|
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())
|
if (! storage.isEmpty())
|
||||||
getRegistered().add (ctFont.get());
|
getRegistered().add (ctFont.get());
|
||||||
|
|
@ -342,15 +356,8 @@ private:
|
||||||
// We store this, rather than calling hb_coretext_font_get_ct_font, because harfbuzz may
|
// We store this, rather than calling hb_coretext_font_get_ct_font, because harfbuzz may
|
||||||
// override the font cascade list in the returned font.
|
// override the font cascade list in the returned font.
|
||||||
CFUniquePtr<CTFontRef> ctFont;
|
CFUniquePtr<CTFontRef> ctFont;
|
||||||
HbFont hb;
|
|
||||||
MemoryBlock storage;
|
MemoryBlock storage;
|
||||||
TypefaceAscentDescent nonPortableMetrics = [&]
|
std::unique_ptr<Native> native;
|
||||||
{
|
|
||||||
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) };
|
|
||||||
}();
|
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreTextTypeface)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreTextTypeface)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue