Small Text creation performance improvements.
authorMartin Jones <martin.jones@nokia.com>
Tue, 20 Dec 2011 05:31:13 +0000 (15:31 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 20 Dec 2011 06:33:37 +0000 (07:33 +0100)
Change-Id: Ie92129887730d3738e14116cf22e1c30b836a415
Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
Reviewed-by: Martin Jones <martin.jones@nokia.com>

src/quick/items/qquicktext.cpp
src/quick/items/qquicktext_p_p.h
tests/auto/qtquick2/qquicktext/tst_qquicktext.cpp

index e73fa9f..2a6be05 100644 (file)
@@ -78,9 +78,10 @@ QQuickTextPrivate::QQuickTextPrivate()
   format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap), lineHeight(1),
   lineHeightMode(QQuickText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
   maximumLineCountValid(false),
-  texture(0),
+  imageCache(0), texture(0),
   imageCacheDirty(false), updateOnComponentComplete(true),
-  richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
+  richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true),
+  disableDistanceField(false), internalWidthUpdate(false),
   requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
   layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true),
   naturalWidth(0), doc(0), elipsisLayout(0), textLine(0), nodeType(NodeIsNull)
@@ -91,6 +92,7 @@ QQuickTextPrivate::QQuickTextPrivate()
 
 {
     cacheAllTextAsImage = enableImageCache();
+    disableDistanceField = qmlDisableDistanceField();
 }
 
 void QQuickTextPrivate::init()
@@ -188,6 +190,7 @@ QQuickTextPrivate::~QQuickTextPrivate()
 {
     delete elipsisLayout;
     delete textLine; textLine = 0;
+    delete imageCache;
 }
 
 qreal QQuickTextPrivate::getImplicitWidth() const
@@ -217,9 +220,11 @@ void QQuickTextPrivate::updateLayout()
             delete elipsisLayout;
             elipsisLayout = 0;
         }
-        layout.clearLayout();
         layout.setFont(font);
-        if (!styledText) {
+        if (text.isEmpty()) {
+            if (!layout.text().isEmpty())
+                layout.setText(text);
+        } else if (!styledText) {
             QString tmp = text;
             tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
             singleline = !tmp.contains(QChar::LineSeparator);
@@ -281,8 +286,9 @@ void QQuickTextPrivate::updateSize()
 
     QFontMetrics fm(font);
     if (text.isEmpty()) {
-        q->setImplicitSize(0, fm.height());
-        paintedSize = QSize(0, fm.height());
+        qreal fontHeight = fm.height();
+        q->setImplicitSize(0, fontHeight);
+        paintedSize = QSize(0, fontHeight);
         emit q->paintedSizeChanged();
         q->update();
         return;
@@ -315,7 +321,7 @@ void QQuickTextPrivate::updateSize()
         QTextOption option;
         option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
         option.setWrapMode(QTextOption::WrapMode(wrapMode));
-        if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
+        if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
             option.setUseDesignMetrics(true);
         doc->setDefaultTextOption(option);
         if (requireImplicitWidth && q->widthValid()) {
@@ -451,9 +457,9 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
 
 #if defined(Q_OS_MAC)
     if (QThread::currentThread() != paintingThread) {
-#endif
         if (!line.lineNumber())
             linesRects.clear();
+#endif
 
         if (!textLine)
             textLine = new QQuickTextLine;
@@ -471,10 +477,11 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height,
 
         emit q->lineLaidOut(textLine);
 
-        linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
         height += textLine->height();
 
 #if defined(Q_OS_MAC)
+        linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
+
     } else {
         if (line.lineNumber() < linesRects.count()) {
             QRectF r = linesRects.at(line.lineNumber());
@@ -508,7 +515,7 @@ QRect QQuickTextPrivate::setupTextLayout()
     QTextOption textOption = layout.textOption();
     textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
     textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
-    if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
+    if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
         textOption.setUseDesignMetrics(true);
     layout.setTextOption(textOption);
 
@@ -731,23 +738,33 @@ QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle)
     return img;
 }
 
+
+void QQuickTextPrivate::markDirty()
+{
+    Q_Q(QQuickText);
+    if (!invalidateImageCache() && q->isComponentComplete())
+       q->update();
+}
+
 /*!
     Mark the image cache as dirty.
 */
-void QQuickTextPrivate::invalidateImageCache()
+bool QQuickTextPrivate::invalidateImageCache()
 {
     Q_Q(QQuickText);
 
-    if (richTextAsImage || cacheAllTextAsImage || (qmlDisableDistanceField() && style != QQuickText::Normal)) { // If actually using the image cache
+    if (richTextAsImage || cacheAllTextAsImage || (disableDistanceField && style != QQuickText::Normal)) { // If actually using the image cache
         if (imageCacheDirty)
-            return;
+            return true;
 
         imageCacheDirty = true;
 
         if (q->isComponentComplete())
             QCoreApplication::postEvent(q, new QEvent(QEvent::User));
-    } else if (q->isComponentComplete())
-        q->update();
+        return true;
+    }
+
+    return false;
 }
 
 /*!
@@ -762,7 +779,8 @@ void QQuickTextPrivate::checkImageCache()
 
     if (text.isEmpty()) {
 
-        imageCache = QPixmap();
+        delete imageCache;
+        imageCache = 0;
 
     } else {
 
@@ -779,18 +797,19 @@ void QQuickTextPrivate::checkImageCache()
                 styledImage = textLayoutImage(true); //### should use styleColor
         }
 
+        delete imageCache;
         switch (style) {
         case QQuickText::Outline:
-            imageCache = drawOutline(textImage, styledImage);
+            imageCache = new QPixmap(drawOutline(textImage, styledImage));
             break;
         case QQuickText::Sunken:
-            imageCache = drawOutline(textImage, styledImage, -1);
+            imageCache = new QPixmap(drawOutline(textImage, styledImage, -1));
             break;
         case QQuickText::Raised:
-            imageCache = drawOutline(textImage, styledImage, 1);
+            imageCache = new QPixmap(drawOutline(textImage, styledImage, 1));
             break;
         default:
-            imageCache = textImage;
+            imageCache = new QPixmap(textImage);
             break;
         }
 
@@ -1183,7 +1202,7 @@ void QQuickText::setColor(const QColor &color)
         return;
 
     d->color = color;
-    d->invalidateImageCache();
+    d->markDirty();
     emit colorChanged(d->color);
 }
 /*!
@@ -1226,7 +1245,7 @@ void QQuickText::setStyle(QQuickText::TextStyle style)
     if (isComponentComplete() && (d->style == Normal || style == Normal))
         update();
     d->style = style;
-    d->invalidateImageCache();
+    d->markDirty();
     emit styleChanged(d->style);
 }
 
@@ -1258,7 +1277,7 @@ void QQuickText::setStyleColor(const QColor &color)
         return;
 
     d->styleColor = color;
-    d->invalidateImageCache();
+    d->markDirty();
     emit styleColorChanged(d->styleColor);
 }
 
@@ -1653,6 +1672,11 @@ QRectF QQuickText::boundingRect() const
 void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
 {
     Q_D(QQuickText);
+    if (d->text.isEmpty()) {
+        QQuickItem::geometryChanged(newGeometry, oldGeometry);
+        return;
+    }
+
     bool widthChanged = newGeometry.width() != oldGeometry.width();
     bool heightChanged = newGeometry.height() != oldGeometry.height();
     bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
@@ -1714,11 +1738,11 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 #endif
 
     // XXX todo - some styled text can be done by the QQuickTextNode
-    if (d->richTextAsImage || d->cacheAllTextAsImage || (qmlDisableDistanceField() && d->style != Normal)) {
+    if (d->richTextAsImage || d->cacheAllTextAsImage || (d->disableDistanceField && d->style != Normal)) {
         bool wasDirty = d->textureImageCacheDirty;
         d->textureImageCacheDirty = false;
 
-        if (d->imageCache.isNull()) {
+        if (!d->imageCache || d->imageCache->isNull()) {
             delete oldNode;
             return 0;
         }
@@ -1736,12 +1760,12 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
         }
 
         if (wasDirty) {
-            qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache.toImage());
+            qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache->toImage());
             node->setTexture(0);
             node->setTexture(d->texture);
         }
 
-        node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache.width(), d->imageCache.height()));
+        node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache->width(), d->imageCache->height()));
         node->setSourceRect(QRectF(0, 0, 1, 1));
         node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
         node->setVerticalWrapMode(QSGTexture::ClampToEdge);
index 756acbf..43ca31d 100644 (file)
@@ -103,9 +103,10 @@ public:
 
     static QString elideChar;
 
-    void invalidateImageCache();
+    void markDirty();
+    bool invalidateImageCache();
     void checkImageCache();
-    QPixmap imageCache;
+    QPixmap *imageCache;
     QSGTexture *texture;
 
     bool imageCacheDirty:1;
@@ -114,6 +115,7 @@ public:
     bool styledText:1;
     bool singleline:1;
     bool cacheAllTextAsImage:1;
+    bool disableDistanceField:1;
     bool internalWidthUpdate:1;
     bool requireImplicitWidth:1;
     bool truncated:1;
@@ -141,7 +143,6 @@ public:
     QString anchorAt(const QPointF &pos);
     QTextLayout layout;
     QTextLayout *elipsisLayout;
-    QList<QRectF> linesRects;
     QQuickTextLine *textLine;
 
     static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource);
@@ -159,6 +160,7 @@ public:
     NodeType nodeType;
 
 #if defined(Q_OS_MAC)
+    QList<QRectF> linesRects;
     QThread *layoutThread;
     QThread *paintingThread;
 #endif
index 09e7b9c..88a8b6d 100644 (file)
@@ -1443,10 +1443,12 @@ void tst_qquicktext::lineLaidOut()
     QTextDocument *doc = textPrivate->textDocument();
     QVERIFY(doc == 0);
 
+#if defined(Q_OS_MAC)
     QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
+#endif
 
-    for (int i = 0; i < textPrivate->linesRects.count(); ++i) {
-        QRectF r = textPrivate->linesRects.at(i);
+    for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
+        QRectF r = textPrivate->layout.lineAt(i).rect();
         QVERIFY(r.width() == i * 15);
         if (i >= 30)
             QVERIFY(r.x() == r.width() + 30);