Implement high-dpi "@2x" image handling.
authorMorten Johan Sørvig <morten.sorvig@digia.com>
Mon, 19 Aug 2013 11:29:43 +0000 (13:29 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 20 Mar 2014 21:12:24 +0000 (22:12 +0100)
Make QQuickBaseImage::load() load "@2x" image files
on high-dpi displays. Reload images on screen change
in order to load the correct version depending on
screen dpi. Modify QQuickImageBase::updatePaintNode()
to work with @2x images.

QQuickBaseImage::load() now looks at the target
window's devicePixelRatio and checks for the presence
of a "@2x" file on disk. If found the @2x version
will be used.

Unlike QPixmap, QQuickPixmap has no special knowledge
of "@2x" files. They pixmap system will be asked to
load "@2x" files and will cache them and report the
(device) pixel size, like any other pixmap.

Add auto-test and manual test.

Task-number: QTBUG-32862, QTBUG-33069
Change-Id: I1f57a10075e499f6eee61df5421e1986521c6ab0
Reviewed-by: Andy Nichols <andy.nichols@digia.com>
16 files changed:
src/quick/items/qquickimage.cpp
src/quick/items/qquickimagebase.cpp
src/quick/items/qquickimagebase_p.h
src/quick/items/qquickimagebase_p_p.h
tests/auto/quick/qquickimage/data/heart-highdpi@2x.png [new file with mode: 0644]
tests/auto/quick/qquickimage/tst_qquickimage.cpp
tests/manual/highdpi/fillmodes.qml [new file with mode: 0644]
tests/manual/highdpi/heart-highdpi@2x.png [new file with mode: 0644]
tests/manual/highdpi/heart-lowdpi.png [new file with mode: 0644]
tests/manual/highdpi/heart.png [new file with mode: 0644]
tests/manual/highdpi/heart@2x.png [new file with mode: 0644]
tests/manual/highdpi/image.qml [new file with mode: 0644]
tests/manual/highdpi/image2.qml [new file with mode: 0644]
tests/manual/highdpi/imagesize.qml [new file with mode: 0644]
tests/manual/highdpi/mirror.qml [new file with mode: 0644]
tests/manual/highdpi/sourcesize.qml [new file with mode: 0644]

index 69a39d23962337e5200b9c8d040ed8bcb3fbf019..08dbfa3c236c29f1027363123ff5aded95da93ec 100644 (file)
@@ -589,8 +589,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
     QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
     QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
 
-    qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width();
-    qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height();
+    qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
+    qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight :  d->pix.height() / d->devicePixelRatio;
 
     int xOffset = 0;
     if (d->hAlign == QQuickImage::AlignHCenter)
@@ -671,10 +671,12 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
         break;
     };
 
-    QRectF nsrect(sourceRect.x() / d->pix.width(),
-                  sourceRect.y() / d->pix.height(),
-                  sourceRect.width() / d->pix.width(),
-                  sourceRect.height() / d->pix.height());
+    qreal nsWidth = (hWrap == QSGTexture::Repeat) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
+    qreal nsHeight = (vWrap == QSGTexture::Repeat) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
+    QRectF nsrect(sourceRect.x() / nsWidth,
+                  sourceRect.y() / nsHeight,
+                  sourceRect.width() / nsWidth,
+                  sourceRect.height() / nsHeight);
 
     if (targetRect.isEmpty()
         || !qIsFinite(targetRect.width()) || !qIsFinite(targetRect.height())
index c842922dc612f36b885dad9ae378e4b90813d44b..edd6faa5695741492401d1e093bbb394f60d3336 100644 (file)
 #include "qquickimagebase_p.h"
 #include "qquickimagebase_p_p.h"
 
+#include <QtGui/qguiapplication.h>
+
 #include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlfile.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -50,12 +53,14 @@ QQuickImageBase::QQuickImageBase(QQuickItem *parent)
 : QQuickImplicitSizeItem(*(new QQuickImageBasePrivate), parent)
 {
     setFlag(ItemHasContents);
+    connect(this, SIGNAL(windowChanged(QQuickWindow*)), SLOT(handleWindowChanged(QQuickWindow*)));
 }
 
 QQuickImageBase::QQuickImageBase(QQuickImageBasePrivate &dd, QQuickItem *parent)
 : QQuickImplicitSizeItem(dd, parent)
 {
     setFlag(ItemHasContents);
+    connect(this, SIGNAL(windowChanged(QQuickWindow*)), SLOT(handleWindowChanged(QQuickWindow*)));
 }
 
 QQuickImageBase::~QQuickImageBase()
@@ -208,7 +213,13 @@ void QQuickImageBase::load()
         if (d->cache)
             options |= QQuickPixmap::Cache;
         d->pix.clear(this);
-        d->pix.load(qmlEngine(this), d->url, d->sourcesize, options);
+
+        const qreal targetDevicePixelRatio = (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio());
+        d->devicePixelRatio = 1.0;
+
+        QUrl loadUrl = d->url;
+        resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
+        d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options);
 
         if (d->pix.isLoading()) {
             if (d->progress != 0.0) {
@@ -275,6 +286,19 @@ void QQuickImageBase::requestProgress(qint64 received, qint64 total)
     }
 }
 
+void QQuickImageBase::handleWindowChanged(QQuickWindow* window)
+{
+    if (window)
+        connect(window, SIGNAL(screenChanged(QScreen*)), this, SLOT(handleScreenChanged(QScreen*)));
+}
+
+void QQuickImageBase::handleScreenChanged(QScreen*)
+{
+    // Screen DPI might have changed, reload images on screen change.
+    if (isComponentComplete())
+        load();
+}
+
 void QQuickImageBase::componentComplete()
 {
     Q_D(QQuickImageBase);
@@ -286,7 +310,52 @@ void QQuickImageBase::componentComplete()
 void QQuickImageBase::pixmapChange()
 {
     Q_D(QQuickImageBase);
-    setImplicitSize(d->pix.width(), d->pix.height());
+    setImplicitSize(d->pix.width() / d->devicePixelRatio, d->pix.height() / d->devicePixelRatio);
+}
+
+// /path/to/foo.png -> path/too/foo@2x.png
+static QString image2xPath(const QString &path)
+{
+    const int dotIndex = path.lastIndexOf(QLatin1Char('.'));
+    if (dotIndex == -1)
+        return path;
+    if (path.contains("@2x."))
+        return path;
+
+    QString retinaPath = path;
+    retinaPath.insert(dotIndex, QStringLiteral("@2x"));
+    return retinaPath;
+}
+
+void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
+{
+    Q_ASSERT(sourceUrl);
+    Q_ASSERT(sourceDevicePixelRatio);
+
+    QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
+
+    // Non-local file path: @2x loading is not supported.
+    if (localFile.isEmpty())
+        return;
+
+    // Special case: the url in the QML source refers directly to an "@2x" file.
+    if (localFile.contains("@2x")) {
+        *sourceDevicePixelRatio = qreal(2.0);
+        return;
+    }
+
+    // Don't load @2x files non normal-dpi displays.
+    if (!(targetDevicePixelRatio > qreal(1.0)))
+        return;
+
+    // Look for an @2x version
+    QString localFile2x = image2xPath(localFile);
+    if (!QFile(localFile2x).exists())
+        return;
+
+    // @2x file found found: Change url and devicePixelRatio
+    *sourceUrl = QUrl::fromLocalFile(localFile2x);
+    *sourceDevicePixelRatio = qreal(2.0);
 }
 
 QT_END_NAMESPACE
index 72258b4971ce4203765032314f813944d6473956..67f1e81caeb93890cb4fa0283767ba2d76d1fb33 100644 (file)
@@ -86,6 +86,8 @@ public:
     virtual void setMirror(bool mirror);
     bool mirror() const;
 
+    void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
+
 Q_SIGNALS:
     void sourceChanged(const QUrl &);
     void sourceSizeChanged();
@@ -104,6 +106,8 @@ protected:
 private Q_SLOTS:
     virtual void requestFinished();
     void requestProgress(qint64,qint64);
+    void handleWindowChanged(QQuickWindow *window);
+    void handleScreenChanged(QScreen *);
 
 private:
     Q_DISABLE_COPY(QQuickImageBase)
index 395abf01fa7f208c279ea33e5f972bbb7c84654d..bb8778d7894439801a688b6ec7731875bbf98f5c 100644 (file)
@@ -69,6 +69,7 @@ public:
     QQuickImageBasePrivate()
       : status(QQuickImageBase::Null),
         progress(0.0),
+        devicePixelRatio(1.0),
         async(false),
         cache(true),
         mirror(false)
@@ -81,6 +82,7 @@ public:
     qreal progress;
     QSize sourcesize;
     QSize oldSourceSize;
+    qreal devicePixelRatio;
     bool async : 1;
     bool cache : 1;
     bool mirror: 1;
diff --git a/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png b/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png
new file mode 100644 (file)
index 0000000..abe97fe
Binary files /dev/null and b/tests/auto/quick/qquickimage/data/heart-highdpi@2x.png differ
index b23591b593421fa04ae62f5a90c4f07789854c14..0855403d5ae7f02cc251e311e8d72e1cbaadcc01 100644 (file)
@@ -105,6 +105,7 @@ private slots:
     void progressAndStatusChanges();
     void sourceSizeChanges();
     void correctStatus();
+    void highdpi();
 
 private:
     QQmlEngine engine;
@@ -928,6 +929,49 @@ void tst_qquickimage::correctStatus()
     delete obj;
 }
 
+void tst_qquickimage::highdpi()
+{
+    TestHTTPServer server(14449);
+    QVERIFY(server.isValid());
+    server.serveDirectory(dataDirectory());
+
+    QString componentStr = "import QtQuick 2.0\nImage { source: srcImage ;  }";
+    QQmlComponent component(&engine);
+    component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+    QQmlContext *ctxt = engine.rootContext();
+
+    // Testing "@2x" high-dpi image loading:
+    // The basic case is as follows. Suppose you have foo.png,
+    // which is a 64x64 png that fits in a QML layout. Now,
+    // on a high-dpi system that pixmap would not provide
+    // enough pixels. To fix this the app developer provides
+    // a 128x128 foo@2x.png, which Qt automatically loads.
+    // The image continues to be referred to as "foo.png" in
+    // the QML sources, and reports a size of 64x64.
+    //
+
+    // Load "heart-highdpi@2x.png", which is a 300x300 png. As a 2x scale image it
+    // should render and report a geometry of 150x150.
+    ctxt->setContextProperty("srcImage", testFileUrl("heart-highdpi@2x.png"));
+
+    QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
+    QVERIFY(obj != 0);
+
+    QCOMPARE(obj->width(), 150.0);
+    QCOMPARE(obj->height(), 150.0);
+    QCOMPARE(obj->paintedWidth(), 150.0);
+    QCOMPARE(obj->paintedHeight(), 150.0);
+
+    // Load a normal 1x image.
+    ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
+    QCOMPARE(obj->width(), 300.0);
+    QCOMPARE(obj->height(), 300.0);
+    QCOMPARE(obj->paintedWidth(), 300.0);
+    QCOMPARE(obj->paintedHeight(), 300.0);
+
+    delete obj;
+}
+
 QTEST_MAIN(tst_qquickimage)
 
 #include "tst_qquickimage.moc"
diff --git a/tests/manual/highdpi/fillmodes.qml b/tests/manual/highdpi/fillmodes.qml
new file mode 100644 (file)
index 0000000..cff2bcc
--- /dev/null
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 700
+
+    // the images should have the same display size and appearance on each row.
+    Column {
+        anchors.centerIn: parent.Center
+        Row {
+            Image {  width: 130; height: 70; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 130; height: 70; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 130; height: 70; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart-lowdpi.png" }
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart.png" }
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectFit; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart-lowdpi.png" }
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart.png" }
+            Image {  width: 130; height: 100; fillMode: Image.PreserveAspectCrop; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 230; height: 200; fillMode: Image.Tile; source : "heart-lowdpi.png" }
+            Image {  width: 230; height: 200; fillMode: Image.Tile; source : "heart.png" }
+            Image {  width: 230; height: 200; fillMode: Image.Tile; source : "heart-highdpi@2x.png" }
+        }
+    }
+}
diff --git a/tests/manual/highdpi/heart-highdpi@2x.png b/tests/manual/highdpi/heart-highdpi@2x.png
new file mode 100644 (file)
index 0000000..a7a1ca8
Binary files /dev/null and b/tests/manual/highdpi/heart-highdpi@2x.png differ
diff --git a/tests/manual/highdpi/heart-lowdpi.png b/tests/manual/highdpi/heart-lowdpi.png
new file mode 100644 (file)
index 0000000..deaec18
Binary files /dev/null and b/tests/manual/highdpi/heart-lowdpi.png differ
diff --git a/tests/manual/highdpi/heart.png b/tests/manual/highdpi/heart.png
new file mode 100644 (file)
index 0000000..deaec18
Binary files /dev/null and b/tests/manual/highdpi/heart.png differ
diff --git a/tests/manual/highdpi/heart@2x.png b/tests/manual/highdpi/heart@2x.png
new file mode 100644 (file)
index 0000000..a7a1ca8
Binary files /dev/null and b/tests/manual/highdpi/heart@2x.png differ
diff --git a/tests/manual/highdpi/image.qml b/tests/manual/highdpi/image.qml
new file mode 100644 (file)
index 0000000..8deab5c
--- /dev/null
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 400
+
+    Image {
+        source : "heart.png"
+        anchors.centerIn: parent
+    }
+}
diff --git a/tests/manual/highdpi/image2.qml b/tests/manual/highdpi/image2.qml
new file mode 100644 (file)
index 0000000..b83c800
--- /dev/null
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 400
+
+    // These images should all have the same visual size:
+    Row {
+        anchors.centerIn: parent
+        // 1X only
+        Image {
+            source : "heart-lowdpi.png"
+        }
+        // 1X and 2x, switches on screen change.
+        Image {
+            source : "heart.png"
+        }
+        // 2x only
+        Image {
+            source : "heart-highdpi@2x.png"
+        }
+    }
+}
diff --git a/tests/manual/highdpi/imagesize.qml b/tests/manual/highdpi/imagesize.qml
new file mode 100644 (file)
index 0000000..ee6719a
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 400
+
+    Column {
+        anchors.centerIn: parent.Center
+        Row {
+            Image {  width: 50; height: 50; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 50; height: 50; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 50; height: 50; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 100; height: 100; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 100; height: 100; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 100; height: 100; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 150; height: 150; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 150; height: 150; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 150; height: 150; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 200; height: 200; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 200; height: 200; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 200; height: 200; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+        Row {
+            Image {  width: 300; height: 300; fillMode: Image.Stretch; source : "heart-lowdpi.png" }
+            Image {  width: 300; height: 300; fillMode: Image.Stretch; source : "heart.png" }
+            Image {  width: 300; height: 300; fillMode: Image.Stretch; source : "heart-highdpi@2x.png" }
+        }
+    }
+}
diff --git a/tests/manual/highdpi/mirror.qml b/tests/manual/highdpi/mirror.qml
new file mode 100644 (file)
index 0000000..3a92a9a
--- /dev/null
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 700
+
+    // the images should have the same display size and appearance on each row.
+    Column {
+        anchors.centerIn: parent.Center
+        Row {
+            Image { mirror: true; source : "heart-lowdpi.png" }
+            Image { mirror: true; source : "heart.png" }
+            Image { mirror: true; source : "heart-highdpi@2x.png" }
+        }
+    }
+}
diff --git a/tests/manual/highdpi/sourcesize.qml b/tests/manual/highdpi/sourcesize.qml
new file mode 100644 (file)
index 0000000..64bf8ad
--- /dev/null
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Rectangle {
+    width: 400
+    height: 400
+
+    // SourceSize is in device-independent pixels. These images
+    // should display at the same visual size.
+    Column {
+        anchors.centerIn: parent.Center
+        Row {
+
+            // standard image with no @2x version
+            Image {
+                sourceSize.width: 75
+                sourceSize.height: 75
+                source : "heart-lowdpi.png"
+            }
+
+            // image with "@2x" version on disk
+            Image {
+                sourceSize.width: 75
+                sourceSize.height: 75
+                source : "heart.png"
+            }
+
+            // direct use of "@2x" image
+            Image {
+                sourceSize.width: 75
+                sourceSize.height: 75
+                source : "heart-highdpi@2x.png"
+            }
+        }
+    }
+}