=== modified file 'debian/control'
--- debian/control	2015-07-10 05:40:21 +0000
+++ debian/control	2015-08-12 11:28:41 +0000
@@ -45,6 +45,11 @@
                suru-icon-theme,
                uuid-runtime,
                python3-sphinx,
+               libfontconfig1-dev,
+               libfreetype6-dev,
+               libmtdev-dev,
+               libudev-dev,
+               libxrender-dev
 Standards-Version: 3.9.4
 Homepage: https://launchpad.net/ubuntu-ui-toolkit
 # If you aren't a member of ~ubuntu-sdk-team but need to upload packaging

=== modified file 'src/Ubuntu/Components/plugin/ucqquickimageextension.cpp'
--- src/Ubuntu/Components/plugin/ucqquickimageextension.cpp	2014-11-24 13:14:35 +0000
+++ src/Ubuntu/Components/plugin/ucqquickimageextension.cpp	2015-08-12 11:28:41 +0000
@@ -19,6 +19,7 @@
 #include <QtCore/QFile>
 #include <QtCore/QFileInfo>
 #include <QtCore/QDir>
+#include <QtGui/QGuiApplication>
 #include <QtQuick/private/qquickimagebase_p.h>
 
 #include "ucqquickimageextension.h"
@@ -78,8 +79,18 @@
     QString selectedFilePath = resolved.mid(separatorPosition+1);
 
     if (scaleFactor == "1") {
-        // No scaling. Just pass the file as is.
-        m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
+        if (qFuzzyCompare(qGuiApp->devicePixelRatio(), (qreal)1.0)
+                || selectedFilePath.endsWith(".svg") || selectedFilePath.endsWith(".svgz")) {
+            // No scaling necessary. Just pass the file as is.
+            m_image->setSource(QUrl::fromLocalFile(selectedFilePath));
+        } else {
+            // Need to scale the pixel-based image to suit the devicePixelRatio setting ourselves.
+            // If we let Qt do it, Qt will not choose the UITK-supported "@gu" scaled images.
+            m_image->setSource(QUrl("image://scaling/1/" + selectedFilePath));
+            // explicitly set the source size in the QQuickImageBase, this persuades it that the
+            // supplied image is suitable for the current devicePixelRatio.
+            m_image->setSourceSize(m_image->sourceSize());
+        }
     } else {
         // Prepend "image://scaling" for the image to be loaded by UCScalingImageProvider.
         if (!m_source.path().endsWith(".sci")) {
@@ -100,7 +111,13 @@
                 rewrittenSciFile->setFileTemplate(QDir::tempPath() + QDir::separator() + "XXXXXX.sci");
                 rewrittenSciFile->open();
                 QTextStream output(rewrittenSciFile);
-                rewritten = rewriteSciFile(selectedFilePath, scaleFactor, output);
+
+                if (qFuzzyCompare(qGuiApp->devicePixelRatio(), (qreal)1.0)) {
+                    rewritten = rewriteSciFile(selectedFilePath, scaleFactor, output);
+                } else {
+                    QString scaleFactorInDevicePixels = QString::number(scaleFactor.toFloat() / qGuiApp->devicePixelRatio());
+                    rewritten = rewriteSciFile(selectedFilePath, scaleFactorInDevicePixels, output);
+                }
                 rewrittenSciFile->close();
 
                 s_rewrittenSciFiles.insert(m_source, QSharedPointer<QTemporaryFile>(rewrittenSciFile));
@@ -112,6 +129,9 @@
                 m_image->setSource(m_source);
             }
         }
+        // explicitly set the source size in the QQuickImageBase, this persuades it that the
+        // supplied image is suitable for the current devicePixelRatio.
+        m_image->setSourceSize(m_image->sourceSize());
     }
 }
 

=== modified file 'src/Ubuntu/Components/plugin/ucubuntushape.cpp'
--- src/Ubuntu/Components/plugin/ucubuntushape.cpp	2015-08-06 13:16:24 +0000
+++ src/Ubuntu/Components/plugin/ucubuntushape.cpp	2015-08-12 11:28:41 +0000
@@ -308,10 +308,7 @@
     setFlag(ItemHasContents);
     QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
                      SLOT(_q_gridUnitChanged()));
-    const float gridUnit = UCUnits::instance().gridUnit();
-    setImplicitWidth(implicitWidthGU * gridUnit);
-    setImplicitHeight(implicitHeightGU * gridUnit);
-    update();
+    _q_gridUnitChanged();
 }
 
 /*! \qmlproperty string UbuntuShape::radius
@@ -998,9 +995,9 @@
 
 void UCUbuntuShape::_q_gridUnitChanged()
 {
-    const float gridUnit = UCUnits::instance().gridUnit();
-    setImplicitWidth(implicitWidthGU * gridUnit);
-    setImplicitHeight(implicitHeightGU * gridUnit);
+    const float gridUnitInDevicePixels = UCUnits::instance().gridUnit() / qGuiApp->devicePixelRatio();
+    setImplicitWidth(implicitWidthGU * gridUnitInDevicePixels);
+    setImplicitHeight(implicitHeightGU * gridUnitInDevicePixels);
     update();
 }
 
@@ -1162,13 +1159,15 @@
             sourceTextureRect = sourceTexture->normalizedTextureSubRect();
         }
         if (m_flags & DirtySourceTransform) {
+            const float dpr = qGuiApp->devicePixelRatio();
+
             if (m_flags & SourceApiSet) {
-                updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,
+                updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, m_sourceFillMode,
                                       m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
                                       sourceTexture->textureSize());
             } else {
                 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
-                updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,
+                updateSourceTransform(itemSize.width() * dpr, itemSize.height() * dpr, imageFillMode,
                                       m_imageHorizontalAlignment, m_imageVerticalAlignment,
                                       sourceTexture->textureSize());
             }
@@ -1198,13 +1197,15 @@
         // accordingly. The shape was using a fixed image for the corner before switching to a
         // distance field, since the corner wasn't taking the whole image (ending at ~80%) we need
         // to take that into account when the size is scaled down.
-        radius = UCUnits::instance().gridUnit() * radiusGuMap[m_radius];
+        radius = UCUnits::instance().gridUnit() * radiusGuMap[m_radius]
+                     / qGuiApp->devicePixelRatio();
         const float scaledDownRadius = qMin(itemSize.width(), itemSize.height()) * 0.5f * 0.8f;
         if (radius > scaledDownRadius) {
             radius = scaledDownRadius;
         }
     } else {
-        radius = qMin(itemSize.width(), itemSize.height()) * 0.5f * (m_relativeRadius * 0.01f);
+        radius = qMin(itemSize.width(), itemSize.height()) * 0.5f * (m_relativeRadius * 0.01f)
+                     / qGuiApp->devicePixelRatio();
     }
 
     updateMaterial(node, radius, shapeTextureId, sourceTexture && m_sourceOpacity);
@@ -1284,16 +1285,19 @@
         materialData->sourceOpacity = 0;
     }
 
+    const float physicalRadius = radius * qGuiApp->devicePixelRatio();
+
     // Mapping of radius size range from [0, 4] to [0, 1] with clamping, plus quantization.
     const float start = 0.0f + radiusSizeOffset;
     const float end = 4.0f + radiusSizeOffset;
+
     materialData->distanceAAFactor =
-        qMin((radius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
+        qMin((physicalRadius / (end - start)) - (start / (end - start)), 1.0f) * 255.0f;
 
     // When the radius is equal to radiusSizeOffset (which means radius size is 0), no aspect is
     // flagged so that a dedicated (statically flow controlled) shaved off shader can be used for
     // optimal performance.
-    if (radius > radiusSizeOffset) {
+    if (physicalRadius > radiusSizeOffset) {
         const quint8 aspectFlags[] = {
             ShapeMaterial::Data::Flat, ShapeMaterial::Data::Inset, ShapeMaterial::Data::DropShadow,
             ShapeMaterial::Data::Inset | ShapeMaterial::Data::Pressed

=== modified file 'src/Ubuntu/Components/plugin/ucunits.cpp'
--- src/Ubuntu/Components/plugin/ucunits.cpp	2015-03-03 13:47:48 +0000
+++ src/Ubuntu/Components/plugin/ucunits.cpp	2015-08-12 11:28:41 +0000
@@ -24,6 +24,8 @@
 #include <QtCore/QDir>
 #include <QtCore/QRegularExpression>
 #include <QtCore/qmath.h>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
 
 #define ENV_GRID_UNIT_PX "GRID_UNIT_PX"
 #define DEFAULT_GRID_UNIT_PX 8
@@ -62,10 +64,46 @@
 
     \sa {Resolution Independence}
 */
+
+/*
+ * Note on the interaction between GRID_UNIT_PX and QT_DEVICE_PIXEL_RATIO
+ *
+ * In Qt5.4 there is a single means to scale the UI: the QT_DEVICE_PIXEL_RATIO environment
+ * variable. This accepts only integer values, thus allowing a x2 or x3 scaling of any
+ * Qt-based UI, that includes QWidget as well as any QML UI.
+ *
+ * Setting QT_DEVICE_PIXEL_RATIO=2 implies one density-independent pixel corresponds to 2
+ * physical pixels. Developers describe their UI in terms of density-independent pixels.
+ * Qt scales accordingly.
+ *
+ * The Ubuntu UI Toolkit has solved the scaling problem with the GRID_UNIT_PX variable.
+ * It offers more flexibility, but only scales QML applications written to use the UITK
+ * (since it uses this Units class) as it is built on top of QML.
+ *
+ * There are additional areas in Qt where QT_DEVICE_PIXEL_RATIO causes correct scaling which
+ * GRID_UNIT_PX cannot, for example:
+ *   1. cacheBuffer for ListView/GridViews - specified in density-independent pixels
+ *   2. gesture recognition  matches what is on screen better, as it is density-independent
+ *      pixel aware
+ *
+ * In order to get the best of both worlds, Ubuntu will set both GRID_UNIT_PX and
+ * QT_DEVICE_PIXEL_RATIO. Thus all Qt apps will scale reasonably well, with UITK-based apps
+ * scaling perfectly for any desired scale (i.e. non-integer scales).
+ *
+ * However UITK developers can just use this Units class as usual, and will be almost totally
+ * isolated from Qt's own scaling concept.
+ */
+
 UCUnits::UCUnits(QObject *parent) :
-    QObject(parent)
+    QObject(parent),
+    m_devicePixelRatio(qGuiApp->devicePixelRatio())
 {
-    m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
+    // If GRID_UNIT_PX set, always use it. If not, 1GU := DEFAULT_GRID_UNIT_PX * m_devicePixelRatio
+    if (qEnvironmentVariableIsSet(ENV_GRID_UNIT_PX)) {
+        m_gridUnit = getenvFloat(ENV_GRID_UNIT_PX, DEFAULT_GRID_UNIT_PX);
+    } else {
+        m_gridUnit = DEFAULT_GRID_UNIT_PX * m_devicePixelRatio;
+    }
 }
 
 /*!
@@ -89,14 +127,15 @@
 
     Returns the number of pixels \a value density independent pixels correspond to.
 */
+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
 float UCUnits::dp(float value)
 {
     const float ratio = m_gridUnit / DEFAULT_GRID_UNIT_PX;
     if (value <= 2.0) {
         // for values under 2dp, return only multiples of the value
-        return qRound(value * qFloor(ratio));
+        return qRound(value * qFloor(ratio)) / m_devicePixelRatio;
     } else {
-        return qRound(value * ratio);
+        return qRound(value * ratio) / m_devicePixelRatio;
     }
 }
 
@@ -105,9 +144,11 @@
 
     Returns the number of pixels \a value grid units correspond to.
 */
+// Density-independent pixels (and not physical pixels) because Qt sizes in terms of density-independent pixels.
+
 float UCUnits::gu(float value)
 {
-    return qRound(value * m_gridUnit);
+    return qRound(value * m_gridUnit) / m_devicePixelRatio;
 }
 
 QString UCUnits::resolveResource(const QUrl& url)

=== modified file 'src/Ubuntu/Components/plugin/ucunits.h'
--- src/Ubuntu/Components/plugin/ucunits.h	2013-10-18 08:56:39 +0000
+++ src/Ubuntu/Components/plugin/ucunits.h	2015-08-12 11:28:41 +0000
@@ -53,6 +53,7 @@
     float gridUnitSuffixFromFileName(const QString &fileName);
 
 private:
+    float m_devicePixelRatio;
     float m_gridUnit;
 };
 

=== modified file 'tests/unit/add_makecheck.pri'
--- tests/unit/add_makecheck.pri	2015-05-19 07:55:27 +0000
+++ tests/unit/add_makecheck.pri	2015-08-12 11:28:41 +0000
@@ -5,4 +5,15 @@
 check.target = check
 check.commands += cd $$_PRO_FILE_PWD_;
 check.commands += env LD_LIBRARY_PATH=$${ROOT_BUILD_DIR}/qml/Ubuntu/Components:$${ROOT_BUILD_DIR}/qml/Ubuntu/Layouts:$${ROOT_BUILD_DIR}/qml/Ubuntu/PerformanceMetrics:$${ROOT_BUILD_DIR}/qml/Ubuntu/Test UITK_TEST_KEEP_RUNNING=1
-check.commands += '$${ROOT_SOURCE_DIR}/tests/unit/runtest.sh "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" minimal';
+
+TEST_COMMAND = '$${ROOT_SOURCE_DIR}/tests/unit/runtest.sh "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}" "$$shadowed($$_PRO_FILE_PWD_)/$${TARGET}"'
+
+message($$TEST_COMMAND)
+
+# if "CONFIG += custom_qpa" is set, use our custom QPA plugin for the test
+custom_qpa {
+    check.commands += env QT_QPA_PLATFORM_PLUGIN_PATH=$${ROOT_BUILD_DIR}/tests/unit/custom_qpa
+    check.commands += '$$TEST_COMMAND custom';
+} else {
+    check.commands += '$$TEST_COMMAND minimal';
+}

=== added directory 'tests/unit/custom_qpa'
=== added file 'tests/unit/custom_qpa/README'
--- tests/unit/custom_qpa/README	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/README	2015-08-12 11:28:41 +0000
@@ -0,0 +1,15 @@
+In order to correctly test Qt's Device Pixel Ratio system in a 
+unit test, one needs to have the QPA plugin for the platform
+support reading the DEVICE_PIXEL_RATIO environment variable.
+
+These unit tests use the "minimal" QPA plugin, which 
+unfortunately does not support that variable.
+
+The contents of this directory is a near-complete duplicate of 
+"minimal" QPA plugin source from Qt, with added support for the
+DEVICE_PIXEL_RATIO environment variable.
+
+One can use this plugin as follows:
+
+DEVICE_PIXEL_RATIO=2 QT_QPA_PLATFORM_PLUGIN_PATH=$PWD \
+    QT_QPA_PLATFORM=custom qmlscene ~/tmp.qml

=== added file 'tests/unit/custom_qpa/custom.json'
--- tests/unit/custom_qpa/custom.json	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/custom.json	2015-08-12 11:28:41 +0000
@@ -0,0 +1,3 @@
+{
+    "Keys": [ "custom" ]
+}

=== added file 'tests/unit/custom_qpa/custom_qpa.pro'
--- tests/unit/custom_qpa/custom_qpa.pro	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/custom_qpa.pro	2015-08-12 11:28:41 +0000
@@ -0,0 +1,15 @@
+TARGET = qcustom
+TEMPLATE = lib
+
+CONFIG += plugin no_keywords c++11
+
+QT -= gui
+QT += core-private gui-private platformsupport-private
+
+SOURCES =   main.cpp \
+            qcustomintegration.cpp \
+            qcustombackingstore.cpp
+HEADERS =   qcustomintegration.h \
+            qcustombackingstore.h
+
+OTHER_FILES += custom.json

=== added file 'tests/unit/custom_qpa/main.cpp'
--- tests/unit/custom_qpa/main.cpp	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/main.cpp	2015-08-12 11:28:41 +0000
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qcustomintegration.h"
+
+class QCustomIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+    Q_OBJECT
+    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "custom.json")
+public:
+    QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QPlatformIntegration *QCustomIntegrationPlugin::create(const QString& system, const QStringList& /*paramList*/)
+{
+    if (!system.compare(QLatin1String("custom"), Qt::CaseInsensitive))
+        return new QCustomIntegration();
+
+    return 0;
+}
+
+#include "main.moc"

=== added file 'tests/unit/custom_qpa/qcustombackingstore.cpp'
--- tests/unit/custom_qpa/qcustombackingstore.cpp	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/qcustombackingstore.cpp	2015-08-12 11:28:41 +0000
@@ -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 plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qcustombackingstore.h"
+#include "qcustomintegration.h"
+#include "qscreen.h"
+#include <qpa/qplatformscreen.h>
+#include <private/qguiapplication_p.h>
+
+
+QCustomBackingStore::QCustomBackingStore(QWindow *window)
+    : QPlatformBackingStore(window)
+{
+}
+
+QPaintDevice *QCustomBackingStore::paintDevice()
+{
+    return &mImage;
+}
+
+void QCustomBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+    Q_UNUSED(window);
+    Q_UNUSED(region);
+    Q_UNUSED(offset);
+}
+
+void QCustomBackingStore::resize(const QSize &size, const QRegion &)
+{
+    QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
+    if (mImage.size() != size)
+        mImage = QImage(size, format);
+}

=== added file 'tests/unit/custom_qpa/qcustombackingstore.h'
--- tests/unit/custom_qpa/qcustombackingstore.h	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/qcustombackingstore.h	2015-08-12 11:28:41 +0000
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QBACKINGSTORE_MINIMAL_H
+#define QBACKINGSTORE_MINIMAL_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatformwindow.h>
+#include <QtGui/QImage>
+
+class QCustomBackingStore : public QPlatformBackingStore
+{
+public:
+    QCustomBackingStore(QWindow *window);
+    ~QCustomBackingStore() = default;
+
+    QPaintDevice *paintDevice();
+    void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+    void resize(const QSize &size, const QRegion &staticContents);
+
+private:
+    QImage mImage;
+};
+
+#endif

=== added file 'tests/unit/custom_qpa/qcustomintegration.cpp'
--- tests/unit/custom_qpa/qcustomintegration.cpp	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/qcustomintegration.cpp	2015-08-12 11:28:41 +0000
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcustomintegration.h"
+#include "qcustombackingstore.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformfontdatabase.h>
+
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+static const char devicePixelRatioEnvironmentVariable[] = "QT_DEVICE_PIXEL_RATIO";
+
+QCustomScreen::QCustomScreen()
+    : mDepth(32), mFormat(QImage::Format_ARGB32_Premultiplied), mDpr(1.0)
+{
+    if (qEnvironmentVariableIsSet(devicePixelRatioEnvironmentVariable)) {
+        bool ok = false;
+        const float dpr = qgetenv(devicePixelRatioEnvironmentVariable).toFloat(&ok);
+        if (ok && dpr > 0) {
+            mDpr = dpr;
+        }
+    }
+}
+
+QCustomIntegration::QCustomIntegration()
+{
+    QCustomScreen *mPrimaryScreen = new QCustomScreen();
+
+    mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320);
+    mPrimaryScreen->mDepth = 32;
+    mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
+
+    screenAdded(mPrimaryScreen);
+}
+
+bool QCustomIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+    switch (cap) {
+    case ThreadedPixmaps: return true;
+    case MultipleWindows: return true;
+    default: return QPlatformIntegration::hasCapability(cap);
+    }
+}
+
+// Dummy font database that does not scan the fonts directory to be
+// used for command line tools like qmlplugindump that do not create windows
+// unless DebugBackingStore is activated.
+class DummyFontDatabase : public QPlatformFontDatabase
+{
+public:
+    void populateFontDatabase() override {}
+};
+
+QPlatformFontDatabase *QCustomIntegration::fontDatabase() const
+{
+    return new DummyFontDatabase;
+}
+
+
+QPlatformWindow *QCustomIntegration::createPlatformWindow(QWindow *window) const
+{
+    QPlatformWindow *w = new QPlatformWindow(window);
+    w->requestActivateWindow();
+    return w;
+}
+
+QPlatformBackingStore *QCustomIntegration::createPlatformBackingStore(QWindow *window) const
+{
+    return new QCustomBackingStore(window);
+}
+
+QAbstractEventDispatcher *QCustomIntegration::createEventDispatcher() const
+{
+    return createUnixEventDispatcher();
+}
+
+QCustomIntegration *QCustomIntegration::instance()
+{
+    return static_cast<QCustomIntegration *>(QGuiApplicationPrivate::platformIntegration());
+}

=== added file 'tests/unit/custom_qpa/qcustomintegration.h'
--- tests/unit/custom_qpa/qcustomintegration.h	1970-01-01 00:00:00 +0000
+++ tests/unit/custom_qpa/qcustomintegration.h	2015-08-12 11:28:41 +0000
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMINTEGRATION_MINIMAL_H
+#define QPLATFORMINTEGRATION_MINIMAL_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+
+class QCustomScreen : public QPlatformScreen
+{
+public:
+    QCustomScreen();
+
+    QRect geometry() const override { return mGeometry; }
+    int depth() const override { return mDepth; }
+    QImage::Format format() const override { return mFormat; }
+    qreal devicePixelRatio() const override { return mDpr; }
+
+public:
+    QRect mGeometry;
+    int mDepth;
+    QImage::Format mFormat;
+    QSize mPhysicalSize;
+    qreal mDpr;
+};
+
+class QCustomIntegration : public QPlatformIntegration
+{
+public:
+    explicit QCustomIntegration();
+    ~QCustomIntegration() = default;
+
+    bool hasCapability(QPlatformIntegration::Capability cap) const override;
+    QPlatformFontDatabase *fontDatabase() const override;
+
+    QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+    QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+    QAbstractEventDispatcher *createEventDispatcher() const override;
+
+    static QCustomIntegration *instance();
+};
+
+#endif

=== modified file 'tests/unit/runtest.sh'
--- tests/unit/runtest.sh	2015-06-17 18:18:04 +0000
+++ tests/unit/runtest.sh	2015-08-12 11:28:41 +0000
@@ -43,6 +43,8 @@
 
   if [ "$_MINIMAL" = "minimal" ]; then
       _CMD="$_CMD -p -platform -p minimal"
+  elif [ "$_MINIMAL" = "custom" ]; then
+      _CMD="$_CMD -p -platform -p custom"
   fi
 
   if [ $_TARGETPATH != $_TESTFILEPATH ]; then

=== added directory 'tests/unit/tst_units/dpr1'
=== added file 'tests/unit/tst_units/dpr1/dpr1.pro'
--- tests/unit/tst_units/dpr1/dpr1.pro	1970-01-01 00:00:00 +0000
+++ tests/unit/tst_units/dpr1/dpr1.pro	2015-08-12 11:28:41 +0000
@@ -0,0 +1,3 @@
+include(../../test-include.pri)
+SOURCES += tst_units.cpp
+RESOURCES += dpr1.qrc

=== renamed file 'tests/unit/tst_units/tst_units.qrc' => 'tests/unit/tst_units/dpr1/dpr1.qrc'
=== renamed file 'tests/unit/tst_units/exact_match@8.png' => 'tests/unit/tst_units/dpr1/exact_match@8.png'
=== renamed file 'tests/unit/tst_units/exact_match_no_suffix.png' => 'tests/unit/tst_units/dpr1/exact_match_no_suffix.png'
=== renamed file 'tests/unit/tst_units/higher_scale.png' => 'tests/unit/tst_units/dpr1/higher_scale.png'
=== renamed file 'tests/unit/tst_units/lower_scale.png' => 'tests/unit/tst_units/dpr1/lower_scale.png'
=== renamed file 'tests/unit/tst_units/resource@1.png' => 'tests/unit/tst_units/dpr1/resource@1.png'
=== renamed file 'tests/unit/tst_units/resource@10.png' => 'tests/unit/tst_units/dpr1/resource@10.png'
=== renamed file 'tests/unit/tst_units/resource@15.png' => 'tests/unit/tst_units/dpr1/resource@15.png'
=== renamed file 'tests/unit/tst_units/resource@18.png' => 'tests/unit/tst_units/dpr1/resource@18.png'
=== renamed file 'tests/unit/tst_units/resource@19.png' => 'tests/unit/tst_units/dpr1/resource@19.png'
=== renamed file 'tests/unit/tst_units/resource@8.png' => 'tests/unit/tst_units/dpr1/resource@8.png'
=== renamed file 'tests/unit/tst_units/resource_only_higher@13.png' => 'tests/unit/tst_units/dpr1/resource_only_higher@13.png'
=== renamed file 'tests/unit/tst_units/resource_only_smaller@7.png' => 'tests/unit/tst_units/dpr1/resource_only_smaller@7.png'
=== renamed file 'tests/unit/tst_units/resources_unit' => 'tests/unit/tst_units/dpr1/resources_unit'
=== renamed file 'tests/unit/tst_units/tst_units.cpp' => 'tests/unit/tst_units/dpr1/tst_units.cpp'
=== added directory 'tests/unit/tst_units/dpr2'
=== added file 'tests/unit/tst_units/dpr2/dpr2.pro'
--- tests/unit/tst_units/dpr2/dpr2.pro	1970-01-01 00:00:00 +0000
+++ tests/unit/tst_units/dpr2/dpr2.pro	2015-08-12 11:28:41 +0000
@@ -0,0 +1,3 @@
+CONFIG += custom_qpa   # needed by test to set device pixel ratio correctly
+include(../../test-include.pri)
+SOURCES += tst_units_dpr2.cpp

=== added file 'tests/unit/tst_units/dpr2/tst_units_dpr2.cpp'
--- tests/unit/tst_units/dpr2/tst_units_dpr2.cpp	1970-01-01 00:00:00 +0000
+++ tests/unit/tst_units/dpr2/tst_units_dpr2.cpp	2015-08-12 11:28:41 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3, as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QtTest/QtTest>
+#include "ucunits.h"
+
+class tst_UCUnitsDPR2: public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+
+    void dpGridUnitDefaultWithDPR2() {
+        UCUnits units;
+
+        QCOMPARE(units.dp(1.0), 1.0f);
+        QCOMPARE(units.dp(1.32), 1.5f);
+        QCOMPARE(units.dp(1.72), 1.5f);
+        QCOMPARE(units.dp(0.23), 0.0f);
+        QCOMPARE(units.dp(0.51), 0.5f);
+        QCOMPARE(units.dp(0.9999), 1.0f);
+        QCOMPARE(units.dp(1000.01), 1000.0f);
+    }
+
+    void guGridUnitDefaultWithDPR2() {
+        UCUnits units;
+
+        QCOMPARE(units.gu(0.5), 4.0f);
+        QCOMPARE(units.gu(1), 8.0f);
+        QCOMPARE(units.gu(1.5), 12.0f);
+        QCOMPARE(units.gu(2), 16.0f);
+        QCOMPARE(units.gu(4), 32.0f);
+        QCOMPARE(units.gu(100000), 800000.0f);
+        QCOMPARE(units.gu(150.51983), 1204.0f);
+    }
+
+    void dpGridUnitEightWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(8);
+
+        QCOMPARE(units.dp(1.0), 0.5f);
+        QCOMPARE(units.dp(1.32), 0.5f);
+        QCOMPARE(units.dp(1.72), 1.0f);
+        QCOMPARE(units.dp(0.23), 0.0f);
+        QCOMPARE(units.dp(0.51), 0.5f);
+        QCOMPARE(units.dp(0.9999), 0.5f);
+        QCOMPARE(units.dp(1000.01), 500.0f);
+    }
+
+    void guGridUnitEightWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(8);
+
+        QCOMPARE(units.gu(0.5), 2.0f);
+        QCOMPARE(units.gu(1), 4.0f);
+        QCOMPARE(units.gu(1.5), 6.0f);
+        QCOMPARE(units.gu(2), 8.0f);
+        QCOMPARE(units.gu(4), 16.0f);
+        QCOMPARE(units.gu(100000), 400000.0f);
+        QCOMPARE(units.gu(150.51983), 602.0f);
+    }
+
+    void dpGridUnitSixteenWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(16);
+        /* This testcase covers unit calculations when the Qt device pixel ratio is 2.
+         *
+         */
+
+        QCOMPARE(units.dp(1.0), 1.0f);
+        QCOMPARE(units.dp(1.32), 1.5f);
+        QCOMPARE(units.dp(1.72), 1.5f);
+        QCOMPARE(units.dp(0.23), 0.0f);
+        QCOMPARE(units.dp(0.51), 0.5f);
+        QCOMPARE(units.dp(0.9999), 1.0f);
+        QCOMPARE(units.dp(1000.01), 1000.0f);
+    }
+
+    void guGridUnitSixteenWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(16);
+
+        QCOMPARE(units.gu(0.5), 4.0f);
+        QCOMPARE(units.gu(1), 8.0f);
+        QCOMPARE(units.gu(1.5), 12.0f);
+        QCOMPARE(units.gu(2), 16.0f);
+        QCOMPARE(units.gu(4), 32.0f);
+        QCOMPARE(units.gu(100000), 800000.0f);
+        QCOMPARE(units.gu(150.51983), 1204.0f);
+    }
+
+    void dpGridUnitTwentyWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(20);
+
+        QCOMPARE(units.dp(1.0), 1.0f);
+        QCOMPARE(units.dp(1.32), 1.5f);
+        QCOMPARE(units.dp(1.72), 1.5f);
+        QCOMPARE(units.dp(0.23), 0.0f);
+        QCOMPARE(units.dp(0.51), 0.5f);
+        QCOMPARE(units.dp(0.9999), 1.0f);
+        QCOMPARE(units.dp(1000.01), 1250.0f);
+    }
+
+    void guGridUnitTenWithDPR2() {
+        UCUnits units;
+        units.setGridUnit(10);
+
+        QCOMPARE(units.gu(0.5), 2.5f);
+        QCOMPARE(units.gu(1), 5.0f);
+        QCOMPARE(units.gu(1.5), 7.5f);
+        QCOMPARE(units.gu(2), 10.0f);
+        QCOMPARE(units.gu(4), 20.0f);
+        QCOMPARE(units.gu(100000), 500000.0f);
+        QCOMPARE(units.gu(150.51983), 752.5f);
+    }
+};
+
+//QTEST_MAIN(tst_UCUnitsDPR2) - want to set custom env var, so need to use actual code:
+int main(int argc, char *argv[])
+{
+    qputenv("QT_DEVICE_PIXEL_RATIO", "2");
+
+    QGuiApplication app(argc, argv);
+    app.setAttribute(Qt::AA_Use96Dpi, true);
+    tst_UCUnitsDPR2 tc;
+    return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_units_dpr2.moc"

=== added directory 'tests/unit/tst_units/dpr3'
=== added file 'tests/unit/tst_units/dpr3/dpr3.pro'
--- tests/unit/tst_units/dpr3/dpr3.pro	1970-01-01 00:00:00 +0000
+++ tests/unit/tst_units/dpr3/dpr3.pro	2015-08-12 11:28:41 +0000
@@ -0,0 +1,3 @@
+CONFIG += custom_qpa   # needed by test to set device pixel ratio correctly
+include(../../test-include.pri)
+SOURCES += tst_units_dpr3.cpp

=== added file 'tests/unit/tst_units/dpr3/tst_units_dpr3.cpp'
--- tests/unit/tst_units/dpr3/tst_units_dpr3.cpp	1970-01-01 00:00:00 +0000
+++ tests/unit/tst_units/dpr3/tst_units_dpr3.cpp	2015-08-12 11:28:41 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3, as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QtTest/QtTest>
+#include "ucunits.h"
+
+class tst_UCUnitsDPR3: public QObject
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+
+    void dpGridUnitDefaultWithDPR3() {
+        UCUnits units;
+
+        QCOMPARE(units.dp(1.0), 1.0f);
+        QCOMPARE(units.dp(1.32), 1.33333f);
+        QCOMPARE(units.dp(1.72), 1.66666f);
+        QCOMPARE(units.dp(0.23), 0.333333f);
+        QCOMPARE(units.dp(0.51), 0.666666f);
+        QCOMPARE(units.dp(0.9999), 1.0f);
+        QCOMPARE(units.dp(1000.01), 1000.0f);
+    }
+
+    void guGridUnitDefaultWithDPR3() {
+        UCUnits units;
+
+        QCOMPARE(units.gu(0.5), 4.0f);
+        QCOMPARE(units.gu(1), 8.0f);
+        QCOMPARE(units.gu(1.5), 12.0f);
+        QCOMPARE(units.gu(2), 16.0f);
+        QCOMPARE(units.gu(4), 32.0f);
+        QCOMPARE(units.gu(100000), 800000.0f);
+        QCOMPARE(units.gu(150.51983), 1204.0f);
+    }
+
+    void dpGridUnitSixteenWithDPR3() {
+        UCUnits units;
+        units.setGridUnit(16);
+
+        QCOMPARE(units.dp(1.0), 0.666666f);
+        QCOMPARE(units.dp(1.32), 1.0f);
+        QCOMPARE(units.dp(1.72), 1.0f);
+        QCOMPARE(units.dp(0.23), 0.0f);
+        QCOMPARE(units.dp(0.51), 0.333333f);
+        QCOMPARE(units.dp(0.9999), 0.666666f);
+        QCOMPARE(units.dp(1000.01), 666.666666f);
+    }
+
+    void guGridUnitSixteenWithDPR3() {
+        UCUnits units;
+        units.setGridUnit(16);
+
+        QCOMPARE(units.gu(0.5), 2.666666f);
+        QCOMPARE(units.gu(1), 5.333333f);
+        QCOMPARE(units.gu(1.5), 8.0f);
+        QCOMPARE(units.gu(2), 10.666666f);
+        QCOMPARE(units.gu(4), 21.333333f);
+        QCOMPARE(units.gu(100000), 533333.333333f);
+        QCOMPARE(units.gu(150.51983), 802.666666f);
+    }
+};
+
+//QTEST_MAIN(tst_UCUnitsDPR3) - want to set custom env var, so need to use actual code:
+int main(int argc, char *argv[])
+{
+    qputenv("QT_DEVICE_PIXEL_RATIO", "3");
+
+    QGuiApplication app(argc, argv);
+    app.setAttribute(Qt::AA_Use96Dpi, true);
+    tst_UCUnitsDPR3 tc;
+    return QTest::qExec(&tc, argc, argv);
+}
+
+#include "tst_units_dpr3.moc"

=== modified file 'tests/unit/tst_units/tst_units.pro'
--- tests/unit/tst_units/tst_units.pro	2012-10-09 17:54:43 +0000
+++ tests/unit/tst_units/tst_units.pro	2015-08-12 11:28:41 +0000
@@ -1,3 +1,6 @@
-include(../test-include.pri)
-SOURCES += tst_units.cpp
-RESOURCES += tst_units.qrc
+TEMPLATE = subdirs
+
+SUBDIRS += \
+    dpr1 \
+    dpr2 \
+    dpr3

=== modified file 'tests/unit/unit.pro'
--- tests/unit/unit.pro	2015-03-10 11:49:27 +0000
+++ tests/unit/unit.pro	2015-08-12 11:28:41 +0000
@@ -14,7 +14,9 @@
         tst_components_benchmark
 #}
 
-SUBDIRS += tst_units \
+SUBDIRS += \
+    custom_qpa \
+    tst_units \
     tst_scaling_image_provider \
     tst_qquick_image_extension \
     tst_performance \

