macOS: Prevent leaking font data when creating QRawFont from QByteArrays

CTFontCreateWithGraphicsFont has a bug causing it to never release the
graphics font, which cascades down to the data provider never being
released and releaseFontData never being called.

Instead of relying on a callback to release the byte array font data,
we attach the font data to the engine's lifetime. Note that we are
still leaking the CoreFoundation types.

Change-Id: I6eda4212638ccc9439b90e004222272d204c707a
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Tor Arne Vestbø 2017-04-05 13:35:11 +02:00
parent 31273f079e
commit f9226217d1
3 changed files with 45 additions and 27 deletions

View File

@ -419,37 +419,16 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
}
#endif
template <>
QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
template <class T>
QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
Q_UNUSED(hintingPreference);
QByteArray* fontDataCopy = new QByteArray(fontData);
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider);
QFontEngine *fontEngine = NULL;
if (cgFont == NULL) {
qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
} else {
QFontDef def;
def.pixelSize = pixelSize;
def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
fontEngine = new QCoreTextFontEngine(cgFont, def);
CFRelease(cgFont);
}
return fontEngine;
return T::create(fontData, pixelSize, hintingPreference);
}
// Explicitly instantiate so that we don't need the plugin to involve FreeType
template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>;
#ifndef QT_NO_FREETYPE
template <>
QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
}
template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>;
#endif
QFont::StyleHint styleHintFromNSString(NSString *style)

View File

@ -177,6 +177,43 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)
return transform;
}
// Keeps font data alive until engine is disposed
class QCoreTextRawFontEngine : public QCoreTextFontEngine
{
public:
QCoreTextRawFontEngine(CGFontRef font, const QFontDef &def, const QByteArray &fontData)
: QCoreTextFontEngine(font, def)
, m_fontData(fontData)
{}
QByteArray m_fontData;
};
QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
Q_UNUSED(hintingPreference);
QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference);
// Note: CTFontCreateWithGraphicsFont (which we call from the QCoreTextFontEngine
// constructor) has a bug causing it to retain the CGFontRef but never release it.
// The result is that we are leaking the CGFont, CGDataProvider, and CGData, but
// as the CGData is created from the raw QByteArray data, which we deref in the
// subclass above during destruction, we're at least not leaking the font data,
// (unless CoreText copies it internally). http://stackoverflow.com/questions/40805382/
QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
if (!cgFont) {
qWarning("QCoreTextFontEngine::create: CGFontCreateWithDataProvider failed");
return nullptr;
}
QFontDef def;
def.pixelSize = pixelSize;
def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
return new QCoreTextRawFontEngine(cgFont, def, fontData);
}
QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
: QFontEngine(Mac)
{

View File

@ -123,6 +123,8 @@ public:
static int antialiasingThreshold;
static QFontEngine::GlyphFormat defaultGlyphFormat;
static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
private:
void init();
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m);