From 57855fd6a2d3d0d3a1abbafa1000d6a1a7ce3d40 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 12 Mar 2013 18:43:21 +0100 Subject: [PATCH] Implemented text styles for QSGDefaultGlyphNode. Used when Text has renderType: Text.NativeRendering. Task-number: QTBUG-27867 Change-Id: Id1262ef49e26229c86ebd2533b9f6de638bc75cb Reviewed-by: Gunnar Sletta --- src/quick/scenegraph/qsgdefaultglyphnode.cpp | 63 +++++- src/quick/scenegraph/qsgdefaultglyphnode_p.cpp | 279 ++++++++++++++++++++++-- src/quick/scenegraph/qsgdefaultglyphnode_p.h | 12 +- src/quick/scenegraph/qsgdefaultglyphnode_p_p.h | 45 ++++- 4 files changed, 357 insertions(+), 42 deletions(-) diff --git a/src/quick/scenegraph/qsgdefaultglyphnode.cpp b/src/quick/scenegraph/qsgdefaultglyphnode.cpp index 55eadab..8f24485 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode.cpp @@ -48,7 +48,8 @@ QT_BEGIN_NAMESPACE QSGDefaultGlyphNode::QSGDefaultGlyphNode() - : m_material(0) + : m_style(QQuickText::Normal) + , m_material(0) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0) { m_geometry.setDrawingMode(GL_TRIANGLES); @@ -74,22 +75,62 @@ void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &gl if (m_material != 0) delete m_material; - QRawFont font = glyphs.rawFont(); - m_material = new QSGTextMaskMaterial(font); + m_position = position; + m_glyphs = glyphs; + +#ifdef QML_RUNTIME_TESTING + description = QLatin1String("glyphs"); +#endif +} + +void QSGDefaultGlyphNode::setStyle(QQuickText::TextStyle style) +{ + if (m_style == style) + return; + m_style = style; +} + +void QSGDefaultGlyphNode::setStyleColor(const QColor &color) +{ + if (m_styleColor == color) + return; + m_styleColor = color; +} + +void QSGDefaultGlyphNode::update() +{ + QRawFont font = m_glyphs.rawFont(); + QMargins margins(0, 0, 0, 0); + + if (m_style == QQuickText::Normal) { + m_material = new QSGTextMaskMaterial(font); + } else if (m_style == QQuickText::Outline) { + QSGOutlinedTextMaterial *material = new QSGOutlinedTextMaterial(font); + material->setStyleColor(m_styleColor); + m_material = material; + margins = QMargins(1, 1, 1, 1); + } else { + QSGStyledTextMaterial *material = new QSGStyledTextMaterial(font); + if (m_style == QQuickText::Sunken) { + material->setStyleShift(QPointF(0, -1)); + margins.setTop(1); + } else if (m_style == QQuickText::Raised) { + material->setStyleShift(QPointF(0, 1)); + margins.setBottom(1); + } + material->setStyleColor(m_styleColor); + m_material = material; + } + m_material->setColor(m_color); QRectF boundingRect; - m_material->populate(position, glyphs.glyphIndexes(), glyphs.positions(), geometry(), - &boundingRect, &m_baseLine); - - setMaterial(m_material); + m_material->populate(m_position, m_glyphs.glyphIndexes(), m_glyphs.positions(), geometry(), + &boundingRect, &m_baseLine, margins); setBoundingRect(boundingRect); + setMaterial(m_material); markDirty(DirtyGeometry); - -#ifdef QML_RUNTIME_TESTING - description = QLatin1String("glyphs"); -#endif } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 9e0cfca..419062d 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -43,7 +43,6 @@ #include -#include #include #include #include @@ -67,7 +66,7 @@ public: virtual void activate(); virtual void deactivate(); -private: +protected: virtual void initialize(); virtual const char *vertexShader() const; virtual const char *fragmentShader() const; @@ -210,8 +209,197 @@ void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial } } -QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font) - : m_texture(0), m_glyphCache(), m_font(font) +class QSGStyledTextMaterialData : public QSGTextMaskMaterialData +{ +public: + QSGStyledTextMaterialData() { } + + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + virtual void activate(); + virtual void deactivate(); + +private: + virtual void initialize(); + virtual const char *vertexShader() const; + virtual const char *fragmentShader() const; + + int m_shift_id; + int m_styleColor_id; +}; + +void QSGStyledTextMaterialData::initialize() +{ + QSGTextMaskMaterialData::initialize(); + m_shift_id = program()->uniformLocation("shift"); + m_styleColor_id = program()->uniformLocation("styleColor"); +} + +void QSGStyledTextMaterialData::updateState(const RenderState &state, + QSGMaterial *newEffect, + QSGMaterial *oldEffect) +{ + Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + + QSGStyledTextMaterial *material = static_cast(newEffect); + QSGStyledTextMaterial *oldMaterial = static_cast(oldEffect); + + if (oldMaterial == 0 || oldMaterial->styleShift() != material->styleShift()) + program()->setUniformValue(m_shift_id, material->styleShift()); + + if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) { + QColor c = material->color(); + QVector4D color(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF()); + color *= state.opacity(); + program()->setUniformValue(m_color_id, color); + } + + if (oldMaterial == 0 || material->styleColor() != oldMaterial->styleColor() || state.isOpacityDirty()) { + QColor c = material->styleColor(); + QVector4D color(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF()); + color *= state.opacity(); + program()->setUniformValue(m_styleColor_id, color); + } + + bool updated = material->ensureUpToDate(); + Q_ASSERT(material->texture()); + + Q_ASSERT(oldMaterial == 0 || oldMaterial->texture()); + if (updated + || oldMaterial == 0 + || oldMaterial->texture()->textureId() != material->texture()->textureId()) { + program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(), + 1.0 / material->cacheTextureHeight())); + glBindTexture(GL_TEXTURE_2D, material->texture()->textureId()); + + // Set the mag/min filters to be linear. We only need to do this when the texture + // has been recreated. + if (updated) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + } + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); +} + +void QSGStyledTextMaterialData::activate() +{ + QSGMaterialShader::activate(); + +#if !defined(QT_OPENGL_ES_2) && defined(GL_ARB_framebuffer_sRGB) + // 0.25 was found to be acceptable error margin by experimentation. On Mac, the gamma is 2.0, + // but using sRGB looks okay. + if (qAbs(fontSmoothingGamma() - 2.2) < 0.25) + glEnable(GL_FRAMEBUFFER_SRGB); +#endif +} + +void QSGStyledTextMaterialData::deactivate() +{ + QSGMaterialShader::deactivate(); + +#if !defined(QT_OPENGL_ES_2) && defined(GL_ARB_framebuffer_sRGB) + if (qAbs(fontSmoothingGamma() - 2.2) < 0.25) + glDisable(GL_FRAMEBUFFER_SRGB); +#endif +} + +const char *QSGStyledTextMaterialData::vertexShader() const +{ + return + "uniform highp mat4 matrix; \n" + "uniform highp vec2 textureScale; \n" + "uniform highp vec2 shift; \n" + "attribute highp vec4 vCoord; \n" + "attribute highp vec2 tCoord; \n" + "varying highp vec2 sampleCoord; \n" + "varying highp vec2 shiftedSampleCoord; \n" + "void main() { \n" + " sampleCoord = tCoord * textureScale; \n" + " shiftedSampleCoord = (tCoord - shift) * textureScale; \n" + " gl_Position = matrix * vCoord; \n" + "}"; +} + +const char *QSGStyledTextMaterialData::fragmentShader() const +{ + return + "varying highp vec2 sampleCoord; \n" + "varying highp vec2 shiftedSampleCoord; \n" + "uniform sampler2D texture; \n" + "uniform lowp vec4 color; \n" + "uniform lowp vec4 styleColor; \n" + "void main() { \n" + " lowp float glyph = texture2D(texture, sampleCoord).a; \n" + " lowp float style = clamp(texture2D(texture, shiftedSampleCoord).a - glyph, \n" + " 0.0, 1.0); \n" + " gl_FragColor = style * styleColor + glyph * color; \n" + "}"; +} + + +class QSGOutlinedTextMaterialData : public QSGStyledTextMaterialData +{ +public: + QSGOutlinedTextMaterialData() { } + +private: + const char *vertexShader() const; + const char *fragmentShader() const; +}; + +const char *QSGOutlinedTextMaterialData::vertexShader() const +{ + return + "uniform highp mat4 matrix; \n" + "uniform highp vec2 textureScale; \n" + "uniform highp vec2 shift; \n" + "attribute highp vec4 vCoord; \n" + "attribute highp vec2 tCoord; \n" + "varying highp vec2 sampleCoord; \n" + "varying highp vec2 sCoordUp; \n" + "varying highp vec2 sCoordDown; \n" + "varying highp vec2 sCoordLeft; \n" + "varying highp vec2 sCoordRight; \n" + "void main() { \n" + " sampleCoord = tCoord * textureScale; \n" + " sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale; \n" + " sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale; \n" + " sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale; \n" + " sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale; \n" + " gl_Position = matrix * vCoord; \n" + "}"; +} + +const char *QSGOutlinedTextMaterialData::fragmentShader() const +{ + return + "varying highp vec2 sampleCoord; \n" + "varying highp vec2 sCoordUp; \n" + "varying highp vec2 sCoordDown; \n" + "varying highp vec2 sCoordLeft; \n" + "varying highp vec2 sCoordRight; \n" + "uniform sampler2D texture; \n" + "uniform lowp vec4 color; \n" + "uniform lowp vec4 styleColor; \n" + "void main() { \n" + "lowp float glyph = texture2D(texture, sampleCoord).a; \n" + " lowp float outline = clamp(clamp(texture2D(texture, sCoordUp).a + \n" + " texture2D(texture, sCoordDown).a + \n" + " texture2D(texture, sCoordLeft).a + \n" + " texture2D(texture, sCoordRight).a, \n" + " 0.0, 1.0) - glyph, \n" + " 0.0, 1.0); \n" + " gl_FragColor = outline * styleColor + glyph * color; \n" + "}"; +} + +QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font, QFontEngineGlyphCache::Type cacheType) + : m_texture(0) + , m_cacheType(cacheType) + , m_glyphCache(0) + , m_font(font) { init(); } @@ -224,7 +412,6 @@ void QSGTextMaskMaterial::init() { Q_ASSERT(m_font.isValid()); - QFontEngineGlyphCache::Type type = QFontEngineGlyphCache::Raster_RGBMask; setFlag(Blending, true); QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); @@ -232,20 +419,21 @@ void QSGTextMaskMaterial::init() QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); if (fontD->fontEngine != 0) { - m_glyphCache = fontD->fontEngine->glyphCache(ctx, type, QTransform()); - if (!m_glyphCache || m_glyphCache->cacheType() != type) { - m_glyphCache = new QOpenGLTextureGlyphCache(type, QTransform()); + m_glyphCache = fontD->fontEngine->glyphCache(ctx, m_cacheType, QTransform()); + if (!m_glyphCache || m_glyphCache->cacheType() != m_cacheType) { + m_glyphCache = new QOpenGLTextureGlyphCache(m_cacheType, QTransform()); fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data()); } } } void QSGTextMaskMaterial::populate(const QPointF &p, - const QVector &glyphIndexes, - const QVector &glyphPositions, - QSGGeometry *geometry, - QRectF *boundingRect, - QPointF *baseLine) + const QVector &glyphIndexes, + const QVector &glyphPositions, + QSGGeometry *geometry, + QRectF *boundingRect, + QPointF *baseLine, + const QMargins &margins) { Q_ASSERT(m_font.isValid()); QVector fixedPointPositions; @@ -283,15 +471,15 @@ void QSGTextMaskMaterial::populate(const QPointF &p, *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h); - float cx1 = x; - float cx2 = x + c.w; - float cy1 = y; - float cy2 = y + c.h; + float cx1 = x - margins.left(); + float cx2 = x + c.w + margins.right(); + float cy1 = y - margins.top(); + float cy2 = y + c.h + margins.bottom(); - float tx1 = c.x; - float tx2 = (c.x + c.w); - float ty1 = c.y; - float ty2 = (c.y + c.h); + float tx1 = c.x - margins.left(); + float tx2 = c.x + c.w + margins.right(); + float ty1 = c.y - margins.top(); + float ty2 = c.y + c.h + margins.bottom(); if (baseLine->isNull()) *baseLine = glyphPosition; @@ -367,4 +555,53 @@ int QSGTextMaskMaterial::cacheTextureHeight() const return glyphCache()->height(); } + +QSGStyledTextMaterial::QSGStyledTextMaterial(const QRawFont &font) + : QSGTextMaskMaterial(font, QFontEngineGlyphCache::Raster_A8) +{ +} + +QSGMaterialType *QSGStyledTextMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + +QSGMaterialShader *QSGStyledTextMaterial::createShader() const +{ + return new QSGStyledTextMaterialData; +} + +int QSGStyledTextMaterial::compare(const QSGMaterial *o) const +{ + const QSGStyledTextMaterial *other = static_cast(o); + + if (m_styleShift != other->m_styleShift) + return m_styleShift.y() - other->m_styleShift.y(); + + QRgb c1 = m_styleColor.rgba(); + QRgb c2 = other->m_styleColor.rgba(); + if (c1 != c2) + return int(c2 < c1) - int(c1 < c2); + + return QSGTextMaskMaterial::compare(o); +} + + +QSGOutlinedTextMaterial::QSGOutlinedTextMaterial(const QRawFont &font) + : QSGStyledTextMaterial(font) +{ +} + +QSGMaterialType *QSGOutlinedTextMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + +QSGMaterialShader *QSGOutlinedTextMaterial::createShader() const +{ + return new QSGOutlinedTextMaterialData; +} + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h index a3d5d7c..e264c1b 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h @@ -53,22 +53,24 @@ class QSGDefaultGlyphNode: public QSGGlyphNode { public: QSGDefaultGlyphNode(); - ~QSGDefaultGlyphNode(); + virtual ~QSGDefaultGlyphNode(); virtual QPointF baseLine() const { return m_baseLine; } virtual void setGlyphs(const QPointF &position, const QGlyphRun &glyphs); virtual void setColor(const QColor &color); virtual void setPreferredAntialiasingMode(AntialiasingMode) { } - virtual void setStyle(QQuickText::TextStyle) { } - virtual void setStyleColor(const QColor &) { } + virtual void setStyle(QQuickText::TextStyle); + virtual void setStyleColor(const QColor &); - virtual void update() { } + virtual void update(); -private: +protected: QGlyphRun m_glyphs; QPointF m_position; QColor m_color; + QQuickText::TextStyle m_style; + QColor m_styleColor; QPointF m_baseLine; QSGTextMaskMaterial *m_material; diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h index 2635232..d1a739d 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h @@ -43,24 +43,25 @@ #define QSGDEFAULTGLYPHNODE_P_P_H #include +#include #include #include #include #include #include #include +#include QT_BEGIN_NAMESPACE -class QFontEngineGlyphCache; -class QOpenGLTextureGlyphCache; class QFontEngine; class Geometry; class QSGTextMaskMaterial: public QSGMaterial { public: - QSGTextMaskMaterial(const QRawFont &font); - ~QSGTextMaskMaterial(); + QSGTextMaskMaterial(const QRawFont &font, + QFontEngineGlyphCache::Type cacheType = QFontEngineGlyphCache::Raster_RGBMask); + virtual ~QSGTextMaskMaterial(); virtual QSGMaterialType *type() const; virtual QSGMaterialShader *createShader() const; @@ -79,18 +80,52 @@ public: QOpenGLTextureGlyphCache *glyphCache() const; void populate(const QPointF &position, const QVector &glyphIndexes, const QVector &glyphPositions, - QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine); + QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine, + const QMargins &margins = QMargins(0, 0, 0, 0)); private: void init(); QSGPlainTexture *m_texture; + QFontEngineGlyphCache::Type m_cacheType; QExplicitlySharedDataPointer m_glyphCache; QRawFont m_font; QColor m_color; QSize m_size; }; +class QSGStyledTextMaterial : public QSGTextMaskMaterial +{ +public: + QSGStyledTextMaterial(const QRawFont &font); + virtual ~QSGStyledTextMaterial() { } + + void setStyleShift(const QPointF &shift) { m_styleShift = shift; } + const QPointF &styleShift() const { return m_styleShift; } + + void setStyleColor(const QColor &color) { m_styleColor = color; } + const QColor &styleColor() const { return m_styleColor; } + + virtual QSGMaterialType *type() const; + virtual QSGMaterialShader *createShader() const; + + int compare(const QSGMaterial *other) const; + +private: + QPointF m_styleShift; + QColor m_styleColor; +}; + +class QSGOutlinedTextMaterial : public QSGStyledTextMaterial +{ +public: + QSGOutlinedTextMaterial(const QRawFont &font); + ~QSGOutlinedTextMaterial() { } + + QSGMaterialType *type() const; + QSGMaterialShader *createShader() const; +}; + QT_END_NAMESPACE #endif -- 1.7.2.5