FreeType: Load multiple font faces from the same file on macOS
Previously, if a font file contained multiple font faces, only the first could ever be loaded. This could lead to Qt loading different font styles than requested by the application. [ChangeLog][Text][Freetype] Fixed a bug where the macOS FreeType backend would fail to load font faces from font files containing multiple faces. Fixes: QTBUG-100666 Pick-to: 6.2 6.3 Change-Id: I6a126266a2e15f843dd578ab25c11748881bb932 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
parent
d34ae86a00
commit
af875e88f4
@ -403,9 +403,15 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
|
||||
return QFontEngineFT::create(*fontData, fontDef.pixelSize,
|
||||
static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
|
||||
} else if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) {
|
||||
Q_ASSERT(url.fileURL);
|
||||
QFontEngine::FaceId faceId;
|
||||
faceId.filename = QString::fromNSString(url.path).toUtf8();
|
||||
|
||||
Q_ASSERT(url.fileURL);
|
||||
QString faceFileName{QString::fromNSString(url.path)};
|
||||
faceId.filename = faceFileName.toUtf8();
|
||||
|
||||
QString styleName = QCFString(CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute));
|
||||
faceId.index = QFreetypeFace::getFaceIndexByStyleName(faceFileName, styleName);
|
||||
|
||||
return QFontEngineFT::create(fontDef, faceId);
|
||||
}
|
||||
// We end up here with a descriptor does not contain Qt font data or kCTFontURLAttribute.
|
||||
|
@ -128,8 +128,19 @@ public:
|
||||
{ }
|
||||
~QtFreetypeData();
|
||||
|
||||
struct FaceStyle {
|
||||
QString faceFileName;
|
||||
QString styleName;
|
||||
|
||||
FaceStyle(QString faceFileName, QString styleName)
|
||||
: faceFileName(std::move(faceFileName)),
|
||||
styleName(std::move(styleName))
|
||||
{}
|
||||
};
|
||||
|
||||
FT_Library library;
|
||||
QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
|
||||
QHash<FaceStyle, int> faceIndices;
|
||||
};
|
||||
|
||||
QtFreetypeData::~QtFreetypeData()
|
||||
@ -141,6 +152,16 @@ QtFreetypeData::~QtFreetypeData()
|
||||
library = nullptr;
|
||||
}
|
||||
|
||||
inline bool operator==(const QtFreetypeData::FaceStyle &style1, const QtFreetypeData::FaceStyle &style2)
|
||||
{
|
||||
return style1.faceFileName == style2.faceFileName && style1.styleName == style2.styleName;
|
||||
}
|
||||
|
||||
inline size_t qHash(const QtFreetypeData::FaceStyle &style, size_t seed)
|
||||
{
|
||||
return qHashMulti(seed, style.faceFileName, style.styleName);
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
|
||||
|
||||
QtFreetypeData *qt_getFreetypeData()
|
||||
@ -336,6 +357,52 @@ void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
|
||||
}
|
||||
}
|
||||
|
||||
static int computeFaceIndex(const QString &faceFileName, const QString &styleName)
|
||||
{
|
||||
FT_Library library = qt_getFreetype();
|
||||
|
||||
int faceIndex = 0;
|
||||
int numFaces = 0;
|
||||
|
||||
do {
|
||||
FT_Face face;
|
||||
|
||||
FT_Error error = FT_New_Face(library, faceFileName.toUtf8().constData(), faceIndex, &face);
|
||||
if (error != FT_Err_Ok) {
|
||||
qDebug() << "FT_New_Face failed for face index" << faceIndex << ':' << Qt::hex << error;
|
||||
break;
|
||||
}
|
||||
|
||||
QString faceStyleName = QString::fromLatin1(face->style_name);
|
||||
numFaces = face->num_faces;
|
||||
|
||||
FT_Done_Face(face);
|
||||
|
||||
if (faceStyleName == styleName)
|
||||
return faceIndex;
|
||||
} while (++faceIndex < numFaces);
|
||||
|
||||
// Fall back to the first font face in the file
|
||||
return 0;
|
||||
}
|
||||
|
||||
int QFreetypeFace::getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName)
|
||||
{
|
||||
QtFreetypeData *freetypeData = qt_getFreetypeData();
|
||||
|
||||
// Try to get from cache
|
||||
QtFreetypeData::FaceStyle faceStyle(faceFileName, styleName);
|
||||
int faceIndex = freetypeData->faceIndices.value(faceStyle, -1);
|
||||
|
||||
if (faceIndex >= 0)
|
||||
return faceIndex;
|
||||
|
||||
faceIndex = computeFaceIndex(faceFileName, styleName);
|
||||
|
||||
freetypeData->faceIndices.insert(faceStyle, faceIndex);
|
||||
|
||||
return faceIndex;
|
||||
}
|
||||
|
||||
void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor)
|
||||
{
|
||||
|
@ -85,6 +85,8 @@ public:
|
||||
const QByteArray &fontData = QByteArray());
|
||||
void release(const QFontEngine::FaceId &face_id);
|
||||
|
||||
static int getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName);
|
||||
|
||||
// locks the struct for usage. Any read/write operations require locking.
|
||||
void lock()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user