From 8e7db0dd1cdc63c962359b37f882643dd3ed0e1a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 20 Jun 2019 09:55:40 +0200 Subject: distancefieldgenerator: Avoid exceeding max texture size Since we use a single area allocator for all textures, a glyph on the edge between two textures, would end up spanning two textures. It would be assigned to the first, and which in turn would be expanded to account for the additional data. The result was that the texture height exceeded the maximum size set. This is actually an inherited problem from Qt Quick, but it happens more frequently with the distancefieldgenerator because you will typically generate a large number of glyphs, and also the default max size set is quite low to be on the safe side. The bandaid in this patch is to pad the texture height by the size of one glyph, which will for the most part get rid of the problem, except for fonts where a majority of glyphs exceed the em square. [ChangeLog][distancefieldgenerator] Fixed a bug where the generated textures might exceed the maximum height. Task-number: QTBUG-76528 Change-Id: I51487bbf7c46556b022bfd45cefc8776d0272de3 Reviewed-by: Simon Hausmann --- src/distancefieldgenerator/mainwindow.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/distancefieldgenerator/mainwindow.cpp b/src/distancefieldgenerator/mainwindow.cpp index 763aeaa6b..a3f48cb0a 100644 --- a/src/distancefieldgenerator/mainwindow.cpp +++ b/src/distancefieldgenerator/mainwindow.cpp @@ -417,10 +417,20 @@ QByteArray MainWindow::createSfntTable() header.minorVersion = 12; header.pixelSize = qToBigEndian(quint16(qRound(m_model->pixelSize()))); + const quint8 padding = 2; + qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); + const int radius = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) + / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); + quint32 textureSize = ui->sbMaximumTextureSize->value(); + + // Since we are using a single area allocator that spans all textures, we need + // to split the textures one row before the actual maximum size, otherwise + // glyphs that fall on the edge between two textures will expand the texture + // they are assigned to, and this will end up being larger than the max. + textureSize -= quint32(qCeil(m_model->pixelSize() * scaleFactor) + radius * 2 + padding * 2); header.textureSize = qToBigEndian(textureSize); - const quint8 padding = 2; header.padding = padding; header.flags = m_model->doubleGlyphResolution() ? 1 : 0; header.numGlyphs = qToBigEndian(quint32(list.size())); @@ -443,13 +453,9 @@ QByteArray MainWindow::createSfntTable() int textureCount = 0; { - qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); QTransform scaleDown; scaleDown.scale(scaleFactor, scaleFactor); - const int radius = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) - / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); - { bool foundOptimalSize = false; while (!foundOptimalSize) { @@ -466,6 +472,7 @@ QByteArray MainWindow::createSfntTable() glyphData.boundingRect = scaleDown.mapRect(path.boundingRect()); int glyphWidth = qCeil(glyphData.boundingRect.width()) + radius * 2; int glyphHeight = qCeil(glyphData.boundingRect.height()) + radius * 2; + glyphData.glyphSize = QSize(glyphWidth + padding * 2, glyphHeight + padding * 2); if (glyphData.glyphSize.width() > qint32(textureSize) -- cgit v1.2.3