Skip to content

Commit 85cc11f

Browse files
committed
Add: Mac OS font searcher.
1 parent 40c0eba commit 85cc11f

1 file changed

Lines changed: 107 additions & 30 deletions

File tree

src/os/macosx/font_osx.cpp

Lines changed: 107 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
#include "safeguards.h"
2626

27-
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, int, MissingGlyphSearcher *callback)
27+
static void EnumerateCoreFextFonts(const std::string &language_isocode, int ntries, std::function<bool(int, CTFontDescriptorRef, CTFontSymbolicTraits)> enum_func)
2828
{
2929
/* Determine fallback font using CoreText. This uses the language isocode
3030
* to find a suitable font. CoreText is available from 10.5 onwards. */
@@ -55,9 +55,12 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
5555
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
5656
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
5757

58-
bool result = false;
59-
for (int tries = 0; tries < 2; tries++) {
60-
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
58+
/* Nothing to see here. */
59+
if (descs == nullptr) return;
60+
61+
CFIndex count = CFArrayGetCount(descs.get());
62+
for (int tries = 0; tries < ntries; tries++) {
63+
for (CFIndex i = 0; i < count; i++) {
6164
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
6265

6366
/* Get font traits. */
@@ -67,34 +70,44 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
6770

6871
/* Skip symbol fonts and vertical fonts. */
6972
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
70-
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
71-
if (symbolic_traits & kCTFontBoldTrait) continue;
72-
/* Select monospaced fonts if asked for. */
73-
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
74-
75-
/* Get font name. */
76-
char name[128];
77-
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
78-
CFStringGetCString(font_name.get(), name, lengthof(name), kCFStringEncodingUTF8);
79-
80-
/* Serif fonts usually look worse on-screen with only small
81-
* font sizes. As such, we try for a sans-serif font first.
82-
* If we can't find one in the first try, try all fonts. */
83-
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
84-
85-
/* There are some special fonts starting with an '.' and the last
86-
* resort font that aren't usable. Skip them. */
87-
if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) continue;
88-
89-
/* Save result. */
90-
callback->SetFontNames(settings, name);
91-
if (!callback->FindMissingGlyphs()) {
92-
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
93-
result = true;
94-
break;
95-
}
73+
74+
bool continue_enumerating = enum_func(tries, font, symbolic_traits);
75+
if (!continue_enumerating) return;
9676
}
9777
}
78+
}
79+
80+
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, int, MissingGlyphSearcher *callback)
81+
{
82+
bool result = false;
83+
EnumerateCoreFextFonts(language_isocode, 2, [&settings, &language_isocode, &callback, &result](int tries, CTFontDescriptorRef font, CTFontSymbolicTraits symbolic_traits) {
84+
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
85+
if (symbolic_traits & kCTFontBoldTrait) return true;
86+
/* Select monospaced fonts if asked for. */
87+
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) return true;
88+
89+
/* Get font name. */
90+
char name[128];
91+
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
92+
CFStringGetCString(font_name.get(), name, lengthof(name), kCFStringEncodingUTF8);
93+
94+
/* Serif fonts usually look worse on-screen with only small
95+
* font sizes. As such, we try for a sans-serif font first.
96+
* If we can't find one in the first try, try all fonts. */
97+
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) return true;
98+
99+
/* There are some special fonts starting with an '.' and the last
100+
* resort font that aren't usable. Skip them. */
101+
if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) return true;
102+
103+
/* Save result. */
104+
callback->SetFontNames(settings, name);
105+
if (!callback->FindMissingGlyphs()) {
106+
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
107+
result = true;
108+
return false;
109+
}
110+
});
98111

99112
if (!result) {
100113
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
@@ -382,3 +395,67 @@ void LoadCoreTextFont(FontSize fs, const std::string &file_name, uint size)
382395
new CoreTextFontCache(fs, std::move(font_ref), size);
383396
}
384397
}
398+
399+
class MacOSFontSearcher : public FontSearcher {
400+
public:
401+
std::vector<std::string> ListFamilies(const std::string &language_isocode, int winlangid) override;
402+
std::vector<FontFamily> ListStyles(const std::string &language_isocode, int winlangid, std::string_view family) override;
403+
};
404+
405+
std::vector<std::string> MacOSFontSearcher::ListFamilies(const std::string &language_isocode, int)
406+
{
407+
std::vector<std::string> families;
408+
409+
EnumerateCoreFextFonts(language_isocode, 1, [&families](int, CTFontDescriptorRef font, CTFontSymbolicTraits) {
410+
/* Get font name. */
411+
char family[128];
412+
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute));
413+
CFStringGetCString(font_name.get(), family, std::size(family), kCFStringEncodingUTF8);
414+
415+
/* There are some special fonts starting with an '.' and the last resort font that aren't usable. Skip them. */
416+
if (family[0] == '.' || strncmp(family, "LastResort", 10) == 0) return true;
417+
418+
if (std::find(std::begin(families), std::end(families), family) == std::end(families)) {
419+
families.push_back(family);
420+
}
421+
422+
return true;
423+
});
424+
425+
return families;
426+
}
427+
428+
std::vector<FontFamily> MacOSFontSearcher::ListStyles(const std::string &language_isocode, int, std::string_view family)
429+
{
430+
std::vector<FontFamily> styles;
431+
432+
EnumerateCoreFextFonts(language_isocode, 1, [&styles, &family](int, CTFontDescriptorRef font, CTFontSymbolicTraits) {
433+
/* Get font name. */
434+
char font_family[128];
435+
CFAutoRelease<CFStringRef> family_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute));
436+
CFStringGetCString(family_name.get(), family, std::size(family), kCFStringEncodingUTF8);
437+
438+
if (family != font_family) return true;
439+
440+
/* There are some special fonts starting with an '.' and the last resort font that aren't usable. Skip them. */
441+
if (font_family[0] == '.' || strncmp(font_family, "LastResort", 10) == 0) return true;
442+
443+
char style[128];
444+
CFAutoRelease<CFStringRef> style_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute));
445+
CFStringGetCString(style_name.get(), style, std::size(style), kCFStringEncodingUTF8);
446+
447+
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
448+
float weight = 0.0f;
449+
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontWeightTrait), kCFNumberFloatType, &weight);
450+
float slant = 0.0f;
451+
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSlantTrait), kCFNumberFloatType, &slant);
452+
453+
styles.emplace_back(font_family, style, static_cast<int>(slant * 100), static_cast<int>(weight * 100));
454+
455+
return true;
456+
});
457+
458+
return styles;
459+
}
460+
461+
MacOSFontSearcher _macosfs_instance;

0 commit comments

Comments
 (0)