Improved performance of large text when parts are outside view.
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>
Mon, 12 Dec 2011 12:02:13 +0000 (13:02 +0100)
committerQt by Nokia <qt-info@nokia.com>
Tue, 13 Dec 2011 10:11:58 +0000 (11:11 +0100)
Avoid generating paths for the parts of the text that are outside
the viewport in the raster paint engine.

Task-number: QTBUG-22687
Change-Id: I06159bc4c1aa82a07606f4b2f0336cb25dfd56d2
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
src/gui/painting/qpaintengine_raster.cpp

index 89a8f8a..60ead45 100644 (file)
@@ -2878,11 +2878,47 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
 }
 
+static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
+                                         glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
+{
+    QFixed clipLeft = QFixed::fromReal(clip.left());
+    QFixed clipRight = QFixed::fromReal(clip.right());
+    QFixed clipTop = QFixed::fromReal(clip.top());
+    QFixed clipBottom = QFixed::fromReal(clip.bottom());
+
+    int first = 0;
+    while (first < numGlyphs) {
+        glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
+        QFixed left = metrics.x + positions[first].x;
+        QFixed top = metrics.y + positions[first].y;
+        QFixed right = left + metrics.width;
+        QFixed bottom = top + metrics.height;
+        if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+            break;
+        ++first;
+    }
+    int last = numGlyphs - 1;
+    while (last > first) {
+        glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
+        QFixed left = metrics.x + positions[last].x;
+        QFixed top = metrics.y + positions[last].y;
+        QFixed right = left + metrics.width;
+        QFixed bottom = top + metrics.height;
+        if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
+            break;
+        --last;
+    }
+    return QPair<int, int>(first, last + 1);
+}
+
 /*!
    \reimp
 */
 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
 {
+    if (textItem->numGlyphs == 0)
+        return;
+
     ensurePen();
     ensureRasterState();
 
@@ -2890,6 +2926,20 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
     if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) {
         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
                          fontEngine);
+    } else if (state()->matrix.type() < QTransform::TxProject) {
+        bool invertible;
+        QTransform invMat = state()->matrix.inverted(&invertible);
+        if (!invertible)
+            return;
+
+        QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+                                                  textItem->fontEngine(), textItem->glyphs,
+                                                  textItem->glyphPositions, textItem->numGlyphs);
+        QStaticTextItem copy = *textItem;
+        copy.glyphs += range.first;
+        copy.glyphPositions += range.first;
+        copy.numGlyphs = range.second - range.first;
+        QPaintEngineEx::drawStaticTextItem(&copy);
     } else {
         QPaintEngineEx::drawStaticTextItem(textItem);
     }
@@ -2901,7 +2951,6 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
 {
     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
-    QRasterPaintEngineState *s = state();
 
 #ifdef QT_DEBUG_DRAW
     Q_D(QRasterPaintEngine);
@@ -2910,25 +2959,51 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
            d->glyphCacheType);
 #endif
 
+    if (ti.glyphs.numGlyphs == 0)
+        return;
     ensurePen();
     ensureRasterState();
 
+    QRasterPaintEngineState *s = state();
+    QTransform matrix = s->matrix;
 
     if (!supportsTransformations(ti.fontEngine)) {
         QVarLengthArray<QFixedPoint> positions;
         QVarLengthArray<glyph_t> glyphs;
 
-        QTransform matrix = s->matrix;
         matrix.translate(p.x(), p.y());
-
         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
 
         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
-        return;
-    }
+    } else if (matrix.type() < QTransform::TxProject) {
+        bool invertible;
+        QTransform invMat = matrix.inverted(&invertible);
+        if (!invertible)
+            return;
+
+        QVarLengthArray<QFixedPoint> positions;
+        QVarLengthArray<glyph_t> glyphs;
+
+        ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
+                                         ti.flags, glyphs, positions);
+        QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
+                                                  ti.fontEngine, glyphs.data(), positions.data(),
+                                                  glyphs.size());
 
+        if (range.first >= range.second)
+            return;
 
-    QPaintEngineEx::drawTextItem(p, ti);
+        QStaticTextItem staticTextItem;
+        staticTextItem.color = s->pen.color();
+        staticTextItem.font = s->font;
+        staticTextItem.setFontEngine(ti.fontEngine);
+        staticTextItem.numGlyphs = range.second - range.first;
+        staticTextItem.glyphs = glyphs.data() + range.first;
+        staticTextItem.glyphPositions = positions.data() + range.first;
+        QPaintEngineEx::drawStaticTextItem(&staticTextItem);
+    } else {
+        QPaintEngineEx::drawTextItem(p, ti);
+    }
 }
 
 /*!