1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qsgdistancefieldglyphnode_p.h"
43 #include "qsgdistancefieldglyphnode_p_p.h"
44 #include "qsgdistancefieldglyphcache_p.h"
45 #include <private/qsgcontext_p.h>
49 QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheManager *cacheManager)
51 , m_glyph_cacheManager(cacheManager)
53 , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
54 , m_style(QSGText::Normal)
55 , m_antialiasingMode(GrayAntialiasing)
57 , m_dirtyGeometry(false)
58 , m_dirtyMaterial(false)
60 m_geometry.setDrawingMode(GL_TRIANGLES);
61 setGeometry(&m_geometry);
62 setPreferredAntialiasingMode(cacheManager->defaultAntialiasingMode());
65 QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
69 const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
70 m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
74 void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
77 if (m_material != 0) {
78 m_material->setColor(color);
79 setMaterial(m_material); // Indicate the material state has changed
83 void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
85 if (mode == m_antialiasingMode)
87 m_antialiasingMode = mode;
88 m_dirtyMaterial = true;
91 void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
93 QRawFont font = glyphs.rawFont();
94 m_position = QPointF(position.x(), position.y() - font.ascent());
98 m_dirtyGeometry = true;
99 m_dirtyMaterial = true;
102 void QSGDistanceFieldGlyphNode::setStyle(QSGText::TextStyle style)
104 if (m_style == style)
107 m_dirtyMaterial = true;
110 void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
112 if (m_styleColor == color)
114 m_styleColor = color;
115 m_dirtyMaterial = true;
118 void QSGDistanceFieldGlyphNode::update()
128 void QSGDistanceFieldGlyphNode::updateGeometry()
130 Q_ASSERT(m_glyph_cache);
132 QSGGeometry *g = geometry();
135 const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
137 m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
139 Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
141 int oldVertexCount = g->vertexCount();
142 int oldIndexCount = g->indexCount();
144 // We could potentially move the realloc part into the QSGGeometry object as a
145 // grow() function...
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);
155 g->allocate(oldVertexCount + glyphIndexes.size() * 4, oldIndexCount + glyphIndexes.size() * 6);
158 memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
159 memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
160 oldIndexCount * sizeof(quint16));
164 QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D() + oldVertexCount;
165 ushort *ip = g->indexDataAsUShort() + oldIndexCount;
167 QPointF margins(2, 2);
168 QPointF texMargins = margins / m_glyph_cache->fontScale();
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);
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;
186 QPointF glyphPosition = m_glyphs.positions().at(i) + m_position;
187 qreal x = glyphPosition.x() + metrics.baselineX;
188 qreal y = glyphPosition.y() - metrics.baselineY;
190 boundingRect |= QRectF(x, y, metrics.width, metrics.height);
193 float cx2 = x + metrics.width;
195 float cy2 = y + metrics.height;
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;
202 if (m_baseLine.isNull())
203 m_baseLine = glyphPosition;
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);
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;
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);
226 // printf("Indices:\n");
227 // for (int i=0; i<g->indexCount();) {
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++]);
239 setBoundingRect(boundingRect);
240 markDirty(DirtyGeometry);
241 m_dirtyGeometry = false;
244 void QSGDistanceFieldGlyphNode::updateFont()
246 m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
250 void QSGDistanceFieldGlyphNode::updateMaterial()
254 if (m_style == QSGText::Normal) {
255 if (m_antialiasingMode == SubPixelAntialiasing)
256 m_material = new QSGSubPixelDistanceFieldTextMaterial;
258 m_material = new QSGDistanceFieldTextMaterial;
260 QSGDistanceFieldStyledTextMaterial *material;
261 if (m_style == QSGText::Outline) {
262 material = new QSGDistanceFieldOutlineTextMaterial;
264 QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
265 if (m_style == QSGText::Raised)
266 sMaterial->setShift(QPointF(0.0, 1.0));
268 sMaterial->setShift(QPointF(0.0, -1.0));
269 material = sMaterial;
271 material->setStyleColor(m_styleColor);
272 m_material = material;
275 m_material->setGlyphCache(m_glyph_cache);
276 m_material->setColor(m_color);
277 setMaterial(m_material);
278 m_dirtyMaterial = false;