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