Skip to content

Commit

Permalink
Make it possible to create distance field with specific size
Browse files Browse the repository at this point in the history
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: 5.15 6.2 6.5 6.7 6.8
Task-number: QTBUG-124572
Change-Id: I14e381952fdf331286f1ae4b51bb5fef9e39d704
Reviewed-by: Eirik Aavitsland <[email protected]>
  • Loading branch information
eskilblomfeldt committed Jun 18, 2024
1 parent 90e79ae commit b959b8f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/gui/text/qdistancefield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,14 +839,9 @@ QDistanceFieldData *QDistanceFieldData::create(const QSize &size)
return data;
}

QDistanceFieldData *QDistanceFieldData::create(const QPainterPath &path, bool doubleResolution)
QDistanceFieldData *QDistanceFieldData::create(QSize size, 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));

QDistanceFieldData *data = create(size);
makeDistanceField(data,
path,
QT_DISTANCEFIELD_SCALE(doubleResolution),
Expand All @@ -855,6 +850,16 @@ QDistanceFieldData *QDistanceFieldData::create(const QPainterPath &path, bool do
}


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;

return create(QSize(glyphWidth, glyphHeight), path, doubleResolution);
}


QDistanceField::QDistanceField()
: d(new QDistanceFieldData)
{
Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/gui/text/qdistancefield_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Q_GUI_EXPORT QDistanceFieldData : public QSharedData

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;
Expand All @@ -58,6 +59,7 @@ class Q_GUI_EXPORT QDistanceField
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;

Expand Down

0 comments on commit b959b8f

Please sign in to comment.