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