Support loading variable fonts as application fonts in Freetype
When loading the fonts, we go through all the named instances and register these as subfamilies. In addition to exposing these variants by style name, we also register them with the according weights, italic style and stretch. This adds a field to FontFile to allow piping the instance index through to when we instantiate the face. [ChangeLog][Fonts] Added support for selecting named instances in variable application fonts when using the Freetype backend. Task-number: QTBUG-108624 Change-Id: I57ef6b4802756dd408c3aae1f8a6c792a89bee6a Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
3aff1e1678
commit
5469d6a6cc
@ -12,6 +12,7 @@
|
||||
#include <qscreen.h>
|
||||
#include <qpa/qplatformscreen.h>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtGui/QPainterPath>
|
||||
|
||||
#ifndef QT_NO_FREETYPE
|
||||
@ -34,6 +35,7 @@
|
||||
#include FT_GLYPH_H
|
||||
#include FT_MODULE_H
|
||||
#include FT_LCD_FILTER_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
|
||||
#if defined(FT_CONFIG_OPTIONS_H)
|
||||
#include FT_CONFIG_OPTIONS_H
|
||||
@ -53,6 +55,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFontMatch)
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
#define FLOOR(x) ((x) & -64)
|
||||
@ -243,6 +247,15 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
|
||||
} else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
|
||||
if (face_id.instanceIndex >= 0) {
|
||||
qCDebug(lcFontMatch)
|
||||
<< "Selecting named instance" << (face_id.instanceIndex)
|
||||
<< "in" << face_id.filename;
|
||||
FT_Set_Named_Instance(face, face_id.instanceIndex + 1);
|
||||
}
|
||||
#endif
|
||||
newFreetype->face = face;
|
||||
|
||||
newFreetype->ref.storeRelaxed(1);
|
||||
@ -747,6 +760,43 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
||||
|
||||
static void dont_delete(void*) {}
|
||||
|
||||
static FT_UShort calculateActualWeight(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 == MAKE_TAG('w', 'g', 'h', 't')) {
|
||||
return var->namedstyle[faceId.instanceIndex].coords[axis] >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
|
||||
return os2->usWeightClass;
|
||||
}
|
||||
|
||||
return 700;
|
||||
}
|
||||
|
||||
static bool calculateActualItalic(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 == MAKE_TAG('i', 't', 'a', 'l')) {
|
||||
return (var->namedstyle[faceId.instanceIndex].coords[axis] >> 16) == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (face->style_flags & FT_STYLE_FLAG_ITALIC);
|
||||
}
|
||||
|
||||
bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
||||
QFreetypeFace *freetypeFace)
|
||||
{
|
||||
@ -778,18 +828,18 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
||||
FT_Face face = lockFace();
|
||||
|
||||
if (FT_IS_SCALABLE(face)) {
|
||||
bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
|
||||
bool isItalic = calculateActualItalic(face, faceId);
|
||||
bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !isItalic && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
|
||||
if (fake_oblique)
|
||||
obliquen = true;
|
||||
FT_Set_Transform(face, &matrix, nullptr);
|
||||
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")) {
|
||||
if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
|
||||
if (os2->usWeightClass < 700 &&
|
||||
(fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) {
|
||||
embolden = true;
|
||||
}
|
||||
FT_UShort actualWeight = calculateActualWeight(face, faceId);
|
||||
if (actualWeight < 700 &&
|
||||
(fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) {
|
||||
embolden = true;
|
||||
}
|
||||
}
|
||||
// underline metrics
|
||||
@ -2191,6 +2241,15 @@ Qt::HANDLE QFontEngineFT::handle() const
|
||||
return non_locked_face();
|
||||
}
|
||||
|
||||
bool QFontEngineFT::supportsVariableApplicationFonts() const
|
||||
{
|
||||
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_FREETYPE
|
||||
|
@ -159,6 +159,8 @@ private:
|
||||
return supportsHorizontalSubPixelPositions();
|
||||
}
|
||||
|
||||
bool supportsVariableApplicationFonts() const override;
|
||||
|
||||
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override;
|
||||
int synthesized() const override;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <QtCore/QLibraryInfo>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QtEndian>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#undef QT_NO_FREETYPE
|
||||
#include "qfontengine_ft_p.h"
|
||||
@ -18,8 +19,14 @@
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
#include FT_ERRORS_H
|
||||
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include FT_SFNT_NAMES_H
|
||||
#include FT_TRUETYPE_IDS_H
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFontDb)
|
||||
|
||||
using namespace Qt::StringLiterals;
|
||||
|
||||
void QFreeTypeFontDatabase::populateFontDatabase()
|
||||
@ -54,6 +61,7 @@ QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *us
|
||||
QFontEngine::FaceId faceId;
|
||||
faceId.filename = QFile::encodeName(fontfile->fileName);
|
||||
faceId.index = fontfile->indexValue;
|
||||
faceId.instanceIndex = fontfile->instanceIndex;
|
||||
|
||||
return QFontEngineFT::create(fontDef, faceId, fontfile->data);
|
||||
}
|
||||
@ -77,6 +85,110 @@ void QFreeTypeFontDatabase::releaseHandle(void *handle)
|
||||
|
||||
extern FT_Library qt_getFreetype();
|
||||
|
||||
void QFreeTypeFontDatabase::addNamedInstancesForFace(void *face_,
|
||||
int faceIndex,
|
||||
const QString &family,
|
||||
const QString &styleName,
|
||||
QFont::Weight weight,
|
||||
QFont::Stretch stretch,
|
||||
QFont::Style style,
|
||||
bool fixedPitch,
|
||||
const QSupportedWritingSystems &writingSystems,
|
||||
const QByteArray &fileName,
|
||||
const QByteArray &fontData)
|
||||
{
|
||||
FT_Face face = reinterpret_cast<FT_Face>(face_);
|
||||
|
||||
// Note: The following does not actually depend on API from 2.9, but the
|
||||
// FT_Set_Named_Instance() was added in 2.9, so to avoid populating the database with
|
||||
// named instances that cannot be selected, we disable the feature on older Freetype
|
||||
// versions.
|
||||
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
|
||||
FT_MM_Var *var = nullptr;
|
||||
FT_Get_MM_Var(face, &var);
|
||||
if (var != nullptr) {
|
||||
for (FT_UInt i = 0; i < var->num_namedstyles; ++i) {
|
||||
FT_UInt id = var->namedstyle[i].strid;
|
||||
|
||||
QFont::Weight instanceWeight = weight;
|
||||
QFont::Stretch instanceStretch = stretch;
|
||||
QFont::Style instanceStyle = style;
|
||||
for (FT_UInt axis = 0; axis < var->num_axis; ++axis) {
|
||||
if (var->axis[axis].tag == MAKE_TAG('w', 'g', 'h', 't')) {
|
||||
instanceWeight = QFont::Weight(var->namedstyle[i].coords[axis] >> 16);
|
||||
} else if (var->axis[axis].tag == MAKE_TAG('w', 'd', 't', 'h')) {
|
||||
instanceStretch = QFont::Stretch(var->namedstyle[i].coords[axis] >> 16);
|
||||
} else if (var->axis[axis].tag == MAKE_TAG('i', 't', 'a', 'l')) {
|
||||
FT_UInt ital = var->namedstyle[i].coords[axis] >> 16;
|
||||
if (ital == 1)
|
||||
instanceStyle = QFont::StyleItalic;
|
||||
else
|
||||
instanceStyle = QFont::StyleNormal;
|
||||
}
|
||||
}
|
||||
|
||||
FT_UInt count = FT_Get_Sfnt_Name_Count(face);
|
||||
for (FT_UInt j = 0; j < count; ++j) {
|
||||
FT_SfntName name;
|
||||
if (FT_Get_Sfnt_Name(face, j, &name))
|
||||
continue;
|
||||
|
||||
if (name.name_id != id)
|
||||
continue;
|
||||
|
||||
// Only support Unicode for now
|
||||
if (name.encoding_id != TT_MS_ID_UNICODE_CS)
|
||||
continue;
|
||||
|
||||
// Sfnt names stored as UTF-16BE
|
||||
QString instanceName;
|
||||
for (FT_UInt k = 0; k < name.string_len; k += 2)
|
||||
instanceName += QChar((name.string[k] << 8) + name.string[k + 1]);
|
||||
if (instanceName != styleName) {
|
||||
FontFile *variantFontFile = new FontFile{
|
||||
QFile::decodeName(fileName),
|
||||
faceIndex,
|
||||
int(i),
|
||||
fontData
|
||||
};
|
||||
|
||||
qCDebug(lcFontDb) << "Registering named instance" << i
|
||||
<< ":" << instanceName
|
||||
<< "for font family" << family
|
||||
<< "with weight" << instanceWeight
|
||||
<< ", style" << instanceStyle
|
||||
<< ", stretch" << instanceStretch;
|
||||
|
||||
registerFont(family,
|
||||
instanceName,
|
||||
QString(),
|
||||
instanceWeight,
|
||||
instanceStyle,
|
||||
instanceStretch,
|
||||
true,
|
||||
true,
|
||||
0,
|
||||
fixedPitch,
|
||||
writingSystems,
|
||||
variantFontFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(face);
|
||||
Q_UNUSED(family);
|
||||
Q_UNUSED(styleName);
|
||||
Q_UNUSED(weight);
|
||||
Q_UNUSED(stretch);
|
||||
Q_UNUSED(style);
|
||||
Q_UNUSED(fixedPitch);
|
||||
Q_UNUSED(writingSystems);
|
||||
Q_UNUSED(fontData);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont)
|
||||
{
|
||||
FT_Library library = qt_getFreetype();
|
||||
@ -194,6 +306,7 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q
|
||||
FontFile *fontFile = new FontFile{
|
||||
QFile::decodeName(file),
|
||||
index,
|
||||
-1,
|
||||
fontData
|
||||
};
|
||||
|
||||
@ -211,6 +324,9 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q
|
||||
}
|
||||
|
||||
registerFont(family, styleName, QString(), weight, style, stretch, true, true, 0, fixedPitch, writingSystems, fontFile);
|
||||
|
||||
addNamedInstancesForFace(face, index, family, styleName, weight, stretch, style, fixedPitch, writingSystems, file, fontData);
|
||||
|
||||
families.append(family);
|
||||
|
||||
FT_Done_Face(face);
|
||||
|
@ -26,6 +26,7 @@ struct FontFile
|
||||
{
|
||||
QString fileName;
|
||||
int indexValue;
|
||||
int instanceIndex = -1;
|
||||
|
||||
// Note: The data may be implicitly shared throughout the
|
||||
// font database and platform font database, so be careful
|
||||
@ -42,6 +43,13 @@ public:
|
||||
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr) override;
|
||||
void releaseHandle(void *handle) override;
|
||||
|
||||
static void addNamedInstancesForFace(void *face, int faceIndex,
|
||||
const QString &family, const QString &styleName,
|
||||
QFont::Weight weight, QFont::Stretch stretch,
|
||||
QFont::Style style, bool fixedPitch,
|
||||
const QSupportedWritingSystems &writingSystems,
|
||||
const QByteArray &fileName, const QByteArray &fontData);
|
||||
|
||||
static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr);
|
||||
};
|
||||
|
||||
|
@ -247,6 +247,11 @@ bool QFontEngine::supportsTransformation(const QTransform &transform) const
|
||||
return transform.type() < QTransform::TxProject;
|
||||
}
|
||||
|
||||
bool QFontEngine::supportsVariableApplicationFonts() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QFontEngine::expectsGammaCorrectedBlending() const
|
||||
{
|
||||
return true;
|
||||
|
@ -127,10 +127,11 @@ public:
|
||||
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
|
||||
|
||||
struct FaceId {
|
||||
FaceId() : index(0), encoding(0) {}
|
||||
FaceId() : index(0), instanceIndex(-1), encoding(0) {}
|
||||
QByteArray filename;
|
||||
QByteArray uuid;
|
||||
int index;
|
||||
int instanceIndex;
|
||||
int encoding;
|
||||
};
|
||||
virtual FaceId faceId() const { return FaceId(); }
|
||||
@ -212,6 +213,7 @@ public:
|
||||
|
||||
inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; }
|
||||
virtual bool canRender(const QChar *str, int len) const;
|
||||
virtual bool supportsVariableApplicationFonts() const;
|
||||
|
||||
virtual bool supportsTransformation(const QTransform &transform) const;
|
||||
|
||||
@ -370,13 +372,17 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags)
|
||||
|
||||
inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2)
|
||||
{
|
||||
return f1.index == f2.index && f1.encoding == f2.encoding && f1.filename == f2.filename && f1.uuid == f2.uuid;
|
||||
return f1.index == f2.index
|
||||
&& f1.encoding == f2.encoding
|
||||
&& f1.filename == f2.filename
|
||||
&& f1.uuid == f2.uuid
|
||||
&& f1.instanceIndex == f2.instanceIndex;
|
||||
}
|
||||
|
||||
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.encoding);
|
||||
return qHashMulti(seed, f.filename, f.uuid, f.index, f.instanceIndex, f.encoding);
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFontDb)
|
||||
|
||||
static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper)
|
||||
{
|
||||
return qtLower + ((fcweight - fcLower) * (qtUpper - qtLower)) / (fcUpper - fcLower);
|
||||
@ -366,7 +368,10 @@ static inline bool requiresOpenType(int writingSystem)
|
||||
|| writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
|
||||
}
|
||||
|
||||
static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr)
|
||||
static void populateFromPattern(FcPattern *pattern,
|
||||
QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr,
|
||||
FT_Face face = nullptr,
|
||||
QFontconfigDatabase *db = nullptr)
|
||||
{
|
||||
QString familyName;
|
||||
QString familyNameLang;
|
||||
@ -489,6 +494,20 @@ static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::Applic
|
||||
}
|
||||
|
||||
QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1StringView((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
|
||||
if (applicationFont != nullptr && face != nullptr && db != nullptr) {
|
||||
db->addNamedInstancesForFace(face,
|
||||
indexValue,
|
||||
familyName,
|
||||
styleName,
|
||||
weight,
|
||||
stretch,
|
||||
style,
|
||||
fixedPitch,
|
||||
writingSystems,
|
||||
QByteArray((const char*)file_value),
|
||||
applicationFont->data);
|
||||
}
|
||||
|
||||
// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
|
||||
|
||||
for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) {
|
||||
@ -702,6 +721,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
|
||||
QFontEngine::FaceId fid;
|
||||
fid.filename = QFile::encodeName(fontfile->fileName);
|
||||
fid.index = fontfile->indexValue;
|
||||
fid.instanceIndex = fontfile->instanceIndex;
|
||||
|
||||
// FIXME: Unify with logic in QFontEngineFT::create()
|
||||
QFontEngineFT *engine = new QFontEngineFT(f);
|
||||
@ -803,26 +823,28 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont
|
||||
return fallbackFamilies;
|
||||
}
|
||||
|
||||
static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
|
||||
static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count, FT_Face *face)
|
||||
{
|
||||
#if FC_VERSION < 20402
|
||||
Q_UNUSED(data);
|
||||
*face = nullptr;
|
||||
return FcFreeTypeQuery(file, id, blanks, count);
|
||||
#else
|
||||
if (data.isEmpty())
|
||||
if (data.isEmpty()) {
|
||||
*face = nullptr;
|
||||
return FcFreeTypeQuery(file, id, blanks, count);
|
||||
}
|
||||
|
||||
FT_Library lib = qt_getFreetype();
|
||||
|
||||
FcPattern *pattern = nullptr;
|
||||
|
||||
FT_Face face;
|
||||
if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
|
||||
*count = face->num_faces;
|
||||
if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, face)) {
|
||||
*count = (*face)->num_faces;
|
||||
|
||||
pattern = FcFreeTypeQueryFace(face, file, id, blanks);
|
||||
|
||||
FT_Done_Face(face);
|
||||
pattern = FcFreeTypeQueryFace(*face, file, id, blanks);
|
||||
} else {
|
||||
*face = nullptr;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
@ -850,8 +872,9 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
|
||||
|
||||
FcPattern *pattern;
|
||||
do {
|
||||
FT_Face face;
|
||||
pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
|
||||
fontData, id, blanks, &count);
|
||||
fontData, id, blanks, &count, &face);
|
||||
if (!pattern)
|
||||
return families;
|
||||
|
||||
@ -860,7 +883,10 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
|
||||
QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
|
||||
families << family;
|
||||
}
|
||||
populateFromPattern(pattern, applicationFont);
|
||||
populateFromPattern(pattern, applicationFont, face, this);
|
||||
|
||||
if (face)
|
||||
FT_Done_Face(face);
|
||||
|
||||
FcFontSetAdd(set, pattern);
|
||||
|
||||
|
@ -37,11 +37,15 @@ set_source_files_properties("../../../shared/resources/testfont_italic.ttf"
|
||||
set_source_files_properties("../../../shared/resources/testfont_open.otf"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "testfont_open.otf"
|
||||
)
|
||||
set_source_files_properties("../../../shared/resources/testfont_variable.ttf"
|
||||
PROPERTIES QT_RESOURCE_ALIAS "testfont_variable.ttf"
|
||||
)
|
||||
set(testdata_resource_files
|
||||
"../../../shared/resources/testfont.ttf"
|
||||
"../../../shared/resources/testfont_condensed.ttf"
|
||||
"../../../shared/resources/testfont_italic.ttf"
|
||||
"../../../shared/resources/testfont_open.otf"
|
||||
"../../../shared/resources/testfont_variable.ttf"
|
||||
"LED_REAL.TTF"
|
||||
)
|
||||
|
||||
|
@ -61,6 +61,8 @@ private slots:
|
||||
|
||||
void stretchRespected();
|
||||
|
||||
void variableFont();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void findCourier();
|
||||
#endif
|
||||
@ -70,6 +72,7 @@ private:
|
||||
QString m_testFont;
|
||||
QString m_testFontCondensed;
|
||||
QString m_testFontItalic;
|
||||
QString m_testFontVariable;
|
||||
};
|
||||
|
||||
tst_QFontDatabase::tst_QFontDatabase()
|
||||
@ -82,10 +85,12 @@ void tst_QFontDatabase::initTestCase()
|
||||
m_testFont = QFINDTESTDATA("testfont.ttf");
|
||||
m_testFontCondensed = QFINDTESTDATA("testfont_condensed.ttf");
|
||||
m_testFontItalic = QFINDTESTDATA("testfont_italic.ttf");
|
||||
m_testFontVariable = QFINDTESTDATA("testfont_variable.ttf");
|
||||
QVERIFY(!m_ledFont.isEmpty());
|
||||
QVERIFY(!m_testFont.isEmpty());
|
||||
QVERIFY(!m_testFontCondensed.isEmpty());
|
||||
QVERIFY(!m_testFontItalic.isEmpty());
|
||||
QVERIFY(!m_testFontVariable.isEmpty());
|
||||
}
|
||||
|
||||
void tst_QFontDatabase::styles_data()
|
||||
@ -505,5 +510,47 @@ void tst_QFontDatabase::findCourier()
|
||||
}
|
||||
#endif
|
||||
|
||||
void tst_QFontDatabase::variableFont()
|
||||
{
|
||||
{
|
||||
QFont f;
|
||||
f.setStyleStrategy(QFont::NoFontMerging);
|
||||
QFontPrivate *font_d = QFontPrivate::get(f);
|
||||
if (!font_d->engineForScript(QChar::Script_Common)->supportsVariableApplicationFonts())
|
||||
QSKIP("Variable application fonts only supported on Freetype currently");
|
||||
}
|
||||
|
||||
int id = QFontDatabase::addApplicationFont(m_testFontVariable);
|
||||
if (id == -1)
|
||||
QSKIP("Skip the test since app fonts are not supported on this system");
|
||||
|
||||
QString family = QFontDatabase::applicationFontFamilies(id).first();
|
||||
{
|
||||
QFont font(family);
|
||||
QCOMPARE(QFontInfo(font).styleName(), u"Regular"_s);
|
||||
QCOMPARE(QFontInfo(font).weight(), QFont::Normal);
|
||||
}
|
||||
|
||||
{
|
||||
QFont font(family);
|
||||
font.setWeight(QFont::ExtraBold);
|
||||
QCOMPARE(QFontInfo(font).styleName(), u"QtExtraBold"_s);
|
||||
QCOMPARE(QFontInfo(font).weight(), QFont::ExtraBold);
|
||||
}
|
||||
|
||||
{
|
||||
QFont regularFont(family);
|
||||
QFont extraBoldFont(family);
|
||||
extraBoldFont.setStyleName(u"QtExtraBold"_s);
|
||||
|
||||
QFontMetricsF regularFm(regularFont);
|
||||
QFontMetricsF extraBoldFm(extraBoldFont);
|
||||
|
||||
QVERIFY(regularFm.horizontalAdvance(QLatin1Char('1')) < extraBoldFm.horizontalAdvance(QLatin1Char('1')));
|
||||
}
|
||||
|
||||
QFontDatabase::removeApplicationFont(id);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QFontDatabase)
|
||||
#include "tst_qfontdatabase.moc"
|
||||
|
BIN
tests/auto/shared/resources/testfont_variable.ttf
Normal file
BIN
tests/auto/shared/resources/testfont_variable.ttf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user