Add support for retina glyph-based text drawing in the GL paint-engine

Instead of always using a non-transformed glyph-cache we now allow a scaled
glyph-cache so that retina-screens can take advantage of this. We take
the cache's scale into account when positioning and drawing the glyphs
so that the scale is not applied twice.

Change-Id: Ia927656f0070df61e78da76e97d2c49de4d856d9
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
Tor Arne Vestbø 2013-01-15 15:32:41 +01:00 committed by The Qt Project
parent 04773fe72e
commit b5922c89ba
5 changed files with 53 additions and 18 deletions

View File

@ -1069,6 +1069,18 @@ void QOpenGL2PaintEngineExPrivate::resetClipIfNeeded()
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache)
{
Q_Q(QOpenGL2PaintEngineEx);
QTransform &transform = q->state()->matrix;
transform.scale(1.0 / cache.transform().m11(), 1.0 / cache.transform().m22());
bool ret = prepareForDraw(false);
transform.scale(cache.transform().m11(), cache.transform().m22());
return ret;
}
bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
@ -1543,10 +1555,14 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
bool recreateVertexArrays = false;
QFontEngine *fe = staticTextItem->fontEngine();
// We allow scaling, so that the glyph-cache will contain glyphs with the
// appropriate resolution in the case of displays with a device-pixel-ratio != 1.
QTransform transform = QTransform::fromScale(s->matrix.m11(), s->matrix.m22());
QOpenGLTextureGlyphCache *cache =
(QOpenGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphType, QTransform());
(QOpenGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphType, transform);
if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) {
cache = new QOpenGLTextureGlyphCache(glyphType, QTransform());
cache = new QOpenGLTextureGlyphCache(glyphType, transform);
fe->setGlyphCache(cacheKey, cache);
recreateVertexArrays = true;
}
@ -1638,8 +1654,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
if (c.isNull())
continue;
int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin;
int y = qRound(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin;
int x = qFloor(staticTextItem->glyphPositions[i].x.toReal() * cache->transform().m11()) + c.baseLineX - margin;
int y = qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22()) - c.baseLineY - margin;
vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
@ -1712,9 +1728,9 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
}
compositionModeDirty = false; // I can handle this myself, thank you very much
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
// prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset.
// prepareForCachedGlyphDraw() have set the opacity on the current shader, so the opacity state can now be reset.
if (compMode == QPainter::CompositionMode_Source) {
q->state()->opacity = oldOpacity;
opacityUniformDirty = true;
@ -1735,7 +1751,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
}
compositionModeDirty = false; // I can handle this myself, thank you very much
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
@ -1759,7 +1775,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
}
compositionModeDirty = false;
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
}
@ -1768,7 +1784,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
// Greyscale/mono glyphs
shaderManager->setMaskType(QOpenGLEngineShaderManager::PixelMask);
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
}
QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest;

View File

@ -236,6 +236,7 @@ public:
void setBrush(const QBrush& brush);
void transferMode(EngineMode newMode);
bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed
bool prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache);
inline void useSimpleShader();
inline GLuint location(const QOpenGLEngineShaderManager::Uniform uniform) {
return shaderManager->getUniformLocation(uniform);

View File

@ -78,6 +78,7 @@ public:
virtual ~QFontEngineGlyphCache() { }
Type cacheType() const { return m_type; }
const QTransform &transform() const { return m_transform; }
QTransform m_transform;
QFontEngineGlyphCache::Type m_type;

View File

@ -1086,6 +1086,18 @@ void QGL2PaintEngineExPrivate::resetClipIfNeeded()
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
bool QGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache)
{
Q_Q(QGL2PaintEngineEx);
QTransform &transform = q->state()->matrix;
transform.scale(1.0 / cache.transform().m11(), 1.0 / cache.transform().m22());
bool ret = prepareForDraw(false);
transform.scale(cache.transform().m11(), cache.transform().m22());
return ret;
}
bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
@ -1580,11 +1592,15 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
void *cacheKey = const_cast<QGLContext *>(QGLContextPrivate::contextGroup(ctx)->context());
bool recreateVertexArrays = false;
// We allow scaling, so that the glyph-cache will contain glyphs with the
// appropriate resolution in the case of displays with a device-pixel-ratio != 1.
QTransform transform = QTransform::fromScale(s->matrix.m11(), s->matrix.m22());
QFontEngine *fe = staticTextItem->fontEngine();
QGLTextureGlyphCache *cache =
(QGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphType, QTransform());
(QGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphType, transform);
if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) {
cache = new QGLTextureGlyphCache(glyphType, QTransform());
cache = new QGLTextureGlyphCache(glyphType, transform);
fe->setGlyphCache(cacheKey, cache);
recreateVertexArrays = true;
}
@ -1676,8 +1692,8 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
if (c.isNull())
continue;
int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin;
int y = qRound(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin;
int x = qFloor(staticTextItem->glyphPositions[i].x.toReal() * cache->transform().m11()) + c.baseLineX - margin;
int y = qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22()) - c.baseLineY - margin;
vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
@ -1750,9 +1766,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
}
compositionModeDirty = false; // I can handle this myself, thank you very much
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
// prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset.
// prepareForCachedGlyphDraw() have set the opacity on the current shader, so the opacity state can now be reset.
if (compMode == QPainter::CompositionMode_Source) {
q->state()->opacity = oldOpacity;
opacityUniformDirty = true;
@ -1773,7 +1789,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
}
compositionModeDirty = false; // I can handle this myself, thank you very much
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND);
glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
@ -1797,7 +1813,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
}
compositionModeDirty = false;
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
}
@ -1806,7 +1822,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
// Greyscale/mono glyphs
shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
prepareForDraw(false); // Text always causes src pixels to be transparent
prepareForCachedGlyphDraw(*cache);
}
QGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QGLTextureGlyphCache::Linear:QGLTextureGlyphCache::Nearest;

View File

@ -227,6 +227,7 @@ public:
void setBrush(const QBrush& brush);
void transferMode(EngineMode newMode);
bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed
bool prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache);
inline void useSimpleShader();
inline GLuint location(const QGLEngineShaderManager::Uniform uniform) {
return shaderManager->getUniformLocation(uniform);