summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-03-23 14:22:22 +0100
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-03-30 19:55:21 +0100
commitc7280b33628c6a7bc26b2188f6a96c001380c889 (patch)
tree86b5227791c36efe508118d2562b6504c6f4e1c1 /src/gui
parenta068f2d7c9967b6e12eaf8453760d462cbce40db (diff)
CoreText: Populate all variants of theme/system fonts
We populate the various QPlatformTheme::Fonts by asking the system for the preferred font for each use-case, but that just gives us a single font descriptor with a single style and weight. If the user then tweaks the font by e.g. making it bold or italic, our font database will not have any knowledge of these variants, and will fall back to another font. To fix this we ask CoreText for all variants of each of the theme fonts, so that each of the theme font families are fully populated. The preferred way to do this on macOS 10.15/iOS 13 and above is by using the font's UI design trait. This avoids asking CoreText for private fonts by family name directly, which is not supported and may result in giving us Times or another fallback font instead. Pick-to: 6.2 6.3 Change-Id: I4aa21624df62ac09a92d7ae0bc2cdde4f6ad6e5f Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/kernel/qplatformtheme.h1
-rw-r--r--src/gui/text/coretext/qcoretextfontdatabase.mm70
-rw-r--r--src/gui/text/coretext/qcoretextfontdatabase_p.h5
3 files changed, 63 insertions, 13 deletions
diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h
index 398ea2eae1..b29d23de6c 100644
--- a/src/gui/kernel/qplatformtheme.h
+++ b/src/gui/kernel/qplatformtheme.h
@@ -192,6 +192,7 @@ public:
EditorFont,
NFonts
};
+ Q_ENUM(Font)
enum StandardPixmap { // Keep in sync with QStyle::StandardPixmap
TitleBarMenuButton,
diff --git a/src/gui/text/coretext/qcoretextfontdatabase.mm b/src/gui/text/coretext/qcoretextfontdatabase.mm
index 47af17b04b..043272b4c2 100644
--- a/src/gui/text/coretext/qcoretextfontdatabase.mm
+++ b/src/gui/text/coretext/qcoretextfontdatabase.mm
@@ -110,9 +110,6 @@ QCoreTextFontDatabase::QCoreTextFontDatabase()
QCoreTextFontDatabase::~QCoreTextFontDatabase()
{
qDeleteAll(m_themeFonts);
-
- for (CTFontDescriptorRef ref : qAsConst(m_systemFontDescriptors))
- CFRelease(ref);
}
void QCoreTextFontDatabase::populateFontDatabase()
@@ -130,8 +127,13 @@ void QCoreTextFontDatabase::populateFontDatabase()
populateThemeFonts();
- for (CTFontDescriptorRef fontDesc : m_systemFontDescriptors)
- populateFromDescriptor(fontDesc);
+ for (auto familyName : m_systemFontDescriptors.keys()) {
+ for (auto fontDescriptor : m_systemFontDescriptors.value(familyName))
+ populateFromDescriptor(fontDescriptor, familyName);
+ }
+
+ // The font database now has a reference to the original descriptors
+ m_systemFontDescriptors.clear();
qCDebug(lcQpaFonts) << "Populating system descriptors took" << elapsed.restart() << "ms";
@@ -202,6 +204,8 @@ CTFontDescriptorRef descriptorForFamily(const char *familyName)
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
{
+ qCDebug(lcQpaFonts) << "Populating family" << familyName;
+
// A single family might match several different fonts with different styles.
// We need to add them all so that the font database has the full picture,
// as once a family has been populated we will not populate it again.
@@ -749,6 +753,8 @@ static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f)
void QCoreTextFontDatabase::populateThemeFonts()
{
+ QMacAutoReleasePool pool;
+
if (!m_themeFonts.isEmpty())
return;
@@ -760,7 +766,7 @@ void QCoreTextFontDatabase::populateThemeFonts()
for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
QPlatformTheme::Font themeFont = static_cast<QPlatformTheme::Font>(f);
- CTFontDescriptorRef fontDescriptor = fontDescriptorFromTheme(themeFont);
+ QCFType<CTFontDescriptorRef> fontDescriptor = fontDescriptorFromTheme(themeFont);
FontDescription fd;
getFontDescription(fontDescriptor, &fd);
@@ -770,10 +776,54 @@ void QCoreTextFontDatabase::populateThemeFonts()
// would result in the font database having > 0 families, which would result in
// skipping the initialization and population of all other font families. Instead
// we store the descriptors for later and populate them during populateFontDatabase().
- if (!m_systemFontDescriptors.contains(fontDescriptor))
- m_systemFontDescriptors.insert(fontDescriptor);
- else
- CFRelease(fontDescriptor);
+
+ bool haveRegisteredFamily = m_systemFontDescriptors.contains(fd.familyName);
+ qCDebug(lcQpaFonts) << "Got" << (haveRegisteredFamily ? "already registered" : "unseen")
+ << "family" << fd.familyName << "for" << themeFont;
+
+ if (!haveRegisteredFamily) {
+ // We need to register all weights and variants of the theme font,
+ // as the user might tweak the returned QFont before use.
+ QList<QCFType<CTFontDescriptorRef>> themeFontVariants;
+
+ auto addFontVariants = [&](CTFontDescriptorRef descriptor) {
+ QCFType<CFArrayRef> matchingDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr);
+ const int matchingDescriptorsCount = CFArrayGetCount(matchingDescriptors);
+ qCDebug(lcQpaFonts) << "Enumerating font variants based on" << id(descriptor)
+ << "resulted in" << matchingDescriptorsCount << "matching descriptors"
+ << matchingDescriptors.as<NSArray*>();
+
+ for (int i = 0; i < matchingDescriptorsCount; ++i) {
+ auto matchingDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingDescriptors, i));
+ themeFontVariants.append(QCFType<CTFontDescriptorRef>::constructFromGet(matchingDescriptor));
+ }
+ };
+
+ // Try populating the font variants based on its UI design trait, if available
+ if (@available(macos 10.15, ios 13.0, *)) {
+ auto fontTraits = QCFType<CFDictionaryRef>(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontTraitsAttribute));
+ static const NSString *kUIFontDesignTrait = @"NSCTFontUIFontDesignTrait";
+ if (id uiFontDesignTrait = fontTraits.as<NSDictionary*>()[kUIFontDesignTrait]) {
+ QCFType<CTFontDescriptorRef> designTraitDescriptor = CTFontDescriptorCreateWithAttributes(
+ CFDictionaryRef(@{ (id)kCTFontTraitsAttribute: @{ kUIFontDesignTrait: uiFontDesignTrait }
+ }));
+ addFontVariants(designTraitDescriptor);
+ }
+ }
+
+ if (themeFontVariants.isEmpty()) {
+ // Fall back to populating variants based on the family name alone
+ QCFType<CTFontDescriptorRef> familyDescriptor = descriptorForFamily(fd.familyName);
+ addFontVariants(familyDescriptor);
+ }
+
+ if (themeFontVariants.isEmpty()) {
+ qCDebug(lcQpaFonts) << "No theme font variants found, falling back to single variant descriptor";
+ themeFontVariants.append(fontDescriptor);
+ }
+
+ m_systemFontDescriptors.insert(fd.familyName, themeFontVariants);
+ }
QFont *font = new QFont(fd.familyName, fd.pointSize, fd.weight, fd.style == QFont::StyleItalic);
m_themeFonts.insert(themeFont, font);
diff --git a/src/gui/text/coretext/qcoretextfontdatabase_p.h b/src/gui/text/coretext/qcoretextfontdatabase_p.h
index a6f93dd14a..b8fa87996d 100644
--- a/src/gui/text/coretext/qcoretextfontdatabase_p.h
+++ b/src/gui/text/coretext/qcoretextfontdatabase_p.h
@@ -86,9 +86,6 @@ public:
// For iOS and macOS platform themes
QFont *themeFont(QPlatformTheme::Font) const;
-protected:
- mutable QSet<CTFontDescriptorRef> m_systemFontDescriptors;
-
private:
void populateThemeFonts();
void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString(), QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr);
@@ -97,6 +94,8 @@ private:
mutable QString defaultFontName;
QHash<QPlatformTheme::Font, QFont *> m_themeFonts;
+ QHash<QString, QList<QCFType<CTFontDescriptorRef>>> m_systemFontDescriptors;
+
bool m_hasPopulatedAliases;
};