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 <QtQuick/private/qsgdistancefieldutil_p.h>
45 #include <QtQuick/private/qsgcontext_p.h>
49 QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheManager *cacheManager)
51 , m_glyph_cacheManager(cacheManager)
53 , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
54 , m_style(QQuickText::Normal)
55 , m_antialiasingMode(GrayAntialiasing)
56 , m_dirtyGeometry(false)
57 , m_dirtyMaterial(false)
59 m_geometry.setDrawingMode(GL_TRIANGLES);
60 setGeometry(&m_geometry);
61 setPreferredAntialiasingMode(cacheManager->defaultAntialiasingMode());
62 #ifdef QML_RUNTIME_TESTING
63 description = QLatin1String("glyphs");
67 QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
71 m_glyph_cache->release(m_glyphs.glyphIndexes());
72 m_glyph_cache->unregisterGlyphNode(this);
76 void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
79 if (m_material != 0) {
80 m_material->setColor(color);
81 markDirty(DirtyMaterial);
85 void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
87 if (mode == m_antialiasingMode)
89 m_antialiasingMode = mode;
90 m_dirtyMaterial = true;
93 void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs)
95 QRawFont font = glyphs.rawFont();
96 m_position = QPointF(position.x(), position.y() - font.ascent());
99 QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache;
100 m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
101 if (m_glyph_cache != oldCache) {
103 oldCache->unregisterGlyphNode(this);
104 m_glyph_cache->registerGlyphNode(this);
106 m_glyph_cache->populate(glyphs.glyphIndexes());
108 const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
109 const QVector<QPointF> &glyphPositions = m_glyphs.positions();
110 for (int i = 0; i < glyphIndexes.size(); ++i) {
112 g.glyphIndex = glyphIndexes.at(i);
113 g.position = glyphPositions.at(i);
114 m_glyphsToAdd.append(g);
117 m_dirtyGeometry = true;
118 m_dirtyMaterial = true;
121 void QSGDistanceFieldGlyphNode::setStyle(QQuickText::TextStyle style)
123 if (m_style == style)
126 m_dirtyMaterial = true;
129 void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
131 if (m_styleColor == color)
133 m_styleColor = color;
134 m_dirtyMaterial = true;
137 void QSGDistanceFieldGlyphNode::update()
145 void QSGDistanceFieldGlyphNode::updateGeometry()
147 Q_ASSERT(m_glyph_cache);
149 if (m_glyphsToAdd.isEmpty())
152 QSGGeometry *g = geometry();
154 Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
156 int oldVertexCount = g->vertexCount();
157 int oldIndexCount = g->indexCount();
159 QVector<QSGGeometry::TexturedPoint2D> vp;
160 vp.reserve(m_glyphsToAdd.size() * 4);
162 ip.reserve(m_glyphsToAdd.size() * 6);
164 QPointF margins(2, 2);
165 QPointF texMargins = margins / m_glyph_cache->fontScale();
167 const QSGDistanceFieldGlyphCache::Texture *textureToUse = 0;
169 QLinkedList<GlyphInfo>::iterator it = m_glyphsToAdd.begin();
170 while (it != m_glyphsToAdd.end()) {
171 quint32 glyphIndex = it->glyphIndex;
172 QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
178 it = m_glyphsToAdd.erase(it);
182 const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex);
183 if (!texture->textureId) {
188 QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
191 textureToUse = texture;
193 metrics.width += margins.x() * 2;
194 metrics.height += margins.y() * 2;
195 metrics.baselineX -= margins.x();
196 metrics.baselineY += margins.y();
197 c.xMargin -= texMargins.x();
198 c.yMargin -= texMargins.y();
199 c.width += texMargins.x() * 2;
200 c.height += texMargins.y() * 2;
202 const QPointF &glyphPosition = it->position;
203 qreal x = glyphPosition.x() + metrics.baselineX + m_position.x();
204 qreal y = glyphPosition.y() - metrics.baselineY + m_position.y();
206 m_boundingRect |= QRectF(x, y, metrics.width, metrics.height);
209 float cx2 = x + metrics.width;
211 float cy2 = y + metrics.height;
213 float tx1 = c.x + c.xMargin;
214 float tx2 = tx1 + c.width;
215 float ty1 = c.y + c.yMargin;
216 float ty2 = ty1 + c.height;
218 if (m_baseLine.isNull())
219 m_baseLine = glyphPosition;
223 QSGGeometry::TexturedPoint2D v1;
224 v1.set(cx1, cy1, tx1, ty1);
225 QSGGeometry::TexturedPoint2D v2;
226 v2.set(cx2, cy1, tx2, ty1);
227 QSGGeometry::TexturedPoint2D v3;
228 v3.set(cx1, cy2, tx1, ty2);
229 QSGGeometry::TexturedPoint2D v4;
230 v4.set(cx2, cy2, tx2, ty2);
236 int o = i + oldVertexCount;
244 it = m_glyphsToAdd.erase(it);
251 if (oldVertexCount && oldIndexCount) {
252 int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
253 + oldIndexCount * sizeof(quint16);
254 data = qMalloc(byteSize);
255 memcpy(data, g->vertexData(), byteSize);
258 g->allocate(oldVertexCount + vp.size(), oldIndexCount + ip.size());
261 memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
262 memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
263 oldIndexCount * sizeof(quint16));
267 memcpy(g->vertexDataAsTexturedPoint2D() + oldVertexCount, vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
268 memcpy(g->indexDataAsUShort() + oldIndexCount, ip.constData(), ip.size() * sizeof(quint16));
270 setBoundingRect(m_boundingRect);
271 markDirty(DirtyGeometry);
272 m_dirtyGeometry = false;
274 m_material->setTexture(textureToUse);
277 void QSGDistanceFieldGlyphNode::updateMaterial()
281 if (m_style == QQuickText::Normal) {
282 switch (m_antialiasingMode) {
283 case HighQualitySubPixelAntialiasing:
284 m_material = new QSGHiQSubPixelDistanceFieldTextMaterial;
286 case LowQualitySubPixelAntialiasing:
287 m_material = new QSGLoQSubPixelDistanceFieldTextMaterial;
289 case GrayAntialiasing:
291 m_material = new QSGDistanceFieldTextMaterial;
295 QSGDistanceFieldStyledTextMaterial *material;
296 if (m_style == QQuickText::Outline) {
297 material = new QSGDistanceFieldOutlineTextMaterial;
299 QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
300 if (m_style == QQuickText::Raised)
301 sMaterial->setShift(QPointF(0.0, 1.0));
303 sMaterial->setShift(QPointF(0.0, -1.0));
304 material = sMaterial;
306 material->setStyleColor(m_styleColor);
307 m_material = material;
310 m_material->setGlyphCache(m_glyph_cache);
311 m_material->setColor(m_color);
312 setMaterial(m_material);
313 m_dirtyMaterial = false;