summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/text/coretext/qcoretextfontdatabase.mm31
-rw-r--r--src/gui/text/coretext/qfontengine_coretext.mm7
-rw-r--r--src/gui/text/coretext/qfontengine_coretext_p.h2
-rw-r--r--src/gui/text/freetype/qfontengine_ft.cpp27
-rw-r--r--src/gui/text/freetype/qfontengine_ft_p.h2
-rw-r--r--src/gui/text/freetype/qfreetypefontdatabase.cpp3
-rw-r--r--src/gui/text/qfont.cpp193
-rw-r--r--src/gui/text/qfont.h10
-rw-r--r--src/gui/text/qfont_p.h26
-rw-r--r--src/gui/text/qfontengine_p.h6
-rw-r--r--src/gui/text/unix/qfontconfigdatabase.cpp1
-rw-r--r--src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp57
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase.cpp1
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_p.h4
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase.cpp109
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase_p.h10
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp2
17 files changed, 427 insertions, 64 deletions
diff --git a/src/gui/text/coretext/qcoretextfontdatabase.mm b/src/gui/text/coretext/qcoretextfontdatabase.mm
index 0301b2e61e..1ff1832640 100644
--- a/src/gui/text/coretext/qcoretextfontdatabase.mm
+++ b/src/gui/text/coretext/qcoretextfontdatabase.mm
@@ -489,6 +489,31 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine
qreal scaledPointSize = fontDef.pixelSize;
CGAffineTransform matrix = qt_transform_from_fontdef(fontDef);
+
+ if (!fontDef.variableAxisValues.isEmpty()) {
+ QCFType<CFMutableDictionaryRef> variations = CFDictionaryCreateMutable(nullptr,
+ fontDef.variableAxisValues.size(),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ for (auto it = fontDef.variableAxisValues.constBegin();
+ it != fontDef.variableAxisValues.constEnd();
+ ++it) {
+ const quint32 tag = it.key().value();
+ const float value = it.value();
+ QCFType<CFNumberRef> tagRef = CFNumberCreate(nullptr, kCFNumberIntType, &tag);
+ QCFType<CFNumberRef> valueRef = CFNumberCreate(nullptr, kCFNumberFloatType, &value);
+
+ CFDictionarySetValue(variations, tagRef, valueRef);
+ }
+ QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(nullptr,
+ (const void **) &kCTFontVariationAttribute,
+ (const void **) &variations,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes);
+ }
+
if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix))
return new QCoreTextFontEngine(font, fontDef);
@@ -504,7 +529,7 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) {
QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue);
return QFontEngineFT::create(*fontData, fontDef.pixelSize,
- static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
+ static_cast<QFont::HintingPreference>(fontDef.hintingPreference), fontDef.variableAxisValues);
} else if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) {
QFontEngine::FaceId faceId;
@@ -515,6 +540,8 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
QString styleName = QCFString(CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute));
faceId.index = QFreetypeFace::getFaceIndexByStyleName(faceFileName, styleName);
+ faceId.variableAxes = fontDef.variableAxisValues;
+
return QFontEngineFT::create(fontDef, faceId);
}
// We end up here with a descriptor does not contain Qt font data or kCTFontURLAttribute.
@@ -527,7 +554,7 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
template <class T>
QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
- return T::create(fontData, pixelSize, hintingPreference);
+ return T::create(fontData, pixelSize, hintingPreference, {});
}
// Explicitly instantiate so that we don't need the plugin to involve FreeType
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm
index 1ba1c73976..b6fef2fecb 100644
--- a/src/gui/text/coretext/qfontengine_coretext.mm
+++ b/src/gui/text/coretext/qfontengine_coretext.mm
@@ -127,9 +127,13 @@ public:
QByteArray m_fontData;
};
-QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference,
+ const QMap<QFont::Tag, float> &variableAxisValues)
{
Q_UNUSED(hintingPreference);
+ Q_UNUSED(variableAxisValues);
QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference);
@@ -188,6 +192,7 @@ void QCoreTextFontEngine::init()
face_id.index = 0;
QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey);
face_id.filename = QString::fromCFString(name).toUtf8();
+ face_id.variableAxes = fontDef.variableAxisValues;
QCFString family = CTFontCopyFamilyName(ctfont);
fontDef.families = QStringList(family);
diff --git a/src/gui/text/coretext/qfontengine_coretext_p.h b/src/gui/text/coretext/qfontengine_coretext_p.h
index 665b827f11..af87f5f6f3 100644
--- a/src/gui/text/coretext/qfontengine_coretext_p.h
+++ b/src/gui/text/coretext/qfontengine_coretext_p.h
@@ -91,7 +91,7 @@ public:
static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length);
static QFont::Weight qtWeightFromCFWeight(float value);
- static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+ static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference, const QMap<QFont::Tag, float> &variableAxisValue);
protected:
QCoreTextFontEngine(const QFontDef &def);
diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp
index 3c01392e46..33b73e49d8 100644
--- a/src/gui/text/freetype/qfontengine_ft.cpp
+++ b/src/gui/text/freetype/qfontengine_ft.cpp
@@ -295,6 +295,22 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
FT_Set_Char_Size(face, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0);
FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
+
+ if (!face_id.variableAxes.isEmpty()) {
+ FT_MM_Var *var = nullptr;
+ FT_Get_MM_Var(newFreetype->face, &var);
+ if (var != nullptr) {
+ QVarLengthArray<FT_Fixed, 16> coords(var->num_axis);
+ FT_Get_Var_Design_Coordinates(face, var->num_axis, coords.data());
+ for (FT_UInt i = 0; i < var->num_axis; ++i) {
+ if (const auto tag = QFont::Tag::fromValue(var->axis[i].tag))
+ coords[i] = FT_Fixed(face_id.variableAxes.value(*tag, coords[i]));
+ }
+ FT_Set_Var_Design_Coordinates(face, var->num_axis, coords.data());
+ FT_Done_MM_Var(qt_getFreetype(), var);
+ }
+ }
+
QT_TRY {
freetypeData->faces.insert(face_id, newFreetype.get());
} QT_CATCH(...) {
@@ -687,27 +703,32 @@ namespace {
fontDef.weight = QFont::Bold;
}
- bool initFromData(const QByteArray &fontData)
+ bool initFromData(const QByteArray &fontData, const QMap<QFont::Tag, float> &variableAxisValues)
{
FaceId faceId;
faceId.filename = "";
faceId.index = 0;
faceId.uuid = QUuid::createUuid().toByteArray();
+ faceId.variableAxes = variableAxisValues;
return init(faceId, true, Format_None, fontData);
}
};
}
-QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference,
+ const QMap<QFont::Tag, float> &variableAxisValues)
{
QFontDef fontDef;
fontDef.pixelSize = pixelSize;
fontDef.stretch = QFont::Unstretched;
fontDef.hintingPreference = hintingPreference;
+ fontDef.variableAxisValues = variableAxisValues;
QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
- if (!fe->initFromData(fontData)) {
+ if (!fe->initFromData(fontData, variableAxisValues)) {
delete fe;
return nullptr;
}
diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h
index e195174960..b6315a37d3 100644
--- a/src/gui/text/freetype/qfontengine_ft_p.h
+++ b/src/gui/text/freetype/qfontengine_ft_p.h
@@ -266,7 +266,7 @@ private:
HintStyle defaultHintStyle() const { return default_hint_style; }
static QFontEngineFT *create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData = QByteArray());
- static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+ static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference, const QMap<QFont::Tag, float> &variableAxisValue);
protected:
diff --git a/src/gui/text/freetype/qfreetypefontdatabase.cpp b/src/gui/text/freetype/qfreetypefontdatabase.cpp
index b5c925722f..772485471f 100644
--- a/src/gui/text/freetype/qfreetypefontdatabase.cpp
+++ b/src/gui/text/freetype/qfreetypefontdatabase.cpp
@@ -62,6 +62,7 @@ QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *us
faceId.filename = QFile::encodeName(fontfile->fileName);
faceId.index = fontfile->indexValue;
faceId.instanceIndex = fontfile->instanceIndex;
+ faceId.variableAxes = fontDef.variableAxisValues;
return QFontEngineFT::create(fontDef, faceId, fontfile->data);
}
@@ -69,7 +70,7 @@ QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *us
QFontEngine *QFreeTypeFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
- return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
+ return QFontEngineFT::create(fontData, pixelSize, hintingPreference, {});
}
QStringList QFreeTypeFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 875ae519e6..3ac63e9ee1 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -90,6 +90,9 @@ bool QFontDef::exactMatch(const QFontDef &other) const
return false;
}
+ if (variableAxisValues != other.variableAxisValues)
+ return false;
+
return (styleHint == other.styleHint
&& styleStrategy == other.styleStrategy
&& weight == other.weight
@@ -346,6 +349,24 @@ void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
if (!(mask & QFont::FeaturesResolved))
features = other->features;
+
+ if (!(mask & QFont::VariableAxesResolved))
+ request.variableAxisValues = other->request.variableAxisValues;
+}
+
+bool QFontPrivate::hasVariableAxis(QFont::Tag tag, float value) const
+{
+ return request.variableAxisValues.contains(tag) && request.variableAxisValues.value(tag) == value;
+}
+
+void QFontPrivate::setVariableAxis(QFont::Tag tag, float value)
+{
+ request.variableAxisValues.insert(tag, value);
+}
+
+void QFontPrivate::unsetVariableAxis(QFont::Tag tag)
+{
+ request.variableAxisValues.remove(tag);
}
void QFontPrivate::setFeature(QFont::Tag tag, quint32 value)
@@ -1794,13 +1815,29 @@ bool QFont::operator<(const QFont &f) const
if (d->features.size() != f.d->features.size())
return f.d->features.size() < d->features.size();
- auto it = d->features.constBegin();
- auto jt = f.d->features.constBegin();
- for (; it != d->features.constEnd(); ++it, ++jt) {
- if (it.key() != jt.key())
- return jt.key() < it.key();
- if (it.value() != jt.value())
- return jt.value() < it.value();
+ {
+ auto it = d->features.constBegin();
+ auto jt = f.d->features.constBegin();
+ for (; it != d->features.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
+ }
+
+ if (r1.variableAxisValues.size() != r2.variableAxisValues.size())
+ return r1.variableAxisValues.size() < r2.variableAxisValues.size();
+
+ {
+ auto it = r1.variableAxisValues.constBegin();
+ auto jt = r2.variableAxisValues.constBegin();
+ for (; it != r1.variableAxisValues.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
}
return false;
@@ -2359,6 +2396,142 @@ std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view) noexcept
/*!
\since 6.7
+
+ Applies a \a value to the variable axis corresponding to \a tag.
+
+ Variable fonts provide a way to store multiple variations (with different weights, widths
+ or styles) in the same font file. The variations are given as floating point values for
+ a pre-defined set of parameters, called "variable axes". Specific instances are typically
+ given names by the font designer, and, in Qt, these can be selected using setStyleName()
+ just like traditional sub-families.
+
+ In some cases, it is also useful to provide arbitrary values for the different axes. For
+ instance, if a font has a Regular and Bold sub-family, you may want a weight in-between these.
+ You could then manually request this by supplying a custom value for the "wght" axis in the
+ font.
+
+ \code
+ QFont font;
+ font.setVariableAxis("wght", (QFont::Normal + QFont::Bold) / 2.0f);
+ \endcode
+
+ If the "wght" axis is supported by the font and the given value is within its defined range,
+ a font corresponding to the weight 550.0 will be provided.
+
+ There are a few standard axes than many fonts provide, such as "wght" (weight), "wdth" (width),
+ "ital" (italic) and "opsz" (optical size). They each have indivdual ranges defined in the font
+ itself. For instance, "wght" may span from 100 to 900 (QFont::Thin to QFont::Black) whereas
+ "ital" can span from 0 to 1 (from not italic to fully italic).
+
+ A font may also choose to define custom axes; the only limitation is that the name has to
+ meet the requirements for a QFont::Tag (sequence of four latin-1 characters.)
+
+ By default, no variable axes are set.
+
+ \note In order to use variable axes on Windows, the application has to run with either the
+ FreeType or DirectWrite font databases. See the documentation for
+ QGuiApplication::QGuiApplication() for more information on how to select these technologies.
+
+ \sa unsetVariableAxis
+ */
+void QFont::setVariableAxis(Tag tag, float value)
+{
+ if (tag.isValid()) {
+ if (resolve_mask & QFont::VariableAxesResolved && d->hasVariableAxis(tag, value))
+ return;
+
+ detach();
+
+ d->setVariableAxis(tag, value);
+ resolve_mask |= QFont::VariableAxesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+
+ Unsets a previously set variable axis value given by \a tag.
+
+ \note If no value has previously been given for this tag, the QFont will still consider its
+ variable axes as set when resolving against other QFont values.
+
+ \sa setVariableAxis
+*/
+void QFont::unsetVariableAxis(Tag tag)
+{
+ if (tag.isValid()) {
+ detach();
+
+ d->unsetVariableAxis(tag);
+ resolve_mask |= QFont::VariableAxesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+
+ Returns a list of tags for all variable axes currently set on this QFont.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
+*/
+QList<QFont::Tag> QFont::variableAxisTags() const
+{
+ return d->request.variableAxisValues.keys();
+}
+
+/*!
+ \since 6.7
+
+ Returns the value set for a specific variable axis \a tag. If the tag has not been set, 0.0 will
+ be returned instead.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
+*/
+float QFont::variableAxisValue(Tag tag) const
+{
+ return d->request.variableAxisValues.value(tag);
+}
+
+/*!
+ \since 6.7
+
+ Returns true if a value for the variable axis given by \a tag has been set on the QFont,
+ otherwise returns false.
+
+ See \l{QFont::}{setVariableAxis()} for more details on font variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), variableAxisValue(), clearVariableAxes()
+*/
+bool QFont::isVariableAxisSet(Tag tag) const
+{
+ return d->request.variableAxisValues.contains(tag);
+}
+
+/*!
+ \since 6.7
+
+ Clears any previously set variable axis values on the QFont.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), variableAxisValue()
+*/
+void QFont::clearVariableAxes()
+{
+ if (d->request.variableAxisValues.isEmpty())
+ return;
+
+ detach();
+ d->request.variableAxisValues.clear();
+}
+
+
+/*!
+ \since 6.7
\overload
Applies an integer value to the typographical feature specified by \a tag when shaping the
@@ -2626,6 +2799,8 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
}
if (s.version() >= QDataStream::Qt_6_6)
s << font.d->features;
+ if (s.version() >= QDataStream::Qt_6_7)
+ s << font.d->request.variableAxisValues;
return s;
}
@@ -2744,6 +2919,10 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
font.d->features.clear();
s >> font.d->features;
}
+ if (s.version() >= QDataStream::Qt_6_7) {
+ font.d->request.variableAxisValues.clear();
+ s >> font.d->request.variableAxisValues;
+ }
return s;
}
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 362ac25625..3206c5c2ee 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -128,7 +128,8 @@ public:
StyleNameResolved = 0x10000,
FamiliesResolved = 0x20000,
FeaturesResolved = 0x40000,
- AllPropertiesResolved = 0x7ffff
+ VariableAxesResolved = 0x80000,
+ AllPropertiesResolved = 0xfffff
};
Q_ENUM(ResolveProperties)
@@ -271,6 +272,13 @@ public:
QList<Tag> featureTags() const;
void clearFeatures();
+ void setVariableAxis(Tag tag, float value);
+ void unsetVariableAxis(Tag tag);
+ bool isVariableAxisSet(Tag tag) const;
+ float variableAxisValue(Tag tag) const;
+ void clearVariableAxes();
+ QList<Tag> variableAxisTags() const;
+
// dupicated from QFontInfo
bool exactMatch() const;
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 18093de49c..b674e71103 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -55,6 +55,7 @@ struct QFontDef
QString styleName;
QStringList fallBackFamilies;
+ QMap<QFont::Tag, float> variableAxisValues;
qreal pointSize;
qreal pixelSize;
@@ -85,6 +86,7 @@ struct QFontDef
&& families == other.families
&& styleName == other.styleName
&& hintingPreference == other.hintingPreference
+ && variableAxisValues == other.variableAxisValues
;
}
inline bool operator<(const QFontDef &other) const
@@ -103,6 +105,22 @@ struct QFontDef
if (ignorePitch != other.ignorePitch) return ignorePitch < other.ignorePitch;
if (fixedPitch != other.fixedPitch) return fixedPitch < other.fixedPitch;
+ if (variableAxisValues != other.variableAxisValues) {
+ if (variableAxisValues.size() != other.variableAxisValues.size())
+ return variableAxisValues.size() < other.variableAxisValues.size();
+
+ {
+ auto it = variableAxisValues.constBegin();
+ auto jt = other.variableAxisValues.constBegin();
+ for (; it != variableAxisValues.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
+ }
+ }
+
return false;
}
};
@@ -120,7 +138,9 @@ inline size_t qHash(const QFontDef &fd, size_t seed = 0) noexcept
fd.fixedPitch,
fd.families,
fd.styleName,
- fd.hintingPreference);
+ fd.hintingPreference,
+ fd.variableAxisValues.keys(),
+ fd.variableAxisValues.values());
}
class QFontEngineData
@@ -182,6 +202,10 @@ public:
void setFeature(QFont::Tag tag, quint32 value);
void unsetFeature(QFont::Tag tag);
+ void setVariableAxis(QFont::Tag tag, float value);
+ void unsetVariableAxis(QFont::Tag tag);
+ bool hasVariableAxis(QFont::Tag tag, float value) const;
+
private:
QFontPrivate &operator=(const QFontPrivate &) { return *this; }
};
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 1b79ffd14a..9efde7b0cc 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -126,6 +126,7 @@ public:
int index;
int instanceIndex;
int encoding;
+ QMap<QFont::Tag, float> variableAxes;
};
virtual FaceId faceId() const { return FaceId(); }
enum SynthesizedFlags {
@@ -368,13 +369,14 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId
&& f1.encoding == f2.encoding
&& f1.filename == f2.filename
&& f1.uuid == f2.uuid
- && f1.instanceIndex == f2.instanceIndex;
+ && f1.instanceIndex == f2.instanceIndex
+ && f1.variableAxes == f2.variableAxes;
}
inline size_t qHash(const QFontEngine::FaceId &f, size_t seed = 0)
noexcept(noexcept(qHash(f.filename)))
{
- return qHashMulti(seed, f.filename, f.uuid, f.index, f.instanceIndex, f.encoding);
+ return qHashMulti(seed, f.filename, f.uuid, f.index, f.instanceIndex, f.encoding, f.variableAxes.keys(), f.variableAxes.values());
}
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 8043602542..a0b1abd14a 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -722,6 +722,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
fid.filename = QFile::encodeName(fontfile->fileName);
fid.index = fontfile->indexValue;
fid.instanceIndex = fontfile->instanceIndex;
+ fid.variableAxes = f.variableAxisValues;
// FIXME: Unify with logic in QFontEngineFT::create()
QFontEngineFT *engine = new QFontEngineFT(f);
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
index c029a27b1c..31870d4a08 100644
--- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
@@ -18,6 +18,32 @@ QT_BEGIN_NAMESPACE
// Defined in gui/text/qfontdatabase.cpp
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script);
+template<typename T>
+struct DirectWriteScope {
+ DirectWriteScope(T *res = nullptr) : m_res(res) {}
+ ~DirectWriteScope() {
+ if (m_res != nullptr)
+ m_res->Release();
+ }
+
+ T **operator&()
+ {
+ return &m_res;
+ }
+
+ T *operator->()
+ {
+ return m_res;
+ }
+
+ T *operator*() {
+ return m_res;
+ }
+
+private:
+ T *m_res;
+};
+
QWindowsDirectWriteFontDatabase::QWindowsDirectWriteFontDatabase()
{
qCDebug(lcQpaFonts) << "Creating DirectWrite database";
@@ -217,6 +243,37 @@ QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef
IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle);
Q_ASSERT(face != nullptr);
+ DirectWriteScope<IDWriteFontFace5> newFace;
+ if (!fontDef.variableAxisValues.isEmpty()) {
+ DirectWriteScope<IDWriteFontFace5> face5;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
+ reinterpret_cast<void **>(&face5)))) {
+ DirectWriteScope<IDWriteFontResource> font;
+ if (SUCCEEDED(face5->GetFontResource(&font))) {
+ UINT32 fontAxisCount = font->GetFontAxisCount();
+
+ QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
+ if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
+ for (UINT32 i = 0; i < fontAxisCount; ++i) {
+ if (auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
+ if (fontDef.variableAxisValues.contains(*maybeTag))
+ fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
+ }
+ }
+ }
+
+ if (SUCCEEDED(font->CreateFontFace(DWRITE_FONT_SIMULATIONS_NONE,
+ fontAxisValues.data(),
+ fontAxisCount,
+ &newFace))) {
+ face = *newFace;
+ } else {
+ qCWarning(lcQpaFonts) << "DirectWrite: Can't create font face for variable axis values";
+ }
+ }
+ }
+ }
+
QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data());
fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp
index 246e993864..b227cf677e 100644
--- a/src/gui/text/windows/qwindowsfontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase.cpp
@@ -724,6 +724,7 @@ void QWindowsFontDatabase::populateFontDatabase()
void QWindowsFontDatabase::invalidate()
{
+ QWindowsFontDatabaseBase::invalidate();
removeApplicationFonts();
}
diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h
index 45c1956623..dfaa1f9c0e 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_p.h
@@ -45,6 +45,7 @@ public:
void populateFontDatabase() override;
void invalidate() override;
+ void removeApplicationFonts();
void populateFamily(const QString &familyName) override;
bool populateFamilyAliases(const QString &missingFamily) override;
@@ -74,8 +75,9 @@ public:
static void debugFormat(QDebug &d, const LOGFONT &lf);
#endif // !QT_NO_DEBUG_STREAM
+
private:
- void removeApplicationFonts();
+
void addDefaultEUDCFont();
struct WinApplicationFont {
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
index 9343e447ae..a1c400ee9b 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
@@ -359,10 +359,10 @@ namespace {
{
}
- inline void addKey(const void *key, const QByteArray &fontData)
+ inline void addKey(const QByteArray &fontData)
{
- Q_ASSERT(!m_fontDatas.contains(key));
- m_fontDatas.insert(key, fontData);
+ if (!m_fontDatas.contains(fontData.data()))
+ m_fontDatas.insert(fontData.data(), fontData);
}
inline void removeKey(const void *key)
@@ -378,6 +378,11 @@ namespace {
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream **fontFileStream) override;
+ void clear()
+ {
+ m_fontDatas.clear();
+ }
+
private:
ULONG m_referenceCount;
QHash<const void *, QByteArray> m_fontDatas;
@@ -435,52 +440,62 @@ namespace {
return S_OK;
}
- class CustomFontFileLoader
+} // Anonymous namespace
+
+class QCustomFontFileLoader
+{
+public:
+ QCustomFontFileLoader(IDWriteFactory *factory)
{
- public:
- CustomFontFileLoader(IDWriteFactory *factory)
- {
- m_directWriteFactory = factory;
+ m_directWriteFactory = factory;
- if (m_directWriteFactory) {
- m_directWriteFactory->AddRef();
+ if (m_directWriteFactory) {
+ m_directWriteFactory->AddRef();
- m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
- m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
- }
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
+ }
- ~CustomFontFileLoader()
- {
- if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
- m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+ ~QCustomFontFileLoader()
+ {
+ clear();
- if (m_directWriteFactory != nullptr)
- m_directWriteFactory->Release();
- }
+ if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
- void addKey(const void *key, const QByteArray &fontData)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->addKey(key, fontData);
- }
+ if (m_directWriteFactory != nullptr)
+ m_directWriteFactory->Release();
+ }
- void removeKey(const void *key)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->removeKey(key);
- }
+ void addKey(const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->addKey(fontData);
+ }
- IDWriteFontFileLoader *loader() const
- {
- return m_directWriteFontFileLoader;
- }
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ void clear()
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->clear();
+ }
+
+private:
+ IDWriteFactory *m_directWriteFactory = nullptr;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
+};
- private:
- IDWriteFactory *m_directWriteFactory = nullptr;
- DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
- };
-} // Anonymous namespace
#endif // directwrite && direct2d
@@ -704,6 +719,11 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
return faces.isEmpty() ? nullptr : faces.first();
}
+void QWindowsFontDatabaseBase::invalidate()
+{
+ m_fontFileLoader.reset(nullptr);
+}
+
QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
bool queryVariations) const
{
@@ -714,15 +734,17 @@ QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const
return ret;
}
- CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
- fontFileLoader.addKey(this, fontData);
+ if (m_fontFileLoader == nullptr)
+ m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
+
+ m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr;
- const void *key = this;
+ const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *),
- fontFileLoader.loader(),
+ m_fontFileLoader->loader(),
&fontFile);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
@@ -793,6 +815,7 @@ QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const
}
fontFile->Release();
+
return ret;
}
#endif // directwrite && direct2d
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
index b7bd47ba84..55a3363551 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
@@ -29,6 +29,10 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(directwrite)
+ class QCustomFontFileLoader;
+#endif
+
class QWindowsFontEngineData
{
Q_DISABLE_COPY_MOVE(QWindowsFontEngineData)
@@ -56,6 +60,8 @@ public:
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
+ void invalidate() override;
+
static int defaultVerticalDPI();
static QSharedPointer<QWindowsFontEngineData> data();
@@ -98,6 +104,10 @@ protected:
private:
static bool init(QSharedPointer<QWindowsFontEngineData> data);
+
+#if QT_CONFIG(directwrite)
+ mutable std::unique_ptr<QCustomFontFileLoader> m_fontFileLoader;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index 70cface6a1..e5a2c7a2b8 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -1015,6 +1015,8 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request,
else if (fontDef.pixelSize == -1)
fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
+ m_faceId.variableAxes = request.variableAxisValues;
+
#if QT_CONFIG(directwrite3)
IDWriteFontFace3 *face3 = nullptr;
if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace3),