Fix crash due to a stale pointer dereferencing
The HB face caching mechanism introduced in 227e9a40cf
wasn't complete due that fact that HB-NG doesn't parse the entire
font table at once but rather references a table on-demand.
This incompleteness caused a crash in case the engine doesn't
get cached or when it removed from the cache and then re-used.
Task-number: QTBUG-36099
Change-Id: I7816836107655ce7cf6eb9683bb5dc7f892f9cd1
Reviewed-by: Lisandro Damián Nicanor Pérez Meyer <perezmeyer@gmail.com>
Reviewed-by: Michael Krasnyk <michael.krasnyk@gmail.com>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
This commit is contained in:
parent
2565ef220b
commit
84be1bd4d3
@ -171,7 +171,8 @@ static const HB_FontClass hb_fontClass = {
|
||||
static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
|
||||
{
|
||||
QFontEngine *fe = (QFontEngine *)font;
|
||||
if (!fe->getSfntTableData(tableTag, buffer, length))
|
||||
Q_ASSERT(fe->faceData.get_font_table);
|
||||
if (!fe->faceData.get_font_table(fe->faceData.user_data, tableTag, buffer, length))
|
||||
return HB_Err_Invalid_Argument;
|
||||
return HB_Err_Ok;
|
||||
}
|
||||
@ -182,6 +183,13 @@ static void hb_freeFace(void *face)
|
||||
}
|
||||
|
||||
|
||||
static bool qt_get_font_table_default(void *user_data, uint tag, uchar *buffer, uint *length)
|
||||
{
|
||||
QFontEngine *fe = (QFontEngine *)user_data;
|
||||
return fe->getSfntTableData(tag, buffer, length);
|
||||
}
|
||||
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
// for testing purpose only, not thread-safe!
|
||||
static QList<QFontEngine *> *enginesCollector = 0;
|
||||
@ -210,6 +218,9 @@ QFontEngine::QFontEngine()
|
||||
font_(0), font_destroy_func(0),
|
||||
face_(0), face_destroy_func(0)
|
||||
{
|
||||
faceData.user_data = this;
|
||||
faceData.get_font_table = qt_get_font_table_default;
|
||||
|
||||
cache_cost = 0;
|
||||
fsType = 0;
|
||||
symbol = false;
|
||||
|
@ -116,6 +116,21 @@ QT_BEGIN_NAMESPACE
|
||||
#define TRUNC(x) ((x) >> 6)
|
||||
#define ROUND(x) (((x)+32) & -64)
|
||||
|
||||
static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
|
||||
{
|
||||
FT_Face face = (FT_Face)user_data;
|
||||
|
||||
bool result = false;
|
||||
if (FT_IS_SFNT(face)) {
|
||||
FT_ULong len = *length;
|
||||
result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
|
||||
*length = len;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------- Freetype support ------------------------------
|
||||
|
||||
class QtFreetypeData
|
||||
@ -408,15 +423,7 @@ QFontEngine::Properties QFreetypeFace::properties() const
|
||||
|
||||
bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
|
||||
{
|
||||
bool result = false;
|
||||
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
|
||||
if (FT_IS_SFNT(face)) {
|
||||
FT_ULong len = *length;
|
||||
result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
|
||||
*length = len;
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
return ft_getSfntTable(face, tag, buffer, length);
|
||||
}
|
||||
|
||||
/* Some fonts (such as MingLiu rely on hinting to scale different
|
||||
@ -761,6 +768,8 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
||||
fontDef.styleName = QString::fromUtf8(face->style_name);
|
||||
|
||||
if (!freetype->hbFace) {
|
||||
faceData.user_data = face;
|
||||
faceData.get_font_table = ft_getSfntTable;
|
||||
freetype->hbFace = harfbuzzFace();
|
||||
freetype->hbFace_destroy_func = face_destroy_func;
|
||||
} else {
|
||||
@ -1179,7 +1188,7 @@ QFixed QFontEngineFT::emSquareSize() const
|
||||
|
||||
bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
|
||||
{
|
||||
return freetype->getSfntTable(tag, buffer, length);
|
||||
return ft_getSfntTable(freetype->face, tag, buffer, length);
|
||||
}
|
||||
|
||||
int QFontEngineFT::synthesized() const
|
||||
|
@ -85,6 +85,7 @@ enum HB_Compat_Error {
|
||||
};
|
||||
|
||||
typedef void (*qt_destroy_func_t) (void *user_data);
|
||||
typedef bool (*qt_get_font_table_func_t) (void *user_data, uint tag, uchar *buffer, uint *length);
|
||||
|
||||
class Q_GUI_EXPORT QFontEngine
|
||||
{
|
||||
@ -280,6 +281,10 @@ public:
|
||||
mutable qt_destroy_func_t font_destroy_func;
|
||||
mutable void *face_;
|
||||
mutable qt_destroy_func_t face_destroy_func;
|
||||
struct FaceData {
|
||||
void *user_data;
|
||||
qt_get_font_table_func_t get_font_table;
|
||||
} faceData;
|
||||
|
||||
uint cache_cost; // amount of mem used in kb by the font
|
||||
uint fsType : 16;
|
||||
|
@ -623,19 +623,22 @@ hb_font_funcs_t *hb_qt_get_font_funcs()
|
||||
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_qt_get_font_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data)
|
||||
_hb_qt_reference_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
QFontEngine *fe = (QFontEngine *)user_data;
|
||||
Q_ASSERT(fe);
|
||||
QFontEngine::FaceData *data = (QFontEngine::FaceData *)user_data;
|
||||
Q_ASSERT(data);
|
||||
|
||||
qt_get_font_table_func_t get_font_table = data->get_font_table;
|
||||
Q_ASSERT(get_font_table);
|
||||
|
||||
uint length = 0;
|
||||
if (Q_UNLIKELY(!fe->getSfntTableData(tag, 0, &length) || length == 0))
|
||||
if (Q_UNLIKELY(!get_font_table(data->user_data, tag, 0, &length) || length == 0))
|
||||
return hb_blob_get_empty();
|
||||
|
||||
char *buffer = (char *)malloc(length);
|
||||
Q_CHECK_PTR(buffer);
|
||||
|
||||
if (Q_UNLIKELY(!fe->getSfntTableData(tag, reinterpret_cast<uchar *>(buffer), &length)))
|
||||
if (Q_UNLIKELY(!get_font_table(data->user_data, tag, reinterpret_cast<uchar *>(buffer), &length)))
|
||||
length = 0;
|
||||
|
||||
return hb_blob_create(const_cast<const char *>(buffer), length,
|
||||
@ -646,9 +649,14 @@ _hb_qt_get_font_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data)
|
||||
static inline hb_face_t *
|
||||
_hb_qt_face_create(QFontEngine *fe)
|
||||
{
|
||||
hb_face_t *face;
|
||||
Q_ASSERT(fe);
|
||||
|
||||
face = hb_face_create_for_tables(_hb_qt_get_font_table, (void *)fe, NULL);
|
||||
QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData));
|
||||
Q_CHECK_PTR(data);
|
||||
data->user_data = fe->faceData.user_data;
|
||||
data->get_font_table = fe->faceData.get_font_table;
|
||||
|
||||
hb_face_t *face = hb_face_create_for_tables(_hb_qt_reference_table, (void *)data, free);
|
||||
if (Q_UNLIKELY(hb_face_is_immutable(face))) {
|
||||
hb_face_destroy(face);
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user