From bab2eaf3da299c471dd898c89cf356984b077412 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 16 Jan 2012 16:40:13 +1000 Subject: Don't load embedded images from the current working directory. Override QTextImageHandler's image loading as it will attempt to resolve relative paths and load the image itself if the document returns an invalid image from loadResource, which we don't want as it bypasses the pixmap cache and resolves against the application and current working directory instead of the Text items context. Change-Id: Ia1d3633036f96d902e1ac03dae5d5b203fba7ff1 Reviewed-by: Martin Jones --- src/quick/items/qquicktext.cpp | 120 ++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 24 deletions(-) (limited to 'src/quick/items/qquicktext.cpp') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index e8eb555dde..fb9022072a 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -107,6 +107,7 @@ QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuic : QTextDocument(parent), outstanding(0) { setUndoRedoEnabled(false); + documentLayout()->registerHandler(QTextFormat::ImageObject, this); } QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources() @@ -121,27 +122,8 @@ QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl QUrl url = context->resolvedUrl(name); if (type == QTextDocument::ImageResource) { - QHash::Iterator iter = m_resources.find(url); - - if (iter == m_resources.end()) { - QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url); - iter = m_resources.insert(url, p); - - if (p->isLoading()) { - p->connectFinished(this, SLOT(requestFinished())); - outstanding++; - } - } - - QDeclarativePixmap *p = *iter; - if (p->isReady()) { - return p->image(); - } else if (p->isError()) { - if (!errors.contains(url)) { - errors.insert(url); - qmlInfo(parent()) << p->error(); - } - } + QDeclarativePixmap *p = loadPixmap(context, url); + return p->image(); } return QTextDocument::loadResource(type,url); // The *resolved* URL @@ -152,9 +134,7 @@ void QQuickTextDocumentWithImageResources::requestFinished() outstanding--; if (outstanding == 0) { markContentsDirty(0, characterCount()); - - if (QQuickText *item = qobject_cast(parent())) - QQuickTextPrivate::get(item)->updateLayout(); + emit imagesLoaded(); } } @@ -165,6 +145,91 @@ void QQuickTextDocumentWithImageResources::clear() QTextDocument::clear(); } + +QSizeF QQuickTextDocumentWithImageResources::intrinsicSize( + QTextDocument *, int, const QTextFormat &format) +{ + if (format.isImageFormat()) { + QTextImageFormat imageFormat = format.toImageFormat(); + + const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth); + const int width = qRound(imageFormat.width()); + const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight); + const int height = qRound(imageFormat.height()); + + QSizeF size(width, height); + if (!hasWidth || !hasHeight) { + QDeclarativeContext *context = qmlContext(parent()); + QUrl url = context->resolvedUrl(QUrl(imageFormat.name())); + + QDeclarativePixmap *p = loadPixmap(context, url); + if (!p->isReady()) { + if (!hasWidth) + size.setWidth(16); + if (!hasHeight) + size.setHeight(16); + return size; + } + QSize implicitSize = p->implicitSize(); + + if (!hasWidth) { + if (!hasHeight) + size.setWidth(implicitSize.width()); + else + size.setWidth(qRound(height * (implicitSize.width() / (qreal) implicitSize.height()))); + } + if (!hasHeight) { + if (!hasWidth) + size.setHeight(implicitSize.height()); + else + size.setHeight(qRound(width * (implicitSize.height() / (qreal) implicitSize.width()))); + } + } + return size; + } + return QSizeF(); +} + +void QQuickTextDocumentWithImageResources::drawObject( + QPainter *, const QRectF &, QTextDocument *, int, const QTextFormat &) +{ +} + +QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format) +{ + QDeclarativeContext *context = qmlContext(parent()); + QUrl url = context->resolvedUrl(QUrl(format.name())); + + QDeclarativePixmap *p = loadPixmap(context, url); + return p->image(); +} + +QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap( + QDeclarativeContext *context, const QUrl &url) +{ + + QHash::Iterator iter = m_resources.find(url); + + if (iter == m_resources.end()) { + QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url); + iter = m_resources.insert(url, p); + + if (p->isLoading()) { + p->connectFinished(this, SLOT(requestFinished())); + outstanding++; + } + } + + QDeclarativePixmap *p = *iter; + if (p->isError()) { + if (!errors.contains(url)) { + errors.insert(url); + qmlInfo(parent()) << p->error(); + } + } + return p; +} + void QQuickTextDocumentWithImageResources::clearResources() { foreach (QDeclarativePixmap *pixmap, m_resources) @@ -206,6 +271,12 @@ qreal QQuickTextPrivate::getImplicitWidth() const return implicitWidth; } +void QQuickText::q_imagesLoaded() +{ + Q_D(QQuickText); + d->updateLayout(); +} + void QQuickTextPrivate::updateLayout() { Q_Q(QQuickText); @@ -830,6 +901,7 @@ void QQuickTextPrivate::ensureDoc() Q_Q(QQuickText); doc = new QQuickTextDocumentWithImageResources(q); doc->setDocumentMargin(0); + FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded())); } } -- cgit v1.2.3 From de0a5f28bc565c971989e68a19c8621a2309ed91 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 17 Jan 2012 10:42:26 +1000 Subject: Add a baseUrl property to Text and TextEdit. Specifies the base URL which embedded links in rich text are resolved against. By default this is the URL of the item. Task-number: QTBUG-23655 Change-Id: Ib51b8503a18d9ac4e1801c77b77b3595d8f4912a Reviewed-by: Martin Jones --- src/quick/items/qquicktext.cpp | 55 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'src/quick/items/qquicktext.cpp') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index fb9022072a..c5999435eb 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -119,7 +119,7 @@ QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources() QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name) { QDeclarativeContext *context = qmlContext(parent()); - QUrl url = context->resolvedUrl(name); + QUrl url = m_baseUrl.resolved(name); if (type == QTextDocument::ImageResource) { QDeclarativePixmap *p = loadPixmap(context, url); @@ -160,7 +160,7 @@ QSizeF QQuickTextDocumentWithImageResources::intrinsicSize( QSizeF size(width, height); if (!hasWidth || !hasHeight) { QDeclarativeContext *context = qmlContext(parent()); - QUrl url = context->resolvedUrl(QUrl(imageFormat.name())); + QUrl url = m_baseUrl.resolved(QUrl(imageFormat.name())); QDeclarativePixmap *p = loadPixmap(context, url); if (!p->isReady()) { @@ -198,12 +198,21 @@ void QQuickTextDocumentWithImageResources::drawObject( QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format) { QDeclarativeContext *context = qmlContext(parent()); - QUrl url = context->resolvedUrl(QUrl(format.name())); + QUrl url = m_baseUrl.resolved(QUrl(format.name())); QDeclarativePixmap *p = loadPixmap(context, url); return p->image(); } +void QQuickTextDocumentWithImageResources::setBaseUrl(const QUrl &url, bool clear) +{ + m_baseUrl = url; + if (clear) { + clearResources(); + markContentsDirty(0, characterCount()); + } +} + QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap( QDeclarativeContext *context, const QUrl &url) { @@ -901,6 +910,7 @@ void QQuickTextPrivate::ensureDoc() Q_Q(QQuickText); doc = new QQuickTextDocumentWithImageResources(q); doc->setDocumentMargin(0); + doc->setBaseUrl(q->baseUrl()); FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded())); } } @@ -1717,6 +1727,45 @@ void QQuickText::setElideMode(QQuickText::TextElideMode mode) emit elideModeChanged(d->elideMode); } +/*! + \qmlproperty url QtQuick2::Text::baseUrl + + This property specifies a base URL which is used to resolve relative URLs + within the text. + + By default is the url of the Text element. +*/ + +QUrl QQuickText::baseUrl() const +{ + Q_D(const QQuickText); + if (d->baseUrl.isEmpty()) { + if (QDeclarativeContext *context = qmlContext(this)) + const_cast(d)->baseUrl = context->baseUrl(); + } + return d->baseUrl; +} + +void QQuickText::setBaseUrl(const QUrl &url) +{ + Q_D(QQuickText); + if (baseUrl() != url) { + d->baseUrl = url; + + if (d->doc) + d->doc->setBaseUrl(url); + emit baseUrlChanged(); + } +} + +void QQuickText::resetBaseUrl() +{ + if (QDeclarativeContext *context = qmlContext(this)) + setBaseUrl(context->baseUrl()); + else + setBaseUrl(QUrl()); +} + /*! \internal */ QRectF QQuickText::boundingRect() const { -- cgit v1.2.3 From e6b224aa2872d7d1030fa98bd30603e16f8f9604 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Fri, 20 Jan 2012 14:04:27 +1000 Subject: Update obsolete contact address. Replace Nokia contact email address with Qt Project website. Change-Id: I6a730abc0c396fb545a48b2d6938abedac2e3f1c Reviewed-by: Rohan McGovern Reviewed-by: Alan Alpert --- src/quick/items/qquicktext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/quick/items/qquicktext.cpp') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index c5999435eb..d7b069a1fc 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: http://www.qt-project.org/ ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** -- cgit v1.2.3 From 47a5c708bf4e555cb8febef583f32c99f7d8ea1e Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 24 Nov 2011 13:48:19 +0100 Subject: Add support for shared glyph cache Use a shared graphics cache to back the distance fields if it is available. Change-Id: Id5e6e7a28e38e349d787e66016b2d0faebc791d7 Reviewed-by: Jiang Jiang --- src/quick/items/qquicktext.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'src/quick/items/qquicktext.cpp') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index d7b069a1fc..82232ab0ea 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -85,7 +85,7 @@ QQuickTextPrivate::QQuickTextPrivate() 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) + naturalWidth(0), doc(0), elipsisLayout(0), textLine(0), nodeType(NodeIsNull), updateType(UpdatePaintNode) #if defined(Q_OS_MAC) , layoutThread(0), paintingThread(0) @@ -371,6 +371,7 @@ void QQuickTextPrivate::updateSize() q->setImplicitSize(0, fontHeight); paintedSize = QSize(0, fontHeight); emit q->paintedSizeChanged(); + updateType = UpdatePaintNode; q->update(); return; } @@ -445,6 +446,7 @@ void QQuickTextPrivate::updateSize() paintedSize = size; emit q->paintedSizeChanged(); } + updateType = UpdatePaintNode; q->update(); } @@ -898,6 +900,7 @@ void QQuickTextPrivate::checkImageCache() imageCacheDirty = false; textureImageCacheDirty = true; + updateType = UpdatePaintNode; q->update(); } @@ -1325,8 +1328,10 @@ void QQuickText::setStyle(QQuickText::TextStyle style) return; // changing to/from Normal requires the boundingRect() to change - if (isComponentComplete() && (d->style == Normal || style == Normal)) + if (isComponentComplete() && (d->style == Normal || style == Normal)) { + d->updateType = QQuickTextPrivate::UpdatePaintNode; update(); + } d->style = style; d->markDirty(); emit styleChanged(d->style); @@ -1842,6 +1847,14 @@ geomChangeDone: QQuickItem::geometryChanged(newGeometry, oldGeometry); } +void QQuickText::triggerPreprocess() +{ + Q_D(QQuickText); + if (d->updateType == QQuickTextPrivate::UpdateNone) + d->updateType = QQuickTextPrivate::UpdatePreprocess; + update(); +} + QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) { Q_UNUSED(data); @@ -1852,6 +1865,14 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data return 0; } + if (!d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != 0) { + // Update done in preprocess() in the nodes + d->updateType = QQuickTextPrivate::UpdateNone; + return oldNode; + } + + d->updateType = QQuickTextPrivate::UpdateNone; + QRectF bounds = boundingRect(); // We need to make sure the layout is done in the current thread @@ -1902,7 +1923,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data QQuickTextNode *node = 0; if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) { delete oldNode; - node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext()); + node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this); d->nodeType = QQuickTextPrivate::NodeIsText; } else { node = static_cast(oldNode); -- cgit v1.2.3