Resolve StyledText img tags relative to baseUrl.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Tue, 7 Feb 2012 07:52:52 +0000 (17:52 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 7 Feb 2012 10:53:54 +0000 (11:53 +0100)
Change-Id: I954195d52330c65e851b7c0fcdb6c8dabf29335d
Reviewed-by: Yann Bodson <yann.bodson@nokia.com>

src/quick/items/qquicktext.cpp
src/quick/util/qdeclarativestyledtext.cpp
src/quick/util/qdeclarativestyledtext_p.h
tests/auto/qtquick2/qdeclarativestyledtext/tst_qdeclarativestyledtext.cpp
tests/auto/qtquick2/qquicktext/tst_qquicktext.cpp

index acf2d17..1401677 100644 (file)
@@ -298,7 +298,7 @@ void QQuickTextPrivate::updateLayout()
     if (!richText) {
         if (textHasChanged) {
             if (styledText && !text.isEmpty()) {
-                QDeclarativeStyledText::parse(text, layout, imgTags, qmlContext(q), !maximumLineCountValid);
+                QDeclarativeStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid);
             } else {
                 layout.clearAdditionalFormats();
                 QString tmp = text;
@@ -893,7 +893,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal
             image->position < line.textStart() + line.textLength()) {
 
             if (!image->pix) {
-                QUrl url = qmlContext(q)->resolvedUrl(image->url);
+                QUrl url = q->baseUrl().resolved(image->url);
                 image->pix = new QDeclarativePixmap(qmlEngine(q), url, image->size);
                 if (image->pix->isLoading()) {
                     image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
@@ -1752,6 +1752,12 @@ void QQuickText::setBaseUrl(const QUrl &url)
 
         if (d->doc)
             d->doc->setBaseUrl(url);
+        if (d->styledText) {
+            d->textHasChanged = true;
+            qDeleteAll(d->imgTags);
+            d->imgTags.clear();
+            d->updateLayout();
+        }
         emit baseUrlChanged();
     }
 }
index 39ea6b1..3023fc5 100644 (file)
@@ -83,9 +83,10 @@ public:
 
     QDeclarativeStyledTextPrivate(const QString &t, QTextLayout &l,
                                   QList<QDeclarativeStyledTextImgTag*> &imgTags,
+                                  const QUrl &baseUrl,
                                   QDeclarativeContext *context,
                                   bool preloadImages)
-        : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), hasNewLine(false), nbImages(0), updateImagePositions(false)
+        : text(t), layout(l), imgTags(&imgTags), baseFont(layout.font()), baseUrl(baseUrl), hasNewLine(false), nbImages(0), updateImagePositions(false)
         , preFormat(false), prependSpace(false), hasSpace(true), preloadImages(preloadImages), context(context)
     {
     }
@@ -117,6 +118,7 @@ public:
     QList<QDeclarativeStyledTextImgTag*> *imgTags;
     QFont baseFont;
     QStack<List> listStack;
+    QUrl baseUrl;
     bool hasNewLine;
     int nbImages;
     bool updateImagePositions;
@@ -155,9 +157,11 @@ const QChar QDeclarativeStyledTextPrivate::lineFeed(QLatin1Char('\n'));
 const QChar QDeclarativeStyledTextPrivate::space(QLatin1Char(' '));
 
 QDeclarativeStyledText::QDeclarativeStyledText(const QString &string, QTextLayout &layout,
-                                               QList<QDeclarativeStyledTextImgTag*> &imgTags, QDeclarativeContext *context,
+                                               QList<QDeclarativeStyledTextImgTag*> &imgTags,
+                                               const QUrl &baseUrl,
+                                               QDeclarativeContext *context,
                                                bool preloadImages)
-    : d(new QDeclarativeStyledTextPrivate(string, layout, imgTags, context, preloadImages))
+    : d(new QDeclarativeStyledTextPrivate(string, layout, imgTags, baseUrl, context, preloadImages))
 {
 }
 
@@ -167,12 +171,14 @@ QDeclarativeStyledText::~QDeclarativeStyledText()
 }
 
 void QDeclarativeStyledText::parse(const QString &string, QTextLayout &layout,
-                                   QList<QDeclarativeStyledTextImgTag*> &imgTags, QDeclarativeContext *context,
+                                   QList<QDeclarativeStyledTextImgTag*> &imgTags,
+                                   const QUrl &baseUrl,
+                                   QDeclarativeContext *context,
                                    bool preloadImages)
 {
     if (string.isEmpty())
         return;
-    QDeclarativeStyledText styledText(string, layout, imgTags, context, preloadImages);
+    QDeclarativeStyledText styledText(string, layout, imgTags, baseUrl, context, preloadImages);
     styledText.d->parse();
 }
 
@@ -657,7 +663,7 @@ void QDeclarativeStyledTextPrivate::parseImageAttributes(const QChar *&ch, const
             // if we don't know its size but the image is a local image,
             // we load it in the pixmap cache and save its implicit size
             // to avoid a relayout later on.
-            QUrl url = context->resolvedUrl(image->url);
+            QUrl url = baseUrl.resolved(image->url);
             if (url.isLocalFile()) {
                 QDeclarativePixmap *pix = new QDeclarativePixmap(context->engine(), url, image->size);
                 if (pix && pix->isReady()) {
index 1c9086e..aa6ae3f 100644 (file)
@@ -83,12 +83,14 @@ class Q_AUTOTEST_EXPORT QDeclarativeStyledText
 public:
     static void parse(const QString &string, QTextLayout &layout,
                       QList<QDeclarativeStyledTextImgTag*> &imgTags,
+                      const QUrl &baseUrl,
                       QDeclarativeContext *context,
                       bool preloadImages);
 
 private:
     QDeclarativeStyledText(const QString &string, QTextLayout &layout,
                            QList<QDeclarativeStyledTextImgTag*> &imgTags,
+                           const QUrl &baseUrl,
                            QDeclarativeContext *context,
                            bool preloadImages);
     ~QDeclarativeStyledText();
index b4e0ba1..fd0d1ab 100644 (file)
@@ -160,7 +160,7 @@ void tst_qdeclarativestyledtext::textOutput()
 
     QTextLayout layout;
     QList<QDeclarativeStyledTextImgTag*> imgTags;
-    QDeclarativeStyledText::parse(input, layout, imgTags, 0, false);
+    QDeclarativeStyledText::parse(input, layout, imgTags, QUrl(), 0, false);
 
     QCOMPARE(layout.text(), output);
 
index 96449c0..8e3a1f4 100644 (file)
@@ -108,6 +108,8 @@ private slots:
 
     void lineLaidOut();
 
+    void imgTagsBaseUrl_data();
+    void imgTagsBaseUrl();
     void imgTagsAlign_data();
     void imgTagsAlign();
     void imgTagsMultipleImages();
@@ -1549,6 +1551,87 @@ void tst_qquicktext::lineLaidOut()
     delete canvas;
 }
 
+void tst_qquicktext::imgTagsBaseUrl_data()
+{
+    QTest::addColumn<QUrl>("src");
+    QTest::addColumn<QUrl>("baseUrl");
+    QTest::addColumn<QUrl>("contextUrl");
+    QTest::addColumn<qreal>("imgHeight");
+
+    QTest::newRow("absolute local")
+            << testFileUrl("images/heart200.png")
+            << QUrl()
+            << QUrl()
+            << 181.;
+    QTest::newRow("relative local context 1")
+            << QUrl("images/heart200.png")
+            << QUrl()
+            << testFileUrl("/app.qml")
+            << 181.;
+    QTest::newRow("relative local context 2")
+            << QUrl("heart200.png")
+            << QUrl()
+            << testFileUrl("images/app.qml")
+            << 181.;
+    QTest::newRow("relative local base 1")
+            << QUrl("images/heart200.png")
+            << testFileUrl("")
+            << testFileUrl("nonexistant/app.qml")
+            << 181.;
+    QTest::newRow("relative local base 2")
+            << QUrl("heart200.png")
+            << testFileUrl("images/")
+            << testFileUrl("nonexistant/app.qml")
+            << 181.;
+    QTest::newRow("base relative to local context")
+            << QUrl("heart200.png")
+            << testFileUrl("images/")
+            << testFileUrl("/app.qml")
+            << 181.;
+
+    QTest::newRow("absolute remote")
+            << QUrl("http://127.0.0.1:14453/images/heart200.png")
+            << QUrl()
+            << QUrl()
+            << 181.;
+    QTest::newRow("relative remote base 1")
+            << QUrl("images/heart200.png")
+            << QUrl("http://127.0.0.1:14453/")
+            << testFileUrl("nonexistant/app.qml")
+            << 181.;
+    QTest::newRow("relative remote base 2")
+            << QUrl("heart200.png")
+            << QUrl("http://127.0.0.1:14453/images/")
+            << testFileUrl("nonexistant/app.qml")
+            << 181.;
+}
+
+void tst_qquicktext::imgTagsBaseUrl()
+{
+    QFETCH(QUrl, src);
+    QFETCH(QUrl, baseUrl);
+    QFETCH(QUrl, contextUrl);
+    QFETCH(qreal, imgHeight);
+
+    TestHTTPServer server(14453);
+    server.serveDirectory(testFile(""));
+
+    QByteArray baseUrlFragment;
+    if (!baseUrl.isEmpty())
+        baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
+    QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
+
+    QDeclarativeComponent component(&engine);
+    component.setData(componentStr, contextUrl);
+    QScopedPointer<QObject> object(component.create());
+    QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+    QVERIFY(textObject);
+
+    QCoreApplication::processEvents();
+
+    QTRY_COMPARE(textObject->height(), imgHeight);
+}
+
 void tst_qquicktext::imgTagsAlign_data()
 {
     QTest::addColumn<QString>("src");