diff options
-rw-r--r-- | src/gui/text/coretext/qcoretextfontdatabase.mm | 31 | ||||
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext.mm | 7 | ||||
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/freetype/qfontengine_ft.cpp | 27 | ||||
-rw-r--r-- | src/gui/text/freetype/qfontengine_ft_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/freetype/qfreetypefontdatabase.cpp | 3 | ||||
-rw-r--r-- | src/gui/text/qfont.cpp | 193 | ||||
-rw-r--r-- | src/gui/text/qfont.h | 10 | ||||
-rw-r--r-- | src/gui/text/qfont_p.h | 26 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 6 | ||||
-rw-r--r-- | src/gui/text/unix/qfontconfigdatabase.cpp | 1 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp | 57 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabase.cpp | 1 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabase_p.h | 4 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase.cpp | 109 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase_p.h | 10 | ||||
-rw-r--r-- | src/gui/text/windows/qwindowsfontenginedirectwrite.cpp | 2 |
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), |