diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp index 66a46d18cd9..3d41cfda0aa 100644 --- a/src/gui/text/freetype/qfontengine_ft.cpp +++ b/src/gui/text/freetype/qfontengine_ft.cpp @@ -278,6 +278,13 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, } #endif newFreetype->face = face; + newFreetype->mm_var = nullptr; + if (FT_IS_NAMED_INSTANCE(newFreetype->face)) { + FT_Error ftresult; + ftresult = FT_Get_MM_Var(face, &newFreetype->mm_var); + if (ftresult != FT_Err_Ok) + newFreetype->mm_var = nullptr; + } newFreetype->ref.storeRelaxed(1); newFreetype->xsize = 0; @@ -351,6 +358,9 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, void QFreetypeFace::cleanup() { hbFace.reset(); + if (mm_var && face && face->glyph) + FT_Done_MM_Var(face->glyph->library, mm_var); + mm_var = nullptr; FT_Done_Face(face); face = nullptr; } @@ -818,16 +828,13 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, static void dont_delete(void*) {} -static FT_UShort calculateActualWeight(FT_Face face, QFontEngine::FaceId faceId) +static FT_UShort calculateActualWeight(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId) { - if (faceId.instanceIndex >= 0) { - FT_MM_Var *var = nullptr; - FT_Get_MM_Var(face, &var); - if (var != nullptr && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) { - for (FT_UInt axis = 0; axis < var->num_axis; ++axis) { - if (var->axis[axis].tag == QFont::Tag("wght").value()) { - return var->namedstyle[faceId.instanceIndex].coords[axis] >> 16; - } + FT_MM_Var *var = freetypeFace->mm_var; + if (var != nullptr && faceId.instanceIndex >= 0 && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) { + for (FT_UInt axis = 0; axis < var->num_axis; ++axis) { + if (var->axis[axis].tag == QFont::Tag("wght").value()) { + return var->namedstyle[faceId.instanceIndex].coords[axis] >> 16; } } } @@ -838,16 +845,13 @@ static FT_UShort calculateActualWeight(FT_Face face, QFontEngine::FaceId faceId) return 700; } -static bool calculateActualItalic(FT_Face face, QFontEngine::FaceId faceId) +static bool calculateActualItalic(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId) { - if (faceId.instanceIndex >= 0) { - FT_MM_Var *var = nullptr; - FT_Get_MM_Var(face, &var); - if (var != nullptr && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) { - for (FT_UInt axis = 0; axis < var->num_axis; ++axis) { - if (var->axis[axis].tag == QFont::Tag("ital").value()) { - return (var->namedstyle[faceId.instanceIndex].coords[axis] >> 16) == 1; - } + FT_MM_Var *var = freetypeFace->mm_var; + if (var != nullptr && faceId.instanceIndex >= 0 && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) { + for (FT_UInt axis = 0; axis < var->num_axis; ++axis) { + if (var->axis[axis].tag == QFont::Tag("ital").value()) { + return (var->namedstyle[faceId.instanceIndex].coords[axis] >> 16) == 1; } } } @@ -886,7 +890,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, FT_Face face = lockFace(); if (FT_IS_SCALABLE(face)) { - bool isItalic = calculateActualItalic(face, faceId); + bool isItalic = calculateActualItalic(freetype, face, faceId); bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !isItalic && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC"); if (fake_oblique) obliquen = true; @@ -894,7 +898,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, freetype->matrix = matrix; // fake bold if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD")) { - FT_UShort actualWeight = calculateActualWeight(face, faceId); + FT_UShort actualWeight = calculateActualWeight(freetype, face, faceId); if (actualWeight < 700 && (fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) { embolden = true; diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h index b6315a37d3e..9245a271adc 100644 --- a/src/gui/text/freetype/qfontengine_ft_p.h +++ b/src/gui/text/freetype/qfontengine_ft_p.h @@ -19,6 +19,7 @@ #include #include FT_FREETYPE_H +#include FT_MULTIPLE_MASTERS_H #ifndef Q_OS_WIN @@ -62,6 +63,7 @@ public: } FT_Face face; + FT_MM_Var *mm_var; int xsize; // 26.6 int ysize; // 26.6 FT_Matrix matrix; diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp index a0b1abd14a9..46e8f5724aa 100644 --- a/src/gui/text/unix/qfontconfigdatabase.cpp +++ b/src/gui/text/unix/qfontconfigdatabase.cpp @@ -575,6 +575,12 @@ void QFontconfigDatabase::populateFontDatabase() FcObjectSetAdd(os, *p); ++p; } + +#ifdef FC_VARIABLE + /* Support the named instance of Variable Fonts. */ + FcPatternAddBool(pattern, FC_VARIABLE, FcFalse); +#endif + fonts = FcFontList(nullptr, pattern, os); FcObjectSetDestroy(os); FcPatternDestroy(pattern); @@ -974,6 +980,7 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef QFontEngine::GlyphFormat format; // try and get the pattern FcPattern *pattern = FcPatternCreate(); + FcPattern *match = nullptr; FcValue value; value.type = FcTypeString; @@ -992,7 +999,7 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef FcPatternAdd(pattern,FC_INDEX,value,true); } - if (fontDef.pixelSize > 0.1) + if (!qFuzzyIsNull(fontDef.pixelSize)) FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize); FcResult result; @@ -1000,7 +1007,55 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef FcConfigSubstitute(nullptr, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); - FcPattern *match = FcFontMatch(nullptr, pattern, &result); +#ifdef FC_VARIABLE + if (!fid.filename.isEmpty()) { + // FC_INDEX is ignored during processing in FcFontMatch. + // So iterate FcPatterns directly and find it out. + FcFontSet *fcsets[2], *fcfs; + + fcsets[0] = FcConfigGetFonts(nullptr, FcSetSystem); + fcsets[1] = FcConfigGetFonts(nullptr, FcSetApplication); + for (int nset = 0; nset < 2; nset++) { + fcfs = fcsets[nset]; + if (fcfs == nullptr) + continue; + for (int fnum = 0; fnum < fcfs->nfont; fnum++) { + FcPattern *fcpat = fcfs->fonts[fnum]; + FcChar8 *fcfile; + FcBool variable; + double fcpixelsize; + int fcindex; + + // Skip the variable font itself, only to use the named instances and normal fonts here + if (FcPatternGetBool(fcpat, FC_VARIABLE, 0, &variable) == FcResultMatch && + variable == FcTrue) + continue; + + if (!qFuzzyIsNull(fontDef.pixelSize)) { + if (FcPatternGetDouble(fcpat, FC_PIXEL_SIZE, 0, &fcpixelsize) == FcResultMatch && + fontDef.pixelSize != fcpixelsize) + continue; + } + + if (FcPatternGetString(fcpat, FC_FILE, 0, &fcfile) == FcResultMatch && + FcPatternGetInteger(fcpat, FC_INDEX, 0, &fcindex) == FcResultMatch) { + QByteArray f = QByteArray::fromRawData((const char *)fcfile, + qstrlen((const char *)fcfile)); + if (f == fid.filename && fcindex == fid.index) { + // We found it. + match = FcFontRenderPrepare(nullptr, pattern, fcpat); + goto bail; + } + } + } + } + } +bail: +#endif + + if (!match) + match = FcFontMatch(nullptr, pattern, &result); + if (match) { engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));