From f9226217d1b653e7786f8b920f6b36bfd4bd0512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 5 Apr 2017 13:35:11 +0200 Subject: 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 --- .../fontdatabases/mac/qcoretextfontdatabase.mm | 33 ++++--------------- .../fontdatabases/mac/qfontengine_coretext.mm | 37 ++++++++++++++++++++++ .../fontdatabases/mac/qfontengine_coretext_p.h | 2 ++ 3 files changed, 45 insertions(+), 27 deletions(-) (limited to 'src/platformsupport/fontdatabases') diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 1862900d48..3b9a456be0 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -419,37 +419,16 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const } #endif -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +template +QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { - Q_UNUSED(hintingPreference); - - QByteArray* fontDataCopy = new QByteArray(fontData); - QCFType 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; #ifndef QT_NO_FREETYPE -template <> -QFontEngine *QCoreTextFontDatabaseEngineFactory::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - return QFontEngineFT::create(fontData, pixelSize, hintingPreference); -} +template class QCoreTextFontDatabaseEngineFactory; #endif QFont::StyleHint styleHintFromNSString(NSString *style) diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index c8ae342f16..49a6049c4b 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -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 fontDataReference = fontData.toRawCFData(); + QCFType 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 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) { diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index 0074790e43..2986f0aaec 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -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); -- cgit v1.2.3