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

Typeface: Add support for querying the default system UI typeface

This commit is contained in:
reuk 2024-04-17 17:26:13 +01:00
parent c083d3e9f1
commit c5a9e26960
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
8 changed files with 233 additions and 54 deletions

View file

@ -566,24 +566,45 @@ public:
ComSmartPtr<IDWriteFontFace> getIDWriteFontFace() const { return dwFontFace; }
private:
float getKerning (int glyph1, int glyph2) const
static Typeface::Ptr findSystemTypeface()
{
const auto face = dwFontFace.getInterface<IDWriteFontFace1>();
NONCLIENTMETRICS nonClientMetrics{};
nonClientMetrics.cbSize = sizeof (NONCLIENTMETRICS);
const UINT16 glyphs[] { (UINT16) glyph1, (UINT16) glyph2 };
INT32 advances [std::size (glyphs)]{};
if (FAILED (face->GetDesignGlyphAdvances ((UINT32) std::size (glyphs), std::data (glyphs), std::data (advances))))
if (! SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICS), &nonClientMetrics, sizeof (NONCLIENTMETRICS)))
return {};
DWRITE_FONT_METRICS metrics{};
face->GetMetrics (&metrics);
SharedResourcePointer<Direct2DFactories> factories;
// TODO(reuk) incorrect
return (float) advances[0] / (float) metrics.designUnitsPerEm;
ComSmartPtr<IDWriteGdiInterop> interop;
if (FAILED (factories->getDWriteFactory()->GetGdiInterop (interop.resetAndGetPointerAddress())) || interop == nullptr)
return {};
ComSmartPtr<IDWriteFont> dwFont;
if (FAILED (interop->CreateFontFromLOGFONT (&nonClientMetrics.lfMessageFont, dwFont.resetAndGetPointerAddress())) || dwFont == nullptr)
return {};
ComSmartPtr<IDWriteFontFace> dwFontFace;
if (FAILED (dwFont->CreateFontFace (dwFontFace.resetAndGetPointerAddress())) || dwFontFace == nullptr)
return {};
const auto name = getLocalisedFamilyName (*dwFont);
const auto style = getLocalisedStyle (*dwFont);
const HbFace hbFace { hb_directwrite_face_create (dwFontFace) };
HbFont font { hb_font_create (hbFace.get()) };
const auto metrics = getGdiMetrics (font.get()).value_or (getDwriteMetrics (dwFontFace));
return new WindowsDirectWriteTypeface (name,
style,
dwFont,
dwFontFace,
std::move (font),
metrics,
{});
}
private:
static UINT32 numUtf16Words (const CharPointer_UTF16& str)
{
return (UINT32) (str.findTerminatingNull().getAddress() - str.getAddress());
@ -795,7 +816,7 @@ struct DefaultFontNames
String defaultSans, defaultSerif, defaultFixed, defaultFallback;
};
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
Typeface::Ptr Font::Native::getDefaultPlatformTypefaceForFont (const Font& font)
{
static DefaultFontNames defaultNames;
@ -822,6 +843,11 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
return WindowsDirectWriteTypeface::from (data);
}
Typeface::Ptr Typeface::findSystemTypeface()
{
return WindowsDirectWriteTypeface::findSystemTypeface();
}
void Typeface::scanFolderForFonts (const File&)
{
// TODO(reuk)

View file

@ -35,7 +35,7 @@
namespace juce
{
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
Typeface::Ptr Font::Native::getDefaultPlatformTypefaceForFont (const Font& font)
{
Font f (font);
f.setTypefaceName ([&]() -> String
@ -285,10 +285,58 @@ public:
c->remove ({ getName(), getStyle() });
}
static Typeface::Ptr findSystemTypeface()
{
if (__builtin_available (android 29, *))
return findSystemTypefaceWithMatcher();
return from (FontOptions{}.withName ("Roboto"));
}
private:
static __INTRODUCED_IN (29) Typeface::Ptr fromMatchedFont (AFont* matched)
{
if (matched == nullptr)
{
// Unable to find any matching fonts. This should never happen - in the worst case,
// we should at least get a font with the tofu character.
jassertfalse;
return {};
}
const File matchedFile { AFont_getFontFilePath (matched) };
const auto matchedIndex = AFont_getCollectionIndex (matched);
auto* cache = TypefaceFileCache::getInstance();
if (cache == nullptr)
return {}; // Perhaps we're shutting down
return cache->get ({ matchedFile, (int) matchedIndex }, &loadCompatibleFont);
}
static __INTRODUCED_IN (29) Typeface::Ptr findSystemTypefaceWithMatcher()
{
using AFontMatcherPtr = std::unique_ptr<AFontMatcher, FunctionPointerDestructor<AFontMatcher_destroy>>;
using AFontPtr = std::unique_ptr<AFont, FunctionPointerDestructor<AFont_close>>;
constexpr uint16_t testString[] { 't', 'e', 's', 't' };
const AFontMatcherPtr matcher { AFontMatcher_create() };
const AFontPtr matched { AFontMatcher_match (matcher.get(),
"system-ui",
testString,
std::size (testString),
nullptr) };
return fromMatchedFont (matched.get());
}
__INTRODUCED_IN (29) Typeface::Ptr matchWithAFontMatcher (const String& text, const String& language) const
{
using AFontMatcherPtr = std::unique_ptr<AFontMatcher, FunctionPointerDestructor<AFontMatcher_destroy>>;
using AFontPtr = std::unique_ptr<AFont, FunctionPointerDestructor<AFont_close>>;
const AFontMatcherPtr matcher { AFontMatcher_create() };
const auto weight = hb_style_get_value (hbFont.get(), HB_STYLE_TAG_WEIGHT);
@ -299,7 +347,6 @@ private:
const auto utf16 = text.toUTF16();
using AFontPtr = std::unique_ptr<AFont, FunctionPointerDestructor<AFont_close>>;
const AFontPtr matched { AFontMatcher_match (matcher.get(),
readFontName (hb_font_get_face (hbFont.get()),
HB_OT_NAME_ID_FONT_FAMILY,
@ -308,23 +355,7 @@ private:
(uint32_t) (utf16.findTerminatingNull().getAddress() - utf16.getAddress()),
nullptr) };
if (matched == nullptr)
{
// Unable to find any matching fonts. This should never happen - in the worst case,
// we should at least get a font with the tofu character.
jassertfalse;
return {};
}
const File matchedFile { AFont_getFontFilePath (matched.get()) };
const auto matchedIndex = AFont_getCollectionIndex (matched.get());
auto* cache = TypefaceFileCache::getInstance();
if (cache == nullptr)
return {}; // Perhaps we're shutting down
return cache->get ({ matchedFile, (int) matchedIndex }, &loadCompatibleFont);
return fromMatchedFont (matched.get());
}
static Typeface::Ptr loadCompatibleFont (const TypefaceFileAndIndex& info)
@ -592,6 +623,11 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
return AndroidTypeface::from (data);
}
Typeface::Ptr Typeface::findSystemTypeface()
{
return AndroidTypeface::findSystemTypeface();
}
void Typeface::scanFolderForFonts (const File&)
{
jassertfalse; // not currently available

View file

@ -39,10 +39,12 @@
namespace juce
{
#if JUCE_USE_FONTCONFIG
using FcConfigPtr = std::unique_ptr<FcConfig, FunctionPointerDestructor<FcConfigDestroy>>;
using FcPatternPtr = std::unique_ptr<FcPattern, FunctionPointerDestructor<FcPatternDestroy>>;
using FcCharSetPtr = std::unique_ptr<FcCharSet, FunctionPointerDestructor<FcCharSetDestroy>>;
using FcLangSetPtr = std::unique_ptr<FcLangSet, FunctionPointerDestructor<FcLangSetDestroy>>;
#endif
struct FTLibWrapper final : public ReferenceCountedObject
{
@ -61,7 +63,10 @@ struct FTLibWrapper final : public ReferenceCountedObject
FT_Done_FreeType (library);
}
#if JUCE_USE_FONTCONFIG
const FcConfigPtr fcConfig { FcInitLoadConfigAndFonts() };
#endif
FT_Library library = {};
using Ptr = ReferenceCountedObjectPtr<FTLibWrapper>;
@ -317,6 +322,8 @@ public:
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FTTypefaceList)
FTLibWrapper::Ptr getLibrary() const { return library; }
private:
FTLibWrapper::Ptr library = new FTLibWrapper;
std::vector<std::unique_ptr<KnownTypeface>> faces;
@ -437,7 +444,6 @@ public:
if (cache == nullptr)
return {};
auto* config = ftFace->library->fcConfig.get();
FcPatternPtr pattern { FcPatternCreate() };
{
@ -468,11 +474,47 @@ public:
FcPatternAddLangSet (pattern.get(), FC_LANG, langset.get());
}
FcConfigSubstitute (config, pattern.get(), FcMatchPattern);
FcDefaultSubstitute (pattern.get());
return fromPattern (pattern.get());
#else
// Font substitution will not work unless fontconfig is enabled.
jassertfalse;
return nullptr;
#endif
}
~FreeTypeTypeface() override
{
if (doCache == DoCache::yes)
if (auto* list = FTTypefaceList::getInstance())
list->removeMemoryFace (ftFace);
}
static Typeface::Ptr findSystemTypeface()
{
#if JUCE_USE_FONTCONFIG
FcPatternPtr pattern { FcNameParse (unalignedPointerCast<const FcChar8*> ("system-ui")) };
return fromPattern (pattern.get());
#else
return nullptr;
#endif
}
private:
#if JUCE_USE_FONTCONFIG
static Typeface::Ptr fromPattern (FcPattern* pattern)
{
auto* cache = TypefaceFileCache::getInstance();
if (cache == nullptr)
return {};
const auto library = FTTypefaceList::getInstance()->getLibrary();
FcConfigSubstitute (library->fcConfig.get(), pattern, FcMatchPattern);
FcDefaultSubstitute (pattern);
FcResult result{};
const FcPatternPtr matched { FcFontMatch (config, pattern.get(), &result) };
const FcPatternPtr matched { FcFontMatch (library->fcConfig.get(), pattern, &result) };
if (result != FcResultMatch)
return {};
@ -502,21 +544,9 @@ public:
return new FreeTypeTypeface (DoCache::no, face, std::move (cachedFont), face->face->family_name, face->face->style_name);
});
#else
// Font substitution will not work unless fontconfig is enabled.
jassertfalse;
return nullptr;
#endif
}
#endif
~FreeTypeTypeface() override
{
if (doCache == DoCache::yes)
if (auto* list = FTTypefaceList::getInstance())
list->removeMemoryFace (ftFace);
}
private:
FreeTypeTypeface (DoCache cache,
FTFaceWrapper::Ptr ftFaceIn,
HbFont hbIn,
@ -551,4 +581,9 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (Span<const std::byte> data)
return FreeTypeTypeface::from (data);
}
Typeface::Ptr Typeface::findSystemTypeface()
{
return FreeTypeTypeface::findSystemTypeface();
}
} // namespace juce

View file

@ -197,7 +197,7 @@ private:
JUCE_DECLARE_NON_COPYABLE (DefaultFontInfo)
};
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
Typeface::Ptr Font::Native::getDefaultPlatformTypefaceForFont (const Font& font)
{
static const DefaultFontInfo defaultInfo;

View file

@ -667,6 +667,26 @@ public:
return ctFont.get();
}
static Typeface::Ptr findSystemTypeface()
{
CFUniquePtr<CTFontRef> defaultCtFont (CTFontCreateUIFontForLanguage (kCTFontUIFontSystem, 0.0, nullptr));
const CFUniquePtr<CFStringRef> newName { CTFontCopyFamilyName (defaultCtFont.get()) };
const CFUniquePtr<CTFontDescriptorRef> descriptor { CTFontCopyFontDescriptor (defaultCtFont.get()) };
const CFUniquePtr<CFStringRef> newStyle { (CFStringRef) CTFontDescriptorCopyAttribute (descriptor.get(),
kCTFontStyleNameAttribute) };
HbFont result { hb_coretext_font_create (defaultCtFont.get()) };
if (result == nullptr)
return {};
return new CoreTextTypeface { std::move (defaultCtFont),
std::move (result),
String::fromCFString (newName.get()),
String::fromCFString (newStyle.get()),
{} };
}
private:
CoreTextTypeface (CFUniquePtr<CTFontRef> nativeFont,
HbFont fontIn,
@ -737,6 +757,11 @@ void Typeface::scanFolderForFonts (const File& folder)
CTFontManagerRegisterFontsForURL (urlref.get(), kCTFontManagerScopeProcess, nullptr);
}
Typeface::Ptr Typeface::findSystemTypeface()
{
return CoreTextTypeface::findSystemTypeface();
}
StringArray Font::findAllTypefaceNames()
{
StringArray names;
@ -807,7 +832,7 @@ struct DefaultFontNames
#endif
};
Typeface::Ptr Font::getDefaultTypefaceForFont (const Font& font)
Typeface::Ptr Font::Native::getDefaultPlatformTypefaceForFont (const Font& font)
{
static DefaultFontNames defaultNames;