Fix memory corruption on scaled emojis

Bitmap glyphs are returned prescaled, which means we should include
the transform in their bounding box.

Additionally painting them should stick the smallest rect to avoid
writing outside the allocated area, and assert in debug builds.

Task-number: QTBUG-64239
Change-Id: I5f877d36566891323f528018f910798344ba4ce2
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
bb10
Allan Sandfeld Jensen 2017-11-03 14:40:46 +01:00
parent c8fa698e99
commit 7df4dcff2c
3 changed files with 23 additions and 12 deletions

View File

@ -318,11 +318,12 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
return;
}
#endif
Q_ASSERT(mask.width() <= c.w && mask.height() <= c.h);
if (m_format == QFontEngine::Format_A32
|| m_format == QFontEngine::Format_ARGB) {
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
qMin(mask.width(), c.w), qMin(mask.height(), c.h), m_image.bytesPerLine(),
m_image.format());
QPainter p(&ref);
p.setCompositionMode(QPainter::CompositionMode_Source);

View File

@ -1776,15 +1776,25 @@ QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const
return m * scalableBitmapScaleFactor;
}
glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m) const
glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const
{
QTransform trans(t);
const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
trans.scale(scaleFactor, scaleFactor);
QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal());
QPointF offset(m.xoff.toReal(), m.yoff.toReal());
rect = trans.mapRect(rect);
offset = trans.map(offset);
glyph_metrics_t metrics;
metrics.x = scaledBitmapMetrics(m.x);
metrics.y = scaledBitmapMetrics(m.y);
metrics.width = scaledBitmapMetrics(m.width);
metrics.height = scaledBitmapMetrics(m.height);
metrics.xoff = scaledBitmapMetrics(m.xoff);
metrics.yoff = scaledBitmapMetrics(m.yoff);
metrics.x = QFixed::fromReal(rect.x());
metrics.y = QFixed::fromReal(rect.y());
metrics.width = QFixed::fromReal(rect.width());
metrics.height = QFixed::fromReal(rect.height());
metrics.xoff = QFixed::fromReal(offset.x());
metrics.yoff = QFixed::fromReal(offset.y());
return metrics;
}
@ -1878,7 +1888,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
unlockFace();
if (isScalableBitmap())
overall = scaledBitmapMetrics(overall);
overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@ -1917,7 +1927,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
unlockFace();
if (isScalableBitmap())
overall = scaledBitmapMetrics(overall);
overall = scaledBitmapMetrics(overall, QTransform());
return overall;
}
@ -1955,7 +1965,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
}
if (isScalableBitmap())
overall = scaledBitmapMetrics(overall);
overall = scaledBitmapMetrics(overall, matrix);
return overall;
}

View File

@ -321,7 +321,7 @@ private:
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
bool shouldUseDesignMetrics(ShaperFlags flags) const;
QFixed scaledBitmapMetrics(QFixed m) const;
glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m) const;
glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const;
GlyphFormat defaultFormat;
FT_Matrix matrix;