Make it possible to create distance field with specific size

The distance field size calculation is floating point math
and  sensitive to numerical errors. When used in Qt Quick,
it is vital that the allocated memory is the same as what
we calculate in the cache, otherwise we will get memory
corruption. In certain cases, numerical errors would cause
a qCeil() to round what was actually an integer up, and
we would end up with an allocated size that was off by one.

To avoid this, we allow the user to specify the size to
allocate, so that we can do the calculation in a single
place.

Pick-to: 6.7 6.5 6.2 5.15
Task-number: QTBUG-124572
Change-Id: I14e381952fdf331286f1ae4b51bb5fef9e39d704
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
(cherry picked from commit b959b8f5ed537f530221e0174b723ea39a34cd58)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2024-06-18 08:47:25 +02:00 committed by Qt Cherry-pick Bot
parent 56d0227a73
commit 260685d1ee
2 changed files with 24 additions and 7 deletions

View File

@ -839,19 +839,24 @@ QDistanceFieldData *QDistanceFieldData::create(const QSize &size)
return data;
}
QDistanceFieldData *QDistanceFieldData::create(QSize size, const QPainterPath &path, bool doubleResolution)
{
QDistanceFieldData *data = create(size);
makeDistanceField(data,
path,
QT_DISTANCEFIELD_SCALE(doubleResolution),
QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution));
return data;
}
QDistanceFieldData *QDistanceFieldData::create(const QPainterPath &path, bool doubleResolution)
{
int dfMargin = QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution);
int glyphWidth = qCeil(path.boundingRect().width() / QT_DISTANCEFIELD_SCALE(doubleResolution)) + dfMargin * 2;
int glyphHeight = qCeil(path.boundingRect().height() / QT_DISTANCEFIELD_SCALE(doubleResolution)) + dfMargin * 2;
QDistanceFieldData *data = create(QSize(glyphWidth, glyphHeight));
makeDistanceField(data,
path,
QT_DISTANCEFIELD_SCALE(doubleResolution),
QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution));
return data;
return create(QSize(glyphWidth, glyphHeight), path, doubleResolution);
}
@ -875,6 +880,16 @@ QDistanceField::QDistanceField(QFontEngine *fontEngine, glyph_t glyph, bool doub
setGlyph(fontEngine, glyph, doubleResolution);
}
QDistanceField::QDistanceField(QSize size, const QPainterPath &path, glyph_t glyph, bool doubleResolution)
{
QPainterPath dfPath = path;
dfPath.translate(-dfPath.boundingRect().topLeft());
dfPath.setFillRule(Qt::WindingFill);
d = QDistanceFieldData::create(size, dfPath, doubleResolution);
d->glyph = glyph;
}
QDistanceField::QDistanceField(const QPainterPath &path, glyph_t glyph, bool doubleResolution)
{
QPainterPath dfPath = path;

View File

@ -42,6 +42,7 @@ public:
static QDistanceFieldData *create(const QSize &size);
static QDistanceFieldData *create(const QPainterPath &path, bool doubleResolution);
static QDistanceFieldData *create(QSize size, const QPainterPath &path, bool doubleResolution);
glyph_t glyph;
int width;
@ -58,6 +59,7 @@ public:
QDistanceField(const QRawFont &font, glyph_t glyph, bool doubleResolution = false);
QDistanceField(QFontEngine *fontEngine, glyph_t glyph, bool doubleResolution = false);
QDistanceField(const QPainterPath &path, glyph_t glyph, bool doubleResolution = false);
QDistanceField(QSize size, const QPainterPath &path, glyph_t glyph, bool doubleResolution = false);
bool isNull() const;