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:
parent
31273f079e
commit
f9226217d1
@ -419,37 +419,16 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <>
|
template <class T>
|
||||||
QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
||||||
{
|
{
|
||||||
Q_UNUSED(hintingPreference);
|
return T::create(fontData, pixelSize, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly instantiate so that we don't need the plugin to involve FreeType
|
||||||
|
template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>;
|
||||||
#ifndef QT_NO_FREETYPE
|
#ifndef QT_NO_FREETYPE
|
||||||
template <>
|
template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>;
|
||||||
QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
|
||||||
{
|
|
||||||
return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QFont::StyleHint styleHintFromNSString(NSString *style)
|
QFont::StyleHint styleHintFromNSString(NSString *style)
|
||||||
|
@ -177,6 +177,43 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)
|
|||||||
return transform;
|
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)
|
QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
|
||||||
: QFontEngine(Mac)
|
: QFontEngine(Mac)
|
||||||
{
|
{
|
||||||
|
@ -123,6 +123,8 @@ public:
|
|||||||
|
|
||||||
static int antialiasingThreshold;
|
static int antialiasingThreshold;
|
||||||
static QFontEngine::GlyphFormat defaultGlyphFormat;
|
static QFontEngine::GlyphFormat defaultGlyphFormat;
|
||||||
|
|
||||||
|
static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m);
|
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user