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