From 41462816074b3309efa31febf224120aa66237df Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Thu, 2 Feb 2012 11:51:45 +1000 Subject: [PATCH] Remove pixmap text caching in QML text element Task-number: QTBUG-24033 Change-Id: Ifa24482b98536300c2f4c643a86517a019de8a84 Reviewed-by: Martin Jones --- src/quick/items/qquicktext.cpp | 342 ++++----------------------------------- src/quick/items/qquicktext_p.h | 1 - src/quick/items/qquicktext_p_p.h | 25 --- 3 files changed, 35 insertions(+), 333 deletions(-) diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 0e1c5a8..f5d1996 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -67,10 +67,6 @@ QT_BEGIN_NAMESPACE -extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled; - -DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) -DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE); const QChar QQuickTextPrivate::elideChar = QChar(0x2026); @@ -80,21 +76,17 @@ QQuickTextPrivate::QQuickTextPrivate() format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap), lineHeight(1), lineHeightMode(QQuickText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX), maximumLineCountValid(false), fontSizeMode(QQuickText::FixedSize), minimumPixelSize(12), - minimumPointSize(12), imageCache(0), texture(0), - imageCacheDirty(false), updateOnComponentComplete(true), - richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), - disableDistanceField(false), internalWidthUpdate(false), + minimumPointSize(12), updateOnComponentComplete(true), + richText(false), styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false), - layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true), - needToUpdateLayout(false), naturalWidth(0), doc(0), elideLayout(0), textLine(0), nodeType(NodeIsNull), + layoutTextElided(false), textHasChanged(true), + needToUpdateLayout(false), naturalWidth(0), doc(0), elideLayout(0), textLine(0), updateType(UpdatePaintNode), nbActiveDownloads(0) #if defined(Q_OS_MAC) , layoutThread(0), paintingThread(0) #endif { - cacheAllTextAsImage = enableImageCache(); - disableDistanceField = qmlDisableDistanceField(); } void QQuickTextPrivate::init() @@ -266,7 +258,6 @@ QQuickTextPrivate::~QQuickTextPrivate() { delete elideLayout; delete textLine; textLine = 0; - delete imageCache; qDeleteAll(imgTags); imgTags.clear(); } @@ -382,8 +373,6 @@ void QQuickTextPrivate::updateSize() return; } - invalidateImageCache(); - QFontMetrics fm(font); if (text.isEmpty()) { qreal fontHeight = fm.height(); @@ -422,8 +411,7 @@ void QQuickTextPrivate::updateSize() QTextOption option; option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign)); option.setWrapMode(QTextOption::WrapMode(wrapMode)); - if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField) - option.setUseDesignMetrics(true); + option.setUseDesignMetrics(true); doc->setDefaultTextOption(option); if (requireImplicitWidth && q->widthValid()) { doc->setTextWidth(-1); @@ -615,8 +603,7 @@ QRect QQuickTextPrivate::setupTextLayout() QTextOption textOption = layout.textOption(); textOption.setAlignment(Qt::Alignment(q->effectiveHAlign())); textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); - if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField) - textOption.setUseDesignMetrics(true); + textOption.setUseDesignMetrics(true); layout.setTextOption(textOption); layout.setFont(font); @@ -947,169 +934,6 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal } /*! - Returns a painted version of the QQuickTextPrivate::layout QTextLayout. - If \a drawStyle is true, the style color overrides all colors in the document. -*/ -QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle) -{ - QSize size = layedOutTextRect.size(); - - //paint text - QPixmap img(size); - if (!size.isEmpty()) { - img.fill(Qt::transparent); -/*#ifdef Q_OS_MAC // Fails on CocoaX64 - bool oldSmooth = qt_applefontsmoothing_enabled; - qt_applefontsmoothing_enabled = false; -#endif*/ - QPainter p(&img); -/*#ifdef Q_OS_MAC // Fails on CocoaX64 - qt_applefontsmoothing_enabled = oldSmooth; -#endif*/ - drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle); - } - return img; -} - -/*! - Paints the QQuickTextPrivate::layout QTextLayout into \a painter at \a pos. If - \a drawStyle is true, the style color overrides all colors in the document. -*/ -void QQuickTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle) -{ - if (drawStyle) - painter->setPen(styleColor); - else - painter->setPen(color); - painter->setFont(font); - layout.draw(painter, pos); - if (!elidePos.isNull()) - painter->drawText(pos + elidePos, elideChar); -} - -/*! - Returns a painted version of the QQuickTextPrivate::doc QTextDocument. - If \a drawStyle is true, the style color overrides all colors in the document. -*/ -QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle) -{ - QSize size = doc->size().toSize(); - - //paint text - QPixmap img(size); - img.fill(Qt::transparent); -/*#ifdef Q_OS_MAC // Fails on CocoaX64 - bool oldSmooth = qt_applefontsmoothing_enabled; - qt_applefontsmoothing_enabled = false; -#endif*/ - QPainter p(&img); -/*#ifdef Q_OS_MAC // Fails on CocoaX64 - qt_applefontsmoothing_enabled = oldSmooth; -#endif*/ - - QAbstractTextDocumentLayout::PaintContext context; - - QTextOption oldOption(doc->defaultTextOption()); - if (drawStyle) { - context.palette.setColor(QPalette::Text, styleColor); - QTextOption colorOption(doc->defaultTextOption()); - colorOption.setFlags(QTextOption::SuppressColors); - doc->setDefaultTextOption(colorOption); - } else { - context.palette.setColor(QPalette::Text, color); - } - doc->documentLayout()->draw(&p, context); - if (drawStyle) - doc->setDefaultTextOption(oldOption); - return img; -} - - -void QQuickTextPrivate::markDirty() -{ - Q_Q(QQuickText); - if (!invalidateImageCache() && q->isComponentComplete()) { - updateType = UpdatePaintNode; - q->update(); - } -} - -/*! - Mark the image cache as dirty. -*/ -bool QQuickTextPrivate::invalidateImageCache() -{ - Q_Q(QQuickText); - - if (richTextAsImage || cacheAllTextAsImage || (disableDistanceField && style != QQuickText::Normal)) { // If actually using the image cache - if (imageCacheDirty) - return true; - - imageCacheDirty = true; - - if (q->isComponentComplete()) - QCoreApplication::postEvent(q, new QEvent(QEvent::User)); - return true; - } - - return false; -} - -/*! - Tests if the image cache is dirty, and repaints it if it is. -*/ -void QQuickTextPrivate::checkImageCache() -{ - Q_Q(QQuickText); - - if (!imageCacheDirty) - return; - - if (text.isEmpty()) { - - delete imageCache; - imageCache = 0; - - } else { - - QPixmap textImage; - QPixmap styledImage; - - if (richText) { - textImage = textDocumentImage(false); - if (style != QQuickText::Normal) - styledImage = textDocumentImage(true); //### should use styleColor - } else { - textImage = textLayoutImage(false); - if (style != QQuickText::Normal) - styledImage = textLayoutImage(true); //### should use styleColor - } - - delete imageCache; - switch (style) { - case QQuickText::Outline: - imageCache = new QPixmap(drawOutline(textImage, styledImage)); - break; - case QQuickText::Sunken: - imageCache = new QPixmap(drawOutline(textImage, styledImage, -1)); - break; - case QQuickText::Raised: - imageCache = new QPixmap(drawOutline(textImage, styledImage, 1)); - break; - default: - imageCache = new QPixmap(textImage); - break; - } - - } - - imageCacheDirty = false; - textureImageCacheDirty = true; - updateType = UpdatePaintNode; - q->update(); -} - -/*! Ensures the QQuickTextPrivate::doc variable is set to a valid text document */ void QQuickTextPrivate::ensureDoc() @@ -1124,51 +948,6 @@ void QQuickTextPrivate::ensureDoc() } /*! - Draw \a styleSource as an outline around \a source and return the new image. -*/ -QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource) -{ - QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2); - img.fill(Qt::transparent); - - QPainter ppm(&img); - - QPoint pos(0, 0); - pos += QPoint(-1, 0); - ppm.drawPixmap(pos, styleSource); - pos += QPoint(2, 0); - ppm.drawPixmap(pos, styleSource); - pos += QPoint(-1, -1); - ppm.drawPixmap(pos, styleSource); - pos += QPoint(0, 2); - ppm.drawPixmap(pos, styleSource); - - pos += QPoint(0, -1); - ppm.drawPixmap(pos, source); - ppm.end(); - - return img; -} - -/*! - Draw \a styleSource below \a source at \a yOffset and return the new image. -*/ -QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset) -{ - QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2); - img.fill(Qt::transparent); - - QPainter ppm(&img); - - ppm.drawPixmap(QPoint(0, yOffset), styleSource); - ppm.drawPixmap(0, 0, source); - - ppm.end(); - - return img; -} - -/*! \qmlclass Text QQuickText \inqmlmodule QtQuick 2 \ingroup qml-basic-visual-elements @@ -1448,7 +1227,6 @@ void QQuickText::setText(const QString &n) d->ensureDoc(); d->doc->setText(n); d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); - d->richTextAsImage = enableImageCache(); } else { d->rightToLeftText = d->text.isRightToLeft(); } @@ -1495,7 +1273,10 @@ void QQuickText::setColor(const QColor &color) return; d->color = color; - d->markDirty(); + if (isComponentComplete()) { + d->updateType = QQuickTextPrivate::UpdatePaintNode; + update(); + } emit colorChanged(d->color); } /*! @@ -1534,13 +1315,11 @@ void QQuickText::setStyle(QQuickText::TextStyle style) if (d->style == style) return; - // changing to/from Normal requires the boundingRect() to change - if (isComponentComplete() && (d->style == Normal || style == Normal)) { + d->style = style; + if (isComponentComplete()) { d->updateType = QQuickTextPrivate::UpdatePaintNode; update(); } - d->style = style; - d->markDirty(); emit styleChanged(d->style); } @@ -1572,7 +1351,10 @@ void QQuickText::setStyleColor(const QColor &color) return; d->styleColor = color; - d->markDirty(); + if (isComponentComplete()) { + d->updateType = QQuickTextPrivate::UpdatePaintNode; + update(); + } emit styleColorChanged(d->styleColor); } @@ -1888,7 +1670,6 @@ void QQuickText::setTextFormat(TextFormat format) d->ensureDoc(); d->doc->setText(d->text); d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); - d->richTextAsImage = enableImageCache(); } else { d->rightToLeftText = d->text.isRightToLeft(); } @@ -2095,84 +1876,32 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data d->updateLayout(); #endif - // XXX todo - some styled text can be done by the QQuickTextNode - if (d->richTextAsImage || d->cacheAllTextAsImage || (d->disableDistanceField && d->style != Normal)) { - bool wasDirty = d->textureImageCacheDirty; - d->textureImageCacheDirty = false; - - if (!d->imageCache || d->imageCache->isNull()) { - delete oldNode; - return 0; - } - - QSGImageNode *node = 0; - if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsTexture) { - delete oldNode; - node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode(); - d->texture = new QSGPlainTexture(); - wasDirty = true; - d->nodeType = QQuickTextPrivate::NodeIsTexture; - } else { - node = static_cast(oldNode); - Q_ASSERT(d->texture); - } - - if (wasDirty) { - qobject_cast(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->setSourceRect(QRectF(0, 0, 1, 1)); - node->setHorizontalWrapMode(QSGTexture::ClampToEdge); - node->setVerticalWrapMode(QSGTexture::ClampToEdge); - node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that.. - node->update(); - - return node; - + QQuickTextNode *node = 0; + if (!oldNode) { + node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this); } else { - QQuickTextNode *node = 0; - if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) { - delete oldNode; - node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this); - d->nodeType = QQuickTextPrivate::NodeIsText; - } else { - node = static_cast(oldNode); - } + node = static_cast(oldNode); + } - node->deleteContent(); - node->setMatrix(QMatrix4x4()); + node->deleteContent(); + node->setMatrix(QMatrix4x4()); - if (d->richText) { - d->ensureDoc(); - node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor); - - } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) { - node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor); - if (d->elideLayout) - node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, d->color, d->style, d->styleColor); - } + if (d->richText) { + d->ensureDoc(); + node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor); - foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) { - QDeclarativePixmap *pix = img->pix; - if (pix && pix->isReady()) - node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image()); - } - return node; + } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) { + node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor); + if (d->elideLayout) + node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, d->color, d->style, d->styleColor); } -} -bool QQuickText::event(QEvent *e) -{ - Q_D(QQuickText); - if (e->type() == QEvent::User) { - d->checkImageCache(); - return true; - } else { - return QQuickImplicitSizeItem::event(e); + foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) { + QDeclarativePixmap *pix = img->pix; + if (pix && pix->isReady()) + node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image()); } + return node; } void QQuickText::updatePolish() @@ -2382,7 +2111,6 @@ void QQuickText::componentComplete() d->ensureDoc(); d->doc->setText(d->text); d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); - d->richTextAsImage = enableImageCache(); } else { d->rightToLeftText = d->text.isRightToLeft(); } diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index 0630fe4..74339e3 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -225,7 +225,6 @@ protected: virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual bool event(QEvent *); void updatePolish(); diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 7585026..db84754 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -66,7 +66,6 @@ QT_BEGIN_NAMESPACE class QTextLayout; class QQuickTextDocumentWithImageResources; -class QSGPlainTexture; class Q_AUTOTEST_EXPORT QQuickTextPrivate : public QQuickImplicitSizeItemPrivate { @@ -110,28 +109,17 @@ public: static const QChar elideChar; - void markDirty(); - bool invalidateImageCache(); - void checkImageCache(); - QPixmap *imageCache; - QSGTexture *texture; - - bool imageCacheDirty:1; bool updateOnComponentComplete:1; bool updateLayoutOnPolish:1; bool richText:1; bool styledText:1; bool singleline:1; - bool cacheAllTextAsImage:1; - bool disableDistanceField:1; bool internalWidthUpdate:1; bool requireImplicitWidth:1; bool truncated:1; bool hAlignImplicit:1; bool rightToLeftText:1; bool layoutTextElided:1; - bool richTextAsImage:1; - bool textureImageCacheDirty:1; bool textHasChanged:1; bool needToUpdateLayout:1; @@ -141,33 +129,20 @@ public: virtual qreal getImplicitWidth() const; void ensureDoc(); - QPixmap textDocumentImage(bool drawStyle); QQuickTextDocumentWithImageResources *doc; QRect setupTextLayout(); void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0); - QPixmap textLayoutImage(bool drawStyle); - void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle); bool isLinkActivatedConnected(); QString anchorAt(const QPointF &pos); QTextLayout layout; QTextLayout *elideLayout; QQuickTextLine *textLine; - static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource); - static QPixmap drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset); - static inline QQuickTextPrivate *get(QQuickText *t) { return t->d_func(); } - enum NodeType { - NodeIsNull, - NodeIsTexture, - NodeIsText - }; - NodeType nodeType; - enum UpdateType { UpdateNone, UpdatePreprocess, -- 2.7.4