QSGDistanceFieldGlyphCache code refactoring.
[profile/ivi/qtdeclarative.git] / src / declarative / scenegraph / qsgdistancefieldglyphnode.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
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 "qsgdistancefieldglyphnode_p.h"
43 #include "qsgdistancefieldglyphnode_p_p.h"
44 #include "qsgdistancefieldglyphcache_p.h"
45 #include <private/qsgcontext_p.h>
46
47 QT_BEGIN_NAMESPACE
48
49 QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheManager *cacheManager)
50     : m_material(0)
51     , m_glyph_cacheManager(cacheManager)
52     , m_glyph_cache(0)
53     , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
54     , m_style(QSGText::Normal)
55     , m_antialiasingMode(GrayAntialiasing)
56     , m_dirtyFont(false)
57     , m_dirtyGeometry(false)
58     , m_dirtyMaterial(false)
59 {
60     m_geometry.setDrawingMode(GL_TRIANGLES);
61     setGeometry(&m_geometry);
62     setPreferredAntialiasingMode(cacheManager->defaultAntialiasingMode());
63 }
64
65 QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
66 {
67     delete m_material;
68     if (m_glyph_cache) {
69         const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
70         m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
71     }
72 }
73
74 void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
75 {
76     m_color = color;
77     if (m_material != 0) {
78         m_material->setColor(color);
79         setMaterial(m_material); // Indicate the material state has changed
80     }
81 }
82
83 void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
84 {
85     if (mode == m_antialiasingMode)
86         return;
87     m_antialiasingMode = mode;
88     m_dirtyMaterial = true;
89 }
90
91 void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
92 {
93     QRawFont font = glyphs.rawFont();
94     m_position = QPointF(position.x(), position.y() - font.ascent());
95     m_glyphs = glyphs;
96
97     m_dirtyFont = true;
98     m_dirtyGeometry = true;
99     m_dirtyMaterial = true;
100 }
101
102 void QSGDistanceFieldGlyphNode::setStyle(QSGText::TextStyle style)
103 {
104     if (m_style == style)
105         return;
106     m_style = style;
107     m_dirtyMaterial = true;
108 }
109
110 void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
111 {
112     if (m_styleColor == color)
113         return;
114     m_styleColor = color;
115     m_dirtyMaterial = true;
116 }
117
118 void QSGDistanceFieldGlyphNode::update()
119 {
120     if (m_dirtyFont)
121         updateFont();
122     if (m_dirtyGeometry)
123         updateGeometry();
124     if (m_dirtyMaterial)
125         updateMaterial();
126 }
127
128 void QSGDistanceFieldGlyphNode::updateGeometry()
129 {
130     Q_ASSERT(m_glyph_cache);
131
132     QSGGeometry *g = geometry();
133     QRectF boundingRect;
134
135     const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
136
137     m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
138
139     Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
140
141     int oldVertexCount = g->vertexCount();
142     int oldIndexCount = g->indexCount();
143
144     // We could potentially move the realloc part into the QSGGeometry object as a
145     // grow() function...
146
147     void *data = 0;
148     if (oldVertexCount && oldIndexCount) {
149         int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
150                      + oldIndexCount * sizeof(quint16);
151         data = qMalloc(byteSize);
152         memcpy(data, g->vertexData(), byteSize);
153     }
154
155     g->allocate(oldVertexCount + glyphIndexes.size() * 4, oldIndexCount + glyphIndexes.size() * 6);
156
157     if (data) {
158         memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
159         memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
160                oldIndexCount * sizeof(quint16));
161         qFree(data);
162     }
163
164     QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D() + oldVertexCount;
165     ushort *ip = g->indexDataAsUShort() + oldIndexCount;
166
167     QPointF margins(2, 2);
168     QPointF texMargins = margins / m_glyph_cache->fontScale();
169
170     for (int i = 0; i < glyphIndexes.size(); ++i) {
171         quint32 glyphIndex = glyphIndexes.at(i);
172         QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
173         QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
174
175         if (!metrics.isNull() && !c.isNull()) {
176                 metrics.width += margins.x() * 2;
177                 metrics.height += margins.y() * 2;
178                 metrics.baselineX -= margins.x();
179                 metrics.baselineY += margins.y();
180                 c.xMargin -= texMargins.x();
181                 c.yMargin -= texMargins.y();
182                 c.width += texMargins.x() * 2;
183                 c.height += texMargins.y() * 2;
184         }
185
186         QPointF glyphPosition = m_glyphs.positions().at(i) + m_position;
187         qreal x = glyphPosition.x() + metrics.baselineX;
188         qreal y = glyphPosition.y() - metrics.baselineY;
189
190         boundingRect |= QRectF(x, y, metrics.width, metrics.height);
191
192         float cx1 = x;
193         float cx2 = x + metrics.width;
194         float cy1 = y;
195         float cy2 = y + metrics.height;
196
197         float tx1 = c.x + c.xMargin;
198         float tx2 = tx1 + c.width;
199         float ty1 = c.y + c.yMargin;
200         float ty2 = ty1 + c.height;
201
202         if (m_baseLine.isNull())
203             m_baseLine = glyphPosition;
204
205         int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
206         vp[4 * vi + 0].set(cx1, cy1, tx1, ty1);
207         vp[4 * vi + 1].set(cx2, cy1, tx2, ty1);
208         vp[4 * vi + 2].set(cx1, cy2, tx1, ty2);
209         vp[4 * vi + 3].set(cx2, cy2, tx2, ty2);
210
211         int o = i * 4 + oldVertexCount;
212         ip[6 * i + 0] = o + 0;
213         ip[6 * i + 1] = o + 2;
214         ip[6 * i + 2] = o + 3;
215         ip[6 * i + 3] = o + 3;
216         ip[6 * i + 4] = o + 1;
217         ip[6 * i + 5] = o + 0;
218     }
219
220 //    printf("Vertices:\n");
221 //    for (int v=0; v<g->vertexCount(); ++v) {
222 //        QSGGeometry::TexturedPoint2D *t = g->vertexDataAsTexturedPoint2D() + v;
223 //        printf(" - %d -- %f %f  --  %.3f %.3f\n", v, t->x, t->y, t->tx, t->ty);
224 //    }
225
226 //    printf("Indices:\n");
227 //    for (int i=0; i<g->indexCount();) {
228
229 //        printf(" - %[ ", i);
230 //        printf("%d, ", g->indexDataAsUShort()[i++]);
231 //        printf("%d, ", g->indexDataAsUShort()[i++]);
232 //        printf("%d, ", g->indexDataAsUShort()[i++]);
233 //        printf("%d, ", g->indexDataAsUShort()[i++]);
234 //        printf("%d, ", g->indexDataAsUShort()[i++]);
235 //        printf("%d",   g->indexDataAsUShort()[i++]);
236 //        printf(" ]\n");
237 //    }
238
239     setBoundingRect(boundingRect);
240     markDirty(DirtyGeometry);
241     m_dirtyGeometry = false;
242 }
243
244 void QSGDistanceFieldGlyphNode::updateFont()
245 {
246     m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
247     m_dirtyFont = false;
248 }
249
250 void QSGDistanceFieldGlyphNode::updateMaterial()
251 {
252     delete m_material;
253
254     if (m_style == QSGText::Normal) {
255         if (m_antialiasingMode == SubPixelAntialiasing)
256             m_material = new QSGSubPixelDistanceFieldTextMaterial;
257         else
258             m_material = new QSGDistanceFieldTextMaterial;
259     } else {
260         QSGDistanceFieldStyledTextMaterial *material;
261         if (m_style == QSGText::Outline) {
262             material = new QSGDistanceFieldOutlineTextMaterial;
263         } else {
264             QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
265             if (m_style == QSGText::Raised)
266                 sMaterial->setShift(QPointF(0.0, 1.0));
267             else
268                 sMaterial->setShift(QPointF(0.0, -1.0));
269             material = sMaterial;
270         }
271         material->setStyleColor(m_styleColor);
272         m_material = material;
273     }
274
275     m_material->setGlyphCache(m_glyph_cache);
276     m_material->setColor(m_color);
277     setMaterial(m_material);
278     m_dirtyMaterial = false;
279 }
280
281 QT_END_NAMESPACE