FontDescriptionCocoa.cpp [plain text]
#include "config.h"
#include "FontCascadeDescription.h"
#include "SystemFontDatabaseCoreText.h"
#include <mutex>
#include <wtf/Language.h>
namespace WebCore {
#if USE(PLATFORM_SYSTEM_FALLBACK_LIST)
#if PLATFORM(IOS_FAMILY)
template<typename T, typename U, std::size_t size, std::size_t... indices> std::array<T, size> convertArray(U (&array)[size], std::index_sequence<indices...>)
{
return { { array[indices]... } };
}
template<typename T, typename U, std::size_t size> inline std::array<T, size> convertArray(U (&array)[size])
{
return convertArray<T>(array, std::make_index_sequence<size> { });
}
#endif
static inline Optional<SystemFontKind> matchSystemFontUse(const AtomString& string)
{
if (equalLettersIgnoringASCIICase(string, "-webkit-system-font")
|| equalLettersIgnoringASCIICase(string, "-apple-system")
|| equalLettersIgnoringASCIICase(string, "-apple-system-font")
|| equalLettersIgnoringASCIICase(string, "system-ui")
|| equalLettersIgnoringASCIICase(string, "ui-sans-serif"))
return SystemFontKind::SystemUI;
#if HAVE(DESIGN_SYSTEM_UI_FONTS)
if (equalLettersIgnoringASCIICase(string, "ui-serif"))
return SystemFontKind::UISerif;
if (equalLettersIgnoringASCIICase(string, "ui-monospace"))
return SystemFontKind::UIMonospace;
if (equalLettersIgnoringASCIICase(string, "ui-rounded"))
return SystemFontKind::UIRounded;
#endif
#if PLATFORM(IOS_FAMILY)
static const CFStringRef styles[] = {
kCTUIFontTextStyleHeadline,
kCTUIFontTextStyleBody,
kCTUIFontTextStyleTitle1,
kCTUIFontTextStyleTitle2,
kCTUIFontTextStyleTitle3,
kCTUIFontTextStyleSubhead,
kCTUIFontTextStyleFootnote,
kCTUIFontTextStyleCaption1,
kCTUIFontTextStyleCaption2,
kCTUIFontTextStyleShortHeadline,
kCTUIFontTextStyleShortBody,
kCTUIFontTextStyleShortSubhead,
kCTUIFontTextStyleShortFootnote,
kCTUIFontTextStyleShortCaption1,
kCTUIFontTextStyleTallBody,
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
kCTUIFontTextStyleTitle0,
kCTUIFontTextStyleTitle4,
#endif
};
static auto strings { makeNeverDestroyed(convertArray<AtomString>(styles)) };
if (std::find(strings.get().begin(), strings.get().end(), string) != strings.get().end())
return SystemFontKind::TextStyle;
#endif
return WTF::nullopt;
}
static inline Vector<RetainPtr<CTFontDescriptorRef>> systemFontCascadeList(const FontDescription& description, const AtomString& cssFamily, SystemFontKind systemFontKind, AllowUserInstalledFonts allowUserInstalledFonts)
{
return SystemFontDatabaseCoreText::singleton().cascadeList(description, cssFamily, systemFontKind, allowUserInstalledFonts);
}
unsigned FontCascadeDescription::effectiveFamilyCount() const
{
unsigned result = 0;
for (unsigned i = 0; i < familyCount(); ++i) {
const auto& cssFamily = familyAt(i);
if (auto use = matchSystemFontUse(cssFamily))
result += systemFontCascadeList(*this, cssFamily, *use, shouldAllowUserInstalledFonts()).size();
else
++result;
}
return result;
}
FontFamilySpecification FontCascadeDescription::effectiveFamilyAt(unsigned index) const
{
for (unsigned i = 0; i < familyCount(); ++i) {
const auto& cssFamily = familyAt(i);
if (auto use = matchSystemFontUse(cssFamily)) {
auto cascadeList = systemFontCascadeList(*this, cssFamily, *use, shouldAllowUserInstalledFonts());
if (index < cascadeList.size())
return FontFamilySpecification(cascadeList[index].get());
index -= cascadeList.size();
}
else if (!index)
return cssFamily;
else
--index;
}
ASSERT_NOT_REACHED();
return nullAtom();
}
#endif // USE(PLATFORM_SYSTEM_FALLBACK_LIST)
static String computeSpecializedChineseLocale()
{
const Vector<String>& preferredLanguages = userPreferredLanguages();
for (auto& language : preferredLanguages) {
if (equalIgnoringASCIICase(language, "zh") || startsWithLettersIgnoringASCIICase(language, "zh-"))
return language;
}
return "zh-hans"_str; }
static String& cachedSpecializedChineseLocale()
{
static NeverDestroyed<String> specializedChineseLocale;
return specializedChineseLocale.get();
}
static void languageChanged(void*)
{
cachedSpecializedChineseLocale() = computeSpecializedChineseLocale();
}
AtomString FontDescription::platformResolveGenericFamily(UScriptCode script, const AtomString& locale, const AtomString& familyName)
{
ASSERT((locale.isNull() && script == USCRIPT_COMMON) || !locale.isNull());
if (script == USCRIPT_COMMON)
return nullAtom();
static std::once_flag onceFlag;
std::call_once(onceFlag, [&] {
static char dummy;
addLanguageChangeObserver(&dummy, &languageChanged); languageChanged(nullptr);
});
auto& usedLocale = script == USCRIPT_HAN ? cachedSpecializedChineseLocale() : locale.string();
if (familyName == serifFamily)
return SystemFontDatabaseCoreText::singleton().serifFamily(usedLocale);
if (familyName == sansSerifFamily)
return SystemFontDatabaseCoreText::singleton().sansSerifFamily(usedLocale);
if (familyName == cursiveFamily)
return SystemFontDatabaseCoreText::singleton().cursiveFamily(usedLocale);
if (familyName == fantasyFamily)
return SystemFontDatabaseCoreText::singleton().fantasyFamily(usedLocale);
if (familyName == monospaceFamily)
return SystemFontDatabaseCoreText::singleton().monospaceFamily(usedLocale);
return nullAtom();
}
}