Merge multiple lines of text into a single geometry node
authorGunnar Sletta <gunnar.sletta@nokia.com>
Thu, 23 Jun 2011 08:40:39 +0000 (10:40 +0200)
committerGunnar Sletta <gunnar.sletta@nokia.com>
Thu, 23 Jun 2011 08:40:39 +0000 (10:40 +0200)
Long term, we might want to have this kind of logic in the QSGGeometry
class through a grow() function or in the QSGRenderer, but we
only have this one usecase where it actually makes sense right
now, so I'm keeping it local.

Change-Id: Ibbb0dd4a6e4b587154e26ffc2a34375fbb4a571d

src/declarative/items/qsgtextnode.cpp
src/declarative/items/qsgtextnode_p.h
src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp

index 6909d8c..b8dee68 100644 (file)
@@ -152,18 +152,25 @@ void QSGTextNode::addTextDecorations(const QPointF &position, const QRawFont &fo
 }
 
 QSGGlyphNode *QSGTextNode::addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color,
-                                           QSGText::TextStyle style, const QColor &styleColor)
+                                           QSGText::TextStyle style, const QColor &styleColor, QSGGlyphNode *prevNode)
 {
-    QSGGlyphNode *node = m_context->createGlyphNode();
-    if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
-        QSGDistanceFieldGlyphNode *dfNode = static_cast<QSGDistanceFieldGlyphNode *>(node);
-        dfNode->setStyle(style);
-        dfNode->setStyleColor(styleColor);
-    }
+    QSGGlyphNode *node = prevNode;
+
+    if (!node)
+        node = m_context->createGlyphNode();
+
     node->setGlyphs(position, glyphs);
-    node->setColor(color);
 
-    appendChildNode(node);
+    if (node != prevNode) {
+        if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+            QSGDistanceFieldGlyphNode *dfNode = static_cast<QSGDistanceFieldGlyphNode *>(node);
+            dfNode->setStyle(style);
+            dfNode->setStyleColor(styleColor);
+        }
+        node->setColor(color);
+        appendChildNode(node);
+    }
+
 
     if (glyphs.overline() || glyphs.strikeOut() || glyphs.underline()) {
         QPointF baseLine = node->baseLine();
@@ -193,10 +200,13 @@ void QSGTextNode::addTextLayout(const QPointF &position, QTextLayout *textLayout
                                 QSGText::TextStyle style, const QColor &styleColor)
 {
     QList<QGlyphRun> glyphsList(textLayout->glyphRuns());
+
+    QSGGlyphNode *prevNode = 0;
+
     for (int i=0; i<glyphsList.size(); ++i) {
         QGlyphRun glyphs = glyphsList.at(i);
         QRawFont font = glyphs.rawFont();
-        addGlyphs(position + QPointF(0, font.ascent()), glyphs, color, style, styleColor);
+        prevNode = addGlyphs(position + QPointF(0, font.ascent()), glyphs, color, style, styleColor, prevNode);
     }
 }
 
index 7a49f51..e442b4c 100644 (file)
@@ -73,7 +73,8 @@ private:
     void addTextBlock(const QPointF &position, QTextDocument *textDocument, const QTextBlock &block,
                       const QColor &overrideColor, QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
     QSGGlyphNode *addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color,
-                                  QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor());
+                                  QSGText::TextStyle style = QSGText::Normal, const QColor &styleColor = QColor(),
+                            QSGGlyphNode *node = 0);
     void addTextDecorations(const QPointF &position, const QRawFont &font, const QColor &color,
                             qreal width, bool hasOverline, bool hasStrikeOut, bool hasUnderline);
     QSGContext *m_context;
index d826f7f..4686067 100644 (file)
@@ -124,9 +124,32 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
     m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
 
     Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
-    g->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
-    QVector4D *vp = (QVector4D *)g->vertexData();
-    ushort *ip = g->indexDataAsUShort();
+
+    int oldVertexCount = g->vertexCount();
+    int oldIndexCount = g->indexCount();
+
+    // We could potentially move the realloc part into the QSGGeometry object as a
+    // grow() function...
+
+    void *data = 0;
+    if (oldVertexCount && oldIndexCount) {
+        int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
+                     + oldIndexCount * sizeof(quint16);
+        data = qMalloc(byteSize);
+        memcpy(data, g->vertexData(), byteSize);
+    }
+
+    g->allocate(oldVertexCount + glyphIndexes.size() * 4, oldIndexCount + glyphIndexes.size() * 6);
+
+    if (data) {
+        memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
+        memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
+               oldIndexCount * sizeof(quint16));
+        qFree(data);
+    }
+
+    QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D() + oldVertexCount;
+    ushort *ip = g->indexDataAsUShort() + oldIndexCount;
 
     QPointF margins(2, 2);
     QPointF texMargins = margins / m_glyph_cache->fontScale();
@@ -167,12 +190,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
             m_baseLine = glyphPosition;
 
         int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
-        vp[4 * vi + 0] = QVector4D(cx1, cy1, tx1, ty1);
-        vp[4 * vi + 1] = QVector4D(cx2, cy1, tx2, ty1);
-        vp[4 * vi + 2] = QVector4D(cx1, cy2, tx1, ty2);
-        vp[4 * vi + 3] = QVector4D(cx2, cy2, tx2, ty2);
+        vp[4 * vi + 0].set(cx1, cy1, tx1, ty1);
+        vp[4 * vi + 1].set(cx2, cy1, tx2, ty1);
+        vp[4 * vi + 2].set(cx1, cy2, tx1, ty2);
+        vp[4 * vi + 3].set(cx2, cy2, tx2, ty2);
 
-        int o = i * 4;
+        int o = i * 4 + oldVertexCount;
         ip[6 * i + 0] = o + 0;
         ip[6 * i + 1] = o + 2;
         ip[6 * i + 2] = o + 3;
@@ -181,6 +204,25 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
         ip[6 * i + 5] = o + 0;
     }
 
+//    printf("Vertices:\n");
+//    for (int v=0; v<g->vertexCount(); ++v) {
+//        QSGGeometry::TexturedPoint2D *t = g->vertexDataAsTexturedPoint2D() + v;
+//        printf(" - %d -- %f %f  --  %.3f %.3f\n", v, t->x, t->y, t->tx, t->ty);
+//    }
+
+//    printf("Indices:\n");
+//    for (int i=0; i<g->indexCount();) {
+
+//        printf(" - %[ ", i);
+//        printf("%d, ", g->indexDataAsUShort()[i++]);
+//        printf("%d, ", g->indexDataAsUShort()[i++]);
+//        printf("%d, ", g->indexDataAsUShort()[i++]);
+//        printf("%d, ", g->indexDataAsUShort()[i++]);
+//        printf("%d, ", g->indexDataAsUShort()[i++]);
+//        printf("%d",   g->indexDataAsUShort()[i++]);
+//        printf(" ]\n");
+//    }
+
     setBoundingRect(boundingRect);
     markDirty(DirtyGeometry);
 }