From 3f88a5b835198e39e899bc77d798f48f0fe593bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 26 Feb 2014 15:27:23 +0100 Subject: Fix renderType: Text.NativeRendering on retina screens The QSGDefaultGlyphNode's QSGTextMaskMaterial failed to take the device pixel ratio of the surface into account, both when building the glyph cache in init() and when blitting the glyphs from the cache in populate(). We now handle both, resulting in equal rendering as the raster engine, which itself matches CoreText, except for some minor shaping differences. One snag with the QSGTextMaskMaterial compared to eg. the raster engine is that the incoming glyph positions (from shaping) are not pre-scaled, which means we have to be careful to apply the device pixel ratio before rounding the coordinates, to match the behavior of the raster engine. Change-Id: I51cf796bd437f68fad298f689ee3f2d9a2863b4d Reviewed-by: Gunnar Sletta Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 51 ++++++++++++++++++++------ 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src/quick/scenegraph/qsgdefaultglyphnode_p.cpp') diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 3267eeed83..300741bc0a 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -366,19 +366,27 @@ void QSGTextMaskMaterial::init(QFontEngine::GlyphFormat glyphFormat) // sequence. See also QSGRenderContext::invalidate QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); - if (fontD->fontEngine != 0) { + if (QFontEngine *fontEngine = fontD->fontEngine) { if (glyphFormat == QFontEngine::Format_None) { - glyphFormat = fontD->fontEngine->glyphFormat != QFontEngine::Format_None - ? fontD->fontEngine->glyphFormat + glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None + ? fontEngine->glyphFormat : QFontEngine::Format_A32; } - m_glyphCache = fontD->fontEngine->glyphCache(ctx, glyphFormat, QTransform()); + + qreal devicePixelRatio = ctx->surface()->surfaceClass() == QSurface::Window ? + static_cast(ctx->surface())->devicePixelRatio() : ctx->screen()->devicePixelRatio(); + + QTransform glyphCacheTransform = QTransform::fromScale(devicePixelRatio, devicePixelRatio); + if (!fontEngine->supportsTransformation(glyphCacheTransform)) + glyphCacheTransform = QTransform(); + + m_glyphCache = fontEngine->glyphCache(ctx, glyphFormat, glyphCacheTransform); if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) { - m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, QTransform()); - fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data()); + m_glyphCache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform); + fontEngine->setGlyphCache(ctx, m_glyphCache.data()); QSGRenderContext *sg = QSGRenderContext::from(ctx); Q_ASSERT(sg); - sg->registerFontengineForCleanup(fontD->fontEngine); + sg->registerFontengineForCleanup(fontEngine); } } } @@ -405,6 +413,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p, int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat()); + qreal glyphCacheScaleX = cache->transform().m11(); + qreal glyphCacheScaleY = cache->transform().m22(); + qreal glyphCacheInverseScaleX = 1.0 / glyphCacheScaleX; + qreal glyphCacheInverseScaleY = 1.0 / glyphCacheScaleY; + Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT); geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6); QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D(); @@ -420,17 +433,31 @@ void QSGTextMaskMaterial::populate(const QPointF &p, QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition); const QTextureGlyphCache::Coord &c = cache->coords.value(glyph); + if (c.isNull()) + continue; QPointF glyphPosition = glyphPositions.at(i) + position; - int x = qFloor(glyphPosition.x()) + c.baseLineX - margin; - int y = qFloor(glyphPosition.y()) - c.baseLineY - margin; - *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h); + // On a retina screen the glyph positions are not pre-scaled (as opposed to + // eg. the raster paint engine). To ensure that we get the same behavior as + // the raster engine (and CoreText itself) when it comes to rounding of the + // coordinates, we need to apply the scale factor before rounding, and then + // apply the inverse scale to get back to the coordinate system of the node. + + qreal x = (qFloor(glyphPosition.x() * glyphCacheScaleX) * glyphCacheInverseScaleX) + + (c.baseLineX * glyphCacheInverseScaleX) - margin; + qreal y = (qRound(glyphPosition.y() * glyphCacheScaleY) * glyphCacheInverseScaleY) - + (c.baseLineY * glyphCacheInverseScaleY) - margin; + + qreal w = c.w * glyphCacheInverseScaleX; + qreal h = c.h * glyphCacheInverseScaleY; + + *boundingRect |= QRectF(x + margin, y + margin, w, h); float cx1 = x - margins.left(); - float cx2 = x + c.w + margins.right(); + float cx2 = x + w + margins.right(); float cy1 = y - margins.top(); - float cy2 = y + c.h + margins.bottom(); + float cy2 = y + h + margins.bottom(); float tx1 = c.x - margins.left(); float tx2 = c.x + c.w + margins.right(); -- cgit v1.2.3