d99ea2bfba20c85500393df01a2aed5b7ff6e488
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / qsgdefaultglyphnode_p.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgdefaultglyphnode_p_p.h"
43
44 #include <qopenglshaderprogram.h>
45
46 #include <QtGui/private/qopengltextureglyphcache_p.h>
47 #include <private/qfontengine_p.h>
48 #include <private/qopenglextensions_p.h>
49
50 #include <QtQuick/private/qsgtexture_p.h>
51
52 #include <private/qrawfont_p.h>
53
54 QT_BEGIN_NAMESPACE
55
56 class QSGTextMaskMaterialData : public QSGMaterialShader
57 {
58 public:
59     QSGTextMaskMaterialData();
60
61     virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
62     virtual char const *const *attributeNames() const;
63 private:
64     virtual void initialize();
65     virtual const char *vertexShader() const;
66     virtual const char *fragmentShader() const;
67
68     int m_matrix_id;
69     int m_color_id;
70     int m_textureScale_id;
71 };
72
73 const char *QSGTextMaskMaterialData::vertexShader() const {
74     return
75         "uniform highp mat4 matrix;                     \n"
76         "uniform highp vec2 textureScale;               \n"
77         "attribute highp vec4 vCoord;                   \n"
78         "attribute highp vec2 tCoord;                   \n"
79         "varying highp vec2 sampleCoord;                \n"
80         "void main() {                                  \n"
81         "     sampleCoord = tCoord * textureScale;      \n"
82         "     gl_Position = matrix * vCoord;            \n"
83         "}";
84 }
85
86 const char *QSGTextMaskMaterialData::fragmentShader() const {
87     return
88         "varying highp vec2 sampleCoord;                \n"
89         "uniform sampler2D texture;                     \n"
90         "uniform lowp vec4 color;                       \n"
91         "void main() {                                  \n"
92         "    gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
93         "}";
94 }
95
96 char const *const *QSGTextMaskMaterialData::attributeNames() const
97 {
98     static char const *const attr[] = { "vCoord", "tCoord", 0 };
99     return attr;
100 }
101
102 QSGTextMaskMaterialData::QSGTextMaskMaterialData()
103 {
104 }
105
106 void QSGTextMaskMaterialData::initialize()
107 {
108     m_matrix_id = program()->uniformLocation("matrix");
109     m_color_id = program()->uniformLocation("color");
110     m_textureScale_id = program()->uniformLocation("textureScale");
111 }
112
113 void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
114 {
115     Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
116     QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect);
117     QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect);
118
119     if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) {
120         QVector4D color(material->color().redF(), material->color().greenF(),
121                         material->color().blueF(), material->color().alphaF());
122         color *= state.opacity();
123         program()->setUniformValue(m_color_id, color);
124     }
125
126     bool updated = material->ensureUpToDate();
127     Q_ASSERT(material->texture());
128
129     Q_ASSERT(oldMaterial == 0 || oldMaterial->texture());
130     if (updated
131             || oldMaterial == 0
132             || oldMaterial->texture()->textureId() != material->texture()->textureId()) {
133         program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
134                                                                1.0 / material->cacheTextureHeight()));
135         glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
136
137         // Set the mag/min filters to be linear. We only need to do this when the texture
138         // has been recreated.
139         if (updated) {
140             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
141             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
142         }
143     }
144
145     if (state.isMatrixDirty())
146         program()->setUniformValue(m_matrix_id, state.combinedMatrix());
147 }
148
149 QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font)
150     : m_texture(0), m_glyphCache(), m_font(font)
151 {
152     init();
153 }
154
155 QSGTextMaskMaterial::~QSGTextMaskMaterial()
156 {
157 }
158
159 void QSGTextMaskMaterial::init()
160 {
161     Q_ASSERT(m_font.isValid());
162
163     QFontEngineGlyphCache::Type type = QFontEngineGlyphCache::Raster_A8;
164     setFlag(Blending, true);
165
166     QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
167     Q_ASSERT(ctx != 0);
168
169     QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
170     if (fontD->fontEngine != 0) {
171         m_glyphCache = fontD->fontEngine->glyphCache(ctx, type, QTransform());
172         if (!m_glyphCache || m_glyphCache->cacheType() != type) {
173             m_glyphCache = new QOpenGLTextureGlyphCache(type, QTransform());
174             fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
175         }
176     }
177 }
178
179 void QSGTextMaskMaterial::populate(const QPointF &p,
180                                 const QVector<quint32> &glyphIndexes,
181                                 const QVector<QPointF> &glyphPositions,
182                                 QSGGeometry *geometry,
183                                 QRectF *boundingRect,
184                                 QPointF *baseLine)
185 {
186     Q_ASSERT(m_font.isValid());
187     QVector<QFixedPoint> fixedPointPositions;
188     for (int i=0; i<glyphPositions.size(); ++i)
189         fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i)));
190
191     QTextureGlyphCache *cache = glyphCache();
192
193     QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
194     cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
195                     fixedPointPositions.data());
196     cache->fillInPendingGlyphs();
197
198     int margin = fontD->fontEngine->glyphMargin(cache->cacheType());
199
200     Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT);
201     geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
202     QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D();
203     Q_ASSERT(geometry->sizeOfVertex() == sizeof(QVector4D));
204     ushort *ip = geometry->indexDataAsUShort();
205
206     QPointF position(p.x(), p.y() - m_font.ascent());
207     bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
208     for (int i=0; i<glyphIndexes.size(); ++i) {
209          QFixed subPixelPosition;
210          if (supportsSubPixelPositions)
211              subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x()));
212
213          QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
214          const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
215
216          QPointF glyphPosition = glyphPositions.at(i) + position;
217          int x = qRound(glyphPosition.x()) + c.baseLineX - margin;
218          int y = qRound(glyphPosition.y()) - c.baseLineY - margin;
219
220          *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h);
221
222          float cx1 = x;
223          float cx2 = x + c.w;
224          float cy1 = y;
225          float cy2 = y + c.h;
226
227          float tx1 = c.x;
228          float tx2 = (c.x + c.w);
229          float ty1 = c.y;
230          float ty2 = (c.y + c.h);
231
232          if (baseLine->isNull())
233              *baseLine = glyphPosition;
234
235          vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1);
236          vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1);
237          vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2);
238          vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2);
239
240          int o = i * 4;
241          ip[6 * i + 0] = o + 0;
242          ip[6 * i + 1] = o + 2;
243          ip[6 * i + 2] = o + 3;
244          ip[6 * i + 3] = o + 3;
245          ip[6 * i + 4] = o + 1;
246          ip[6 * i + 5] = o + 0;
247     }
248 }
249
250 QSGMaterialType *QSGTextMaskMaterial::type() const
251 {
252     static QSGMaterialType type;
253     return &type;
254 }
255
256 QOpenGLTextureGlyphCache *QSGTextMaskMaterial::glyphCache() const
257 {
258     return static_cast<QOpenGLTextureGlyphCache*>(m_glyphCache.data());
259 }
260
261 QSGMaterialShader *QSGTextMaskMaterial::createShader() const
262 {
263     return new QSGTextMaskMaterialData;
264 }
265
266 int QSGTextMaskMaterial::compare(const QSGMaterial *o) const
267 {
268     Q_ASSERT(o && type() == o->type());
269     const QSGTextMaskMaterial *other = static_cast<const QSGTextMaskMaterial *>(o);
270     if (m_glyphCache != other->m_glyphCache)
271         return m_glyphCache - other->m_glyphCache;
272     QRgb c1 = m_color.rgba();
273     QRgb c2 = other->m_color.rgba();
274     return int(c2 < c1) - int(c1 < c2);
275 }
276
277 bool QSGTextMaskMaterial::ensureUpToDate()
278 {
279     QSize glyphCacheSize(glyphCache()->width(), glyphCache()->height());
280     if (glyphCacheSize != m_size) {
281         if (m_texture)
282             delete m_texture;
283         m_texture = new QSGPlainTexture();
284         m_texture->setTextureId(glyphCache()->texture());
285         m_texture->setTextureSize(QSize(glyphCache()->width(), glyphCache()->height()));
286         m_texture->setOwnsTexture(false);
287
288         m_size = glyphCacheSize;
289
290         return true;
291     } else {
292         return false;
293     }
294 }
295
296 int QSGTextMaskMaterial::cacheTextureWidth() const
297 {
298     return glyphCache()->width();
299 }
300
301 int QSGTextMaskMaterial::cacheTextureHeight() const
302 {
303     return glyphCache()->height();
304 }
305
306 QT_END_NAMESPACE